| name | stack-overflow-exploitation |
| description | How to analyze and exploit stack overflow vulnerabilities in binary programs. Use this skill whenever the user mentions stack overflows, buffer overflows, EIP/RIP control, return address manipulation, CTF binary exploitation, or needs help finding offsets and crafting exploits for vulnerable programs. This includes ret2win, shellcode placement, ROP chains, and analyzing real-world CVEs with stack-based vulnerabilities. |
Stack Overflow Exploitation
A skill for analyzing and exploiting stack overflow vulnerabilities in binary programs.
What is a Stack Overflow
A stack overflow occurs when a program writes more data to the stack than allocated, overwriting adjacent memory including:
- Saved instruction pointer (EIP/RIP) - controls where execution returns
- Saved base pointer (EBP/RBP) - stack frame reference
- Local variables - can be manipulated for logic bypasses
This happens with unsafe functions that lack bounds checking:
strcpy, strcat, sprintf, gets (always vulnerable)
fgets, read, memcpy (vulnerable if length > buffer size)
Finding Stack Overflow Offsets
Step 1: Confirm the vulnerability exists
Send a large input of As and look for a crash with 0x41414141 in registers:
python3 -c 'print("A"*1000)' | ./vulnerable_binary
A segmentation fault with EIP/RIP = 0x41414141 confirms the overflow.
Step 2: Find the exact offset to EIP/RIP
Use a De Bruijn sequence - a cyclic pattern where every n-byte subsequence appears exactly once. This lets you find the offset by searching for the value that overwrote EIP.
With pwntools:
from pwn import *
pattern = cyclic(1000)
eip_value = p32(0x6161616c)
offset = cyclic_find(eip_value)
print(f"Offset to EIP: {offset}")
With GEF (GDB plugin):
pattern create 200
pattern search $eip
pattern search "avaaawaa"
Exploitation Techniques
Ret2Win
When a binary contains a hidden "win" function that's never called:
- Find the offset to overwrite EIP/RIP
- Find the address of the win function (ASLR usually disabled)
- Overwrite return address with the function's address
Payload structure:
[padding to offset][address of win function]
Stack Shellcode
Place shellcode on the stack and redirect execution to it:
- Find offset to EIP/RIP
- Place shellcode in the buffer (after padding, before return address)
- Overwrite EIP/RIP with address of shellcode location
Payload structure:
[padding][shellcode][padding][address of shellcode]
Note: Requires executable stack (NX disabled). Use ROP if NX is enabled.
Windows SEH Overflow (32-bit)
On Windows, overflow the Structured Exception Handler chain:
- Overwrite nSEH (next SEH) with a short jump (e.g.,
\xeb\xfe)
- Overwrite SEH pointer with a
POP POP RET gadget
- Place shellcode before nSEH
Payload structure:
[padding][nSEH: short jmp][SEH: POP POP RET][shellcode]
ROP (Return-Oriented Programming)
Bypass NX (non-executable stack) by chaining existing instructions:
- Find gadgets ending in
RET (e.g., pop rdi; ret)
- Build a chain to set up function calls
- Call
system("/bin/sh") or similar
Common ROP chain for system("/bin/sh"):
[padding]
[address of pop rdi; ret]
[address of "/bin/sh" in binary]
[address of system()]
[address of exit()]
Real-World Exploitation Patterns
Delimiter-Driven Multi-NUL Placement
When a parser uses delimiters (like :) and adds NUL terminators:
- Each delimiter restarts parsing and adds a trailing NUL
- Use multiple overlong tokens to place NUL bytes at different offsets
- Critical for non-PIE binaries with addresses containing NUL bytes
Example (Grandstream CVE-2026-2329):
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA:BBBBBBBBBBBBBBBBBBBBB:CCCCCCCCCCCCCCCCCCCC:DDDDDDDDDDD:EEE
Crash-Oracle Bruteforcing
When a service forks per request (same canary/stack layout):
- Use HTTP status code as oracle (200 = success, 502/crash = failure)
- Brute-force each byte serially
- Recover canary, stack pointer, and library base addresses
Example (Synology CVE-2025-12686):
def bf_next_byte(prefix):
for guess in range(0x100):
if send_request(prefix + bytes([guess])).status_code == 200:
return bytes([guess])
raise RuntimeError("oracle lost sync")
Chunked Transfer-Encoding Amplification
Force unbounded stack allocation via HTTP chunked encoding:
- Each chunk creates internal buffer segments
- Server allocates stack memory per segment
- Thousands of small chunks exhaust the stack
Example (NVIDIA Triton CVE-2025-23310):
for _ in range(523_800):
s.send(b"1\r\nA\r\n")
Common Protections and Bypasses
| Protection | What it does | Bypass |
|---|
| ASLR | Randomizes memory addresses | Info leak + brute force, or disable |
| NX/DEP | Marks stack non-executable | ROP chains |
| Stack Canary | Random value before return address | Leak canary, or overflow past it |
| PIE | Position-independent executable | Leak base address |
Workflow Checklist
When analyzing a stack overflow:
- Confirm vulnerability - Send large input, check for crash
- Find offset - Use De Bruijn sequence with pwntools or GEF
- Check protections - Run
checksec or equivalent
- Choose technique:
- No protections → simple shellcode
- NX only → ROP chain
- Canary → leak or brute force
- ASLR/PIE → info leak needed
- Craft payload - Padding + exploit data + return address
- Test and iterate - Debug with GDB, adjust offsets
Tools Reference
- pwntools - Python exploitation framework
- GDB + GEF - Debugging with pattern generation
- checksec - Check binary protections
- objdump/readelf - Find function addresses and gadgets
- ROPgadget - Find ROP gadgets in binaries
Example Exploit Template
from pwn import *
p = process('./vulnerable')
offset = 72
win_addr = 0x08048500
payload = b"A" * offset
payload += p32(win_addr)
p.sendline(payload)
p.interactive()
When to Use This Skill
Use this skill when:
- You're working on a CTF binary exploitation challenge
- You need to analyze a stack overflow vulnerability
- You're crafting an exploit for a vulnerable program
- You need to understand ret2win, shellcode, ROP, or SEH techniques
- You're researching real-world CVEs with stack-based vulnerabilities
- You need help finding offsets or understanding protection bypasses