Hello vuln-dev! As far as I can tell, most people have exploited vulndev2.c by exploiting printf()'s got tables. However, the way I did it was by overwriting the FILE * and pointing it to our own specially crafted FILE structure somewhere in memory. From there, when glibc tries to fclose() f1 it uses the function pointer _IO_file_jumps in the FILE structure to jump to a jump table (which we've also placed in memory), which jumps to our shell code. You can see my exploit code in a previous posting, or visit: http://www.hcsw.org/sploits/vulndev2sploit.c A more thourough explanation: > /* log input */ > if ( (f1 = fopen("db.log", "a+")) == NULL) > return 1; > fprintf(f1, ";;%s;;", argv[2]); > fclose(f1); We put the memory location of where our specially crafted FILE struct will be into the log file from arg2. > strcpy(buf, argv[1]); This call does most of the work. 4 things of note are put into memory because of it: * A new value for bfp pointing 2 bytes before the f1 variable. * A specially crafted FILE struct * A jump table * Our shellcode > /* read log */ > if ( (f1 = fopen("db.log", "r")) == NULL) > return 1; > if (fgets(bfp, BFSIZE, f1) == NULL) > return 1; Here the program reads in data from the log file. When fgets() writes the data to bfp, it actually overwrites the f1 variable because we changed where f1 is pointing in the previous step. (We point bfp to 2 bytes before f1 because the logfile entry will start with 2 semicolons) > fclose(f1); The system tries to fclose() f1 which is now pointing to our FILE struct. It follows the _IO_file_jumps, selects one of our entries in our jump table and jumps to it. Remember all of our entries in our jump table point to our shellcode. Some notes: * We could also have pointed bfp to the actual location in memory of where the FILE struct for fp was closing and overwrote that, just leaving f1 pointing to where it originally pointed. Both would have worked. * Originally I thought this exploit was going to be trivial. I thought we could simply smash the stack on the strcpy() call and overwrite main's ret. However, this function only returns in a few instances: not in the default case. Usually it exits using exit() which, of course, ignores any ret calls. A race condition might exist to exploit this however. Consider this: The application opens up the log file for writing and writes its stuff. The application strcpy()s your arg1 into buf. You overwrite main()'s return code to point at some shellcode. Now, if you're extrememly quick, make the file non-readble in some way (deleting it, changing perms, etc): fopen() will return NULL, and main() will return. 0wn3d: > if ( (f1 = fopen("db.log", "r")) == NULL) > return 1; It would probably be easiest to exploit this on a lagged system accessing its filesystems over a high latency connection like, say, NFS. * A number of people have also suggested a symlink attack. * A number of people have exploited this using printf()'s got tables. Conclusion: This was a very well thought out challenge: There are a number of ways to exploit this code, and I trust it will start some good discussion on vuln-dev. I must disagree with "anon" in this one: > btw. the first challenge was better than this (even if it was already well documented aswell..) This challenge was far more interesting than the previous. I hope vuln-dev challenges grow into a vuln-dev tradition! Shouts that I forgot in the .c: madness for forwarding me the vuln-dev message theclone, rt, magma syke GOBBLES for reminding us how painfully necessary coherency is... Doug Hoyte Hypervivid Solutions, Inc HardCore SoftWare fractal@efnet __________________________________ Do you Yahoo!? The New Yahoo! Search - Faster. Easier. Bingo. http://search.yahoo.com
This archive was generated by hypermail 2b30 : Sat May 24 2003 - 16:18:02 PDT