What is a Buffer Overflow?
A buffer overflow occurs when a program or process tries to store more data in a buffer (temporary data storage area) than it was intended to hold. Since buffers are created to contain a finite amount of data, the extra information – which has to go somewhere – can overflow into adjacent buffers, corrupting or overwriting the valid data held in them. Although it may occur accidentally through programming error, buffer overflow is an increasingly common type of security attack on data integrity. In buffer overflow attacks, the extra data may contain codes designed to trigger specific actions, in effect sending new instructions to the attacked computer that could, for example, damage the user’s files, change data, or disclose confidential information. Buffer overflow attacks are said to have arisen because the C programming language supplied the framework, and poor programming practices supplied the vulnerability.
What can you do with that?
Redirect the flow of a program, wherever you want in the memory.
It is a very powerful and funny exploitation.
- Understand a bit of C and ASM language. (You have to understand what a stack and registers are)
- Know vaguely what “buffer overflow” means.
The goal of this tutorial is to teach you what a stack based buffer overflow is, only with observations and reflections with GDB.
Let’s analyze this code (compiled with -g -fno-stack-protector) :
There is a typical buffer overflow in the function vuln() ;
Indeed, the size of “arg” is not checked.
If it exceeds 50 bytes, there is a buffer overflow, because the size of buffer is 50 bytes.
Let’s try to launch it with 10*A (normal execution), and then with 100*A (crash) :
“Segmentation Fault” means that something went wrong during the process of our program. Indeed, we can notice that the program doesn’t display “Good Bye!” at the end for the 2nd execution.
Something went wrong.
Let’s try to figure out what happened.
We are going to use GDB for that.
Line 16 of main.c, at the end of the function vuln, the program received a SIGSEGV signal.
That means that our stack is compromised, and we cannot exit the function vuln.
Let’s disassemble the vuln function, and put some strategic breakpoints so we can analyze easily what happened.
Let’s put 4 breakpoints :
- At the beggining of the function vuln
- Before the strcpy
- After the strcpy
- At the end of the function vuln
Now let’s run the program with a buffer overflow, and see what happens on the stack :
The first breakpoint is reached, we are at the beginning of the function vuln.
Let’s take a look at the top of our stack :
0x004005fe is the address of the instruction right after the call of the function vuln :
Indeed, “call 0x40059c” is equivalent to “push next_eip; jmp 0x40059c”
So it is not surprising to find our next_eip at the top of the stack at the beginning of the function vuln().
It also means that, if we are able to modify this value, we can redirect the program at whatever address we want.
Let’s continue our analysis.
We continue the execution until the next breakpoint; Before the strcpy.
At this point, nothing is copied yet. Let’s see our stack :
Now let’s see what happens after our buffer overflow :
Apparently, our main_EIP has been overwritten by 0x41414141.
Let’s check this by going to the next breakpoint at the end of the function :
The main_EIP at the adress 0x7ffe668 has been overwritten.
In case of you didn’t know, ascii(‘A’) = 0x41.
So, in practice, our buffer begins at the adress 0x7ffe620.
Our main_EIP is at the adress 0x7ffe668.
So we know that we have to write 0x7ffe668 – 0x7ffe620 = 0x48 = 72 bytes before erasing the main_EIP.
Let’s try to reach the unreachable_code() function :
It is located at the adress 0x400614.
Let’s repeat the previous operation, but we will try to overwrite main_EIP with 0x400614 instead of 0x41414141.
Our main_EIP has been effectively overwritten.
The message “This code is not executed” is displayed, because we changed the flow of the program.
Now you know how to explore and exploit the stack.
Don’t forget that \x00 are NULL byte = end of string, all bytes after it will be ignored by strcpy.