Binary Exploitation Methodology
A structured approach to analyzing and exploiting binary vulnerabilities, particularly stack-based buffer overflows and related techniques.
When to Use This Skill
Use this methodology when:
- Analyzing a binary for vulnerabilities
- Developing exploits for CTF challenges
- Researching buffer overflow vulnerabilities
- Bypassing security protections (ASLR, PIE, NX, canaries)
- Planning exploitation strategies for compiled binaries
Phase 1: Binary Analysis
1.1 Gather ELF Information
Before attempting exploitation, understand the binary's structure:
# Basic binary info
file <binary>
readelf -h <binary>
# Check for PIE
readelf -d <binary> | grep -i type
# Check for stack canaries
readelf -s <binary> | grep -i __stack_chk
# Check for NX (non-executable stack)
readelf -l <binary> | grep GNU_STACK
# Check for ASLR
readelf -d <binary> | grep FLAGS
1.2 Identify Protections
| Protection | Check Method | Impact |
|---|---|---|
| PIE | readelf -h shows DYN type |
Addresses are randomized |
| Canary | __stack_chk_fail in symbols |
Stack overflow detection |
| NX | GNU_STACK without E flag | Stack is non-executable |
| ASLR | readelf -d FLAGS |
Memory addresses randomized |
Phase 2: Vulnerability Identification
2.1 Common Vulnerability Types
Stack Overflows
- Overwriting return pointer (EIP/RIP)
- Overwriting EBP/RBP to control ESP/RSP
- May require integer overflow to trigger
Arbitrary Write Vulnerabilities
- Format string bugs (printf family)
- Array indexing issues
- Buffer overflow to Write-What-Where via ROP
2.2 Analysis Tools
Use these tools to identify vulnerabilities:
- GDB with GEF/PEDA for debugging
- pwntools for exploit development
- radare2/ghidra for reverse engineering
- checksec for protection analysis
Phase 3: Exploitation Goals
Goal 1: Call an Existing Function (ret2win)
Scenario: A win() function exists that grants access
Without PIE and Canary:
[buffer][padding][return_address -> win_function]
With PIE: Need to leak an address first to calculate base
With Canary: Need to leak or bypass the canary value
Setting Function Parameters:
- Use ROP chain if enough gadgets exist
- Use SROP (sigreturn-oriented programming) to control registers
- Use ret2csu/ret2vdso gadgets for register control
Goal 2: Remote Code Execution (RCE)
Via Shellcode
Prerequisites: NX disabled or bypassed
Without ASLR and NX:
[shellcode][padding][return_address -> shellcode_location]
With ASLR: Use ret2esp/ret2reg to jump to stack
With NX: Use ROP to call mprotect() and make memory executable
Via Syscalls (ret2syscall)
Use case: Call execve() to run arbitrary commands
Requirements:
- Find gadgets to set syscall parameters
- Bypass ASLR/PIE to use ROP gadgets
- Consider SROP for ret2execve
Via libc (ret2libc)
Use case: Call system("/bin/sh") from libc
Scenarios:
| ASLR | PIE | Binary uses system() | Approach |
|---|---|---|---|
| No | No | Any | Static addresses work |
| Yes | No | Yes | Leak GOT entry, calculate libc base |
| Yes | No | No | Use ret2dlresolve or leak addresses |
| Yes | Yes | Any | Leak 2 addresses, calculate libc base |
ret2libc payload structure:
[padding][return_to_system][fake_return][pointer_to_/bin/sh]
Goal 3: Stack Pivoting
Use case: Off-by-one overflows or alternate EIP control
Technique: Control ESP/RSP through EBP/RBP chain
Phase 4: Eternal Loops
When a single exploitation attempt isn't enough, create loops:
4.1 ROP Chain to Main
Write the address of main() or the vulnerable function in the ROP chain to re-execute the vulnerability.
4.2 GOT Entry Modification
Overwrite exit GOT entry to point back to the vulnerable function.
4.3 .fini_array Abuse
Store two functions in .fini_array:
- Function to call the vulnerability again
- Function to call
__libc_csu_fini(which re-executes.fini_array)
Phase 5: Protection Bypasses
5.1 Bypassing ASLR
Methods:
- Leak a libc/binary address and calculate base
- Use information disclosure vulnerabilities
- Brute force (only for 32-bit or small address space)
5.2 Bypassing PIE
Methods:
- Leak any function address to calculate base
- Use GOT entries (not affected by PIE)
5.3 Bypassing NX
Methods:
- ROP chain to
mprotect()to make memory executable - Use existing executable memory (code reuse)
- Find gadgets that don't require shellcode
5.4 Bypassing Canary
Methods:
- Leak canary via format string or info disclosure
- Overwrite canary before it's checked
- Use vulnerabilities that don't trigger canary check
Phase 6: Exploit Development Workflow
Step 1: Fuzz and Identify
from pwn import *
# Find offset to return address
offset = cyclic_find(pwn.cyclic(1000))
# Test for vulnerabilities
process = process('./binary')
process.sendline(cyclic(1000))
process.wait()
Step 2: Leak Addresses (if needed)
# Leak libc address via GOT
libc_addr = u64(process.read(8).ljust(8, b'\x00'))
libc_base = libc_addr - libc.symbols['function_name']
Step 3: Build Payload
payload = flat([
cyclic(offset), # Fill to return address
libc.symbols['system'], # Call system
0, # Fake return
next(libc.search(b'/bin/sh')) # /bin/sh address
])
Step 4: Test and Refine
- Test locally first
- Handle timing issues
- Account for different environments
Common Pitfalls
- Endianness: Remember x86 is little-endian
- Bad characters: Avoid null bytes, newlines in shellcode
- Alignment: Some gadgets require stack alignment
- Timing: Race conditions in multi-process scenarios
- Environment differences: Test on target architecture
Quick Reference
ROP Chain Structure
[padding][ret][ret][ret][...][final_ret]
ret2libc Structure
[padding][system_addr][fake_ret][/bin/sh_addr]
Shellcode Structure
[nop_sled][shellcode][padding][return_to_shellcode]
Next Steps
After identifying the vulnerability type and protections:
- Choose the appropriate exploitation goal
- Select the technique based on protection status
- Develop and test the exploit
- Refine for reliability
Remember: Each binary is unique. Adapt this methodology to the specific protections and constraints you encounter.