Exploitation Techniques
Pattern Selection
| Pattern | Signals | Requirement |
|---|---|---|
| Stack BOF | No canary, unbounded input | Control return address |
| Canary Bypass | Canary present, info leak possible | Leak or avoid canary |
| GOT Overwrite | Partial RELRO, write primitive | Writable GOT |
| Format String | printf(user_input) | User controls format |
| ret2libc | NX enabled, libc available | Libc address leak |
| ROP | NX enabled, gadgets needed | Sufficient gadgets |
1. Stack Buffer Overflow
Concept: Overflow a stack buffer to overwrite the saved return address.
Stack Layout:
[ buffer ][ saved_rbp ][ return_addr ]
↑ ↑ ↑
overflow → overwrite → control RIP
Template:
OFFSET = <bytes_to_return_address> TARGET = <address_to_jump_to> payload = b'A' * OFFSET payload += p64(TARGET)
64-bit alignment: Add a ret gadget before the target if crashes occur (16-byte alignment).
2. Stack Canary Bypass
Concept: Leak or avoid corrupting the stack canary.
Approaches:
- •Leak via format string or other info disclosure
- •Brute force (only works with fork servers - canary constant across children)
- •Off-by-one to corrupt variable above canary without touching canary
Leak template:
# Probe for canary (ends in null byte)
for i in range(1, 50):
send(f'%{i}$p')
if response.endswith(b'00'):
CANARY_OFFSET = i
Brute force template:
canary = b'\x00' # First byte always null
for position in range(7):
for byte in range(256):
payload = padding + canary + bytes([byte])
if no_crash(payload):
canary += bytes([byte])
break
3. GOT Overwrite
Concept: Overwrite a GOT entry so the next call to that function jumps to your target.
Requirements: Partial RELRO (GOT writable), write primitive
Template:
GOT_ENTRY = <address_of_got_entry> NEW_VALUE = <address_to_redirect_to> # Write NEW_VALUE to GOT_ENTRY using your primitive # (format string, arbitrary write, etc.)
Common targets: Functions called after your write (puts, printf, exit, __stack_chk_fail)
4. Format String
Concept: User input used directly as printf format string enables read/write.
Read template:
# Leak stack values payload = b'%p.' * N # Leak specific offset payload = b'%<offset>$p'
Write template:
# pwntools handles complexity
writes = {<target_addr>: <value>}
payload = fmtstr_payload(<stack_offset>, writes)
5. ret2libc
Concept: After leaking a libc address, calculate base and call system().
Template:
LEAKED_ADDR = <leaked_function_address> LEAKED_OFFSET = libc.symbols['<leaked_function>'] libc.address = LEAKED_ADDR - LEAKED_OFFSET system = libc.symbols['system'] binsh = next(libc.search(b'/bin/sh')) payload = padding + p64(ret) + p64(pop_rdi) + p64(binsh) + p64(system)
6. ROP Chains
Concept: Chain gadgets ending in ret to perform operations when NX is enabled.
64-bit calling convention: RDI, RSI, RDX, RCX, R8, R9
Gadget types:
- •
pop <reg>; ret- Load value into register - •
mov [<reg>], <reg>; ret- Write to memory - •
syscall; ret- Make syscall
Template:
rop = ROP(elf)
rop.call('<function>', [<arg1>, <arg2>, ...])
payload = padding + rop.chain()
7. Heap Exploitation
Use-After-Free:
- •Allocate chunk A
- •Free chunk A
- •Allocate chunk B (same size, reuses A's memory)
- •Dangling pointer to A now accesses B's data
Heap Overflow:
- •Corrupt adjacent chunk metadata
- •Overwrite forward/backward pointers
- •Achieve write primitive on next alloc/free
Composition Patterns
| Have | Combine With |
|---|---|
| BOF + NX | ret2libc or ROP |
| Format string | GOT overwrite, leak canary/libc |
| Partial RELRO + write | GOT overwrite |
| Fork server + canary | Brute force canary |