Question

I'm going through tutorials on formatstring vulnerabilities to learn how to code more securely. The program I've written so far is as follows:

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

int main(int argc, char *argv[]) {
    char text[100];
    strcpy(text, argv[1]);

    printf(text);
}

I'm running it like this:

>>> ./foo $(ruby -e 'print "AAAA" + "%08x."*9 + "%x"')
AAAAffe466f4.00000001.f763b1c9.ffe458df.ffe458de.00000000.ffe459c4.ffe45964.00000000.41414141

I can see the "41414141" at the end, which is the AAAA at the beginning of the string. However, when I use "%s" instead like so:

>>> ./foo $(ruby -e 'print "AAAA" + "%08x."*9 + "%s"')

I get a segfault. Can anyone point me in the right direction?

Was it helpful?

Solution

The thing is that at this point, you reach raw AAAA on the stack; however, the %s specifier expects a pointer to a string, i.e. the address of your AAAA, instead. There is no format string specifier for what you want to do as in the normal course of execution you wouldn't have a string pasted directly as printf()'s parameter; one idea would be %c%c%c%c to at least print the data as characters instead of hex values, but that will not work either as the smallest size of a parameter in C is an int and even the %c specifier works with int-sized parameter memory region.

OTHER TIPS

It's generally undefined behaviour to use printf on a dynamic string, since you can't guarantee that the string isn't free of format specifiers. The correct thing is to say,

printf("%s", text);

or just

puts(text);

Now, that said, your first example comes down to printf("%x%x");. This is of course UB, but the two %x specifiers just make you read a bounded amount off the stack (two words), which will print garbage, but only a finite amount.

On the other hand, when you say printf("%s"), the function expects a pointer to a null-terminated sequence of bytes in a memory region which you do not control! Essentially, the function will read one word off the stack, pretend it is a pointer, and read the memory pointed to by that value -- which will almost certainly cause a segmentation fault, since you aren't allowed to access most memory addresses by default. And even if the address points into memory you're allowed to access, there's no reason there should be a zero byte coming up soon, and so you may well just run off the page and into illegal memory.

In test you have at the end %s. printf expects a char-pointer when it encounters a %s but you don't provide any --> segfault. Use puts instead or printf("%s", test);

$ ruby -e 'print "AAAA" + "%08x."*9 + "%x"'
AAAA%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%x

$ ruby -e 'print "AAAA" + "%08x."*9 + "%s"'
AAAA%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%s

Both strings are invalid for printf because you are not passing the arguments required.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top