Skip to content

Detecting a classic buffer overflow

Wei Ming Khoo edited this page Oct 25, 2018 · 9 revisions

A classical example would be (see also misprint.c):

/* misprint.c */
#include <stdio.h>
#include <stdlib.h>
#include "taintgrind.h"

void hello_function()
{
    printf("INFO: Hello World!\n");
}

/* 
 * $ VAL=`readelf -s misprint | grep secret_function | awk '{print $2}'` && printf "%d\n" 0x$VAL
 */
void secret_function()
{
    printf("INFO: Oh no! The application is compromised!\n");
}

int main(int argc, char** argv)
{
    int i;
    int val;
    int iter;
    int buffer[10];
    int canary;
    void (*func)(void);

    if (argc != 3) { return(1); }

    iter = atoi(argv[1]);
    val = atoi(argv[2]);

    TNT_TAINT(&val, sizeof(val));

    /* It should print Hello World! */
    func = &hello_function; 

    //canary = UNINTIALIZED;

    /* If iter > 10 then a buffer overflow will occur */
    for (i = 0; i < iter; i++)
        buffer[i] = val;

    /* 
     * ... if the buffer overflow is "severe enough", 
     * it may overwrite the function pointer with user data, 
     * e.g. a pointer to the secret function
     */
    func();

    return(0);
}

Compile the application:

$ cc -g -O0 -Ipath/to/taintgrind -fno-inline -fno-omit-frame-pointer -fno-stack-protector -m32 misprint.c -o misprint

or run

make check

To compile taintgrind/tests/misprint.c

Run it with "safe" parameters, it simply prints Hello World.

$ ./misprint 1 1
INFO: Hello World!

Run it with parameters that lead to a buffer overrun attack (you may have to find the pointer to the secret function):

$ VAL=`readelf -s misprint | grep secret_function | awk '{print $2}'` && printf "%d\n" 0x$VAL
134513809
$ ./misprint 12 134513809
INFO: Oh no! The application is compromised!

Running this test case with valgrind --tool=taintgrind -- taintgrind/tests/misprint 12 134513924 gives this output

0x8048615: main (misprint.c:45) | STle(t59) = t55 | Store | 0x8048504 | canary <- t55_448
...
0x8048623: main (misprint.c:44) | t14 = LDle:I32(t12) | Load | 0x8048504 | t14_7979 <- val
...
0x8048615: main (misprint.c:45) | STle(t18) = t14 | Store | 0x8048504 | func <- t14_7979
...
0x8048625: main (misprint.c:52) | t5 = LDle:I32(t3) | Load | 0x8048504 | t5_11954 <- func
0x8048628: main (misprint.c:52) | JMP t5_11953 | Jmp | 0x8048504 | t5_11954

The jump target at line 52 is tainted. Taint flows from value to func to the jump.

Generate the taint graph by running:

valgrind --tool=taintgrind -- taintgrind/tests/misprint 12 134513924 2>&1 | python taintgrind/log2dot.py | tee misprint.dot
dot -Tpng misprint.dot -o misprint.png

The tainted jump is highlighted in red. misprint

Credit to Giuseppe Di Guglielmo for the test case