2

I have been reading "The Shellcoders Handbook" and been referring to this link for practice of stack overflow. But it seems the Linux kernel developers have made the kernel very secure. Here are my problems.

1) This code

void function(int a, int b, int c) {
   char buffer1[8];
   char buffer2[10];
   int* ret;

   ret = buffer1 + 6;
   *ret+=8;
}

void main() {
  int x;

  x = 0;
  function(1,2,3);
  x = 1;
  printf("%d\n",x);
}

gives the output

$ cc smash.c
smash.c: In function ‘function’:
smash.c:7:8: warning: assignment from incompatible pointer type
$ ./a.out
1

but replacing the line *ret+=8 with *ret=8 gives the following output

*** stack smashing detected ***: ./a.out terminated
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x50)[0xa86df0]
/lib/i386-linux-gnu/libc.so.6(+0xe5d9a)[0xa86d9a]
./a.out[0x8048448]
./a.out[0x8048477]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xe7)[0x9b7e37]
./a.out[0x8048381]
======= Memory map: ========
003df000-003e0000 r-xp 00000000 00:00 0          [vdso]
009a1000-00afb000 r-xp 00000000 08:01 3277633    /lib/i386-linux-gnu/libc-2.13.so
00afb000-00afc000 ---p 0015a000 08:01 3277633    /lib/i386-linux-gnu/libc-2.13.so
00afc000-00afe000 r--p 0015a000 08:01 3277633    /lib/i386-linux-gnu/libc-2.13.so
...
...

If I replace ret = buffer1 + 6 with ret = buffer1 + 7, the result is same as above. If I replace ret = buffer1 + 6 with ret=buffer1+8 (or any larger value), there is smashed stack for BOTH the cases described above (i.e. whether I increment the value *ret by 8 or change it to 8).

Please tell me how this happens. Helpful links will also be appreciated. And above all, how can I disable this security feature of the Linux kernel so that I can work with this book?

Platform: i386 Kernel: 2.6.38

caf
  • 233,326
  • 40
  • 323
  • 462
pflz
  • 1,891
  • 4
  • 26
  • 32

2 Answers2

11

To disable the stack smashing detection, use -fno-stack-protector when compiling. You may also want to use -ggdb and -mpreferred-stack-boundary=4 when working through "The Shellcoders Handbook" to enable GDB symbols and standardize the stack.

edit: When I compiled the code you provided (gcc -fno-stack-protector -ggdb -mpreferred-stack-boundary=4 -o sc in.c), the compiler rearranged the order of the local variables in function. I found this by using GDB:

willi@ubuntu:~/testing$ gdb sc
(gdb) set disassembly-flavor intel
(gdb) disassemble function
Dump of assembler code for function function:
   0x080483c4 <+0>: push   ebp
   0x080483c5 <+1>: mov    ebp,esp
   0x080483c7 <+3>: sub    esp,0x20
   0x080483ca <+6>: lea    eax,[ebp-0xc]
   0x080483cd <+9>: add    eax,0x6
   0x080483d0 <+12>:    mov    DWORD PTR [ebp-0x4],eax
   0x080483d3 <+15>:    mov    eax,DWORD PTR [ebp-0x4]
   0x080483d6 <+18>:    mov    eax,DWORD PTR [eax]
   0x080483d8 <+20>:    lea    edx,[eax+0x8]
   0x080483db <+23>:    mov    eax,DWORD PTR [ebp-0x4]
   0x080483de <+26>:    mov    DWORD PTR [eax],edx
   0x080483e0 <+28>:    leave  
   0x080483e1 <+29>:    ret    
End of assembler dump.

0x080483ca tells me that ebp - 0xC is buffer1, and 0x080483d0 tells me ebp - 0x4 is ret. So, the variables do not exist on the stack as they exist in our C code. Given that ret is our top-most local variable, we could work with it directly. Let's work with your code, though.

To modify the return pointer, we need to change the address stored just below the saved ebp, so ebp + 0x4. So, to get to the return pointer from from our variable buffer1, we have to add 0xC (to get to ebp), and then 0x4 (return pointer is 0x4 under ebp). Now we can make our modifications.

I take from your C code that you'd like to skip the assignment of x = 1 and return directly to the printf. I disassembled main to find the appropriate modification to the return pointer:

(gdb) disassemble main
Dump of assembler code for function main:
   0x080483e2 <+0>: push   ebp
   0x080483e3 <+1>: mov    ebp,esp
   0x080483e5 <+3>: and    esp,0xfffffff0
   0x080483e8 <+6>: sub    esp,0x20
   0x080483eb <+9>: mov    DWORD PTR [esp+0x1c],0x0
   0x080483f3 <+17>:    mov    DWORD PTR [esp+0x8],0x3
   0x080483fb <+25>:    mov    DWORD PTR [esp+0x4],0x2
   0x08048403 <+33>:    mov    DWORD PTR [esp],0x1
   0x0804840a <+40>:    call   0x80483c4 <function>
   0x0804840f <+45>:    mov    DWORD PTR [esp+0x1c],0x1
   0x08048417 <+53>:    mov    eax,DWORD PTR [esp+0x1c]
   0x0804841b <+57>:    mov    DWORD PTR [esp+0x4],eax
   0x0804841f <+61>:    mov    DWORD PTR [esp],0x80484f0
   0x08048426 <+68>:    call   0x80482f4 <printf@plt>
   0x0804842b <+73>:    leave  
   0x0804842c <+74>:    ret    
End of assembler dump.

Without modification to the return pointer, the call to function at 0x0804840a returns to 0x0804840f. But we want to skip this and return to the next instruction. The next instruction begins at 0x08048417, which is 0x8 bytes further along. So our modification to the return pointer must increase its value by 0x8.

Taking these things into consideration, I used the following code to print "0" rather than "1":

void function(int a, int b, int c) {
   char buffer1[8];
   char buffer2[10];
   int* ret;

   ret = buffer1 + 0x10;
   *ret+=8;
}

void main() {
  int x;

  x = 0;
  function(1,2,3);
  x = 1;
  printf("%d\n",x);
}
Willi Ballenthin
  • 6,444
  • 6
  • 38
  • 52
  • Good answer, but I steel don`t understand one thing. Why for getting return address from `function` you add `0x2` and `0x2` and `0xc` (about `0xc` I understand, but not `0x2`) ? – azat Feb 26 '12 at 20:13
  • `ebp` stores the saved stack pointer, and the return address is stored directly under that. So we need to add `sizeof(void *)` to the address of the saved stack pointer to get the address of the return address. I've updated the post to use `0x4` instead of `0x2` to reflect `sizeof(void *)` (not sure why I had `0x2`). – Willi Ballenthin Nov 27 '12 at 21:22
0

Stack smashing protection can be disabled like so:

$ gcc -ggdb -m32 -o buffer1 -fno-stack-protector -mpreferred-stack-boundary=4 buffer1.c

This link provides more information on Linux's security features

bramp
  • 9,581
  • 5
  • 40
  • 46
Madhur Ahuja
  • 22,211
  • 14
  • 71
  • 124