Sunday, January 1, 2017

Format String Vulnerability – Information Leakage

Format string vulnerability is one of those bugs which you may not even recognize that you are actually introducing a vulnerability by doing things “the easy way”. While I’m not a programmer by profession, I have made the mistake in code I’ve developed. Realistically compiling and running the program in most cases works just as well as if you were to do it the “correct way”.

While this post focuses on information leakage as a result of format string vulnerability and the other on overwriting memory, there are more that could be done to a program such as crashing a program.

Let’s start off with the code.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
 * fmtstr_info_leak.c
 * Sample code demonstrating Format String information leakage
 * Author: Nik Alleyne < nikalleyne at gmail dot com >
 * blog: http://securitynik.blogspot.com
 * Date: 2017-01-01
 */

#include <stdio.h>

int main( int argc, char **argv )
  {
    // Putting some stuff on the stack
    char *str1 = " Pop pop, it's show time (Show time) \n";
    char *str2 = " Guess who's back again? \n";

    // Correct way to code 
    //printf("%s", argv[1]);

    // Wrong way to code - introduces vulnerability
    printf(argv[1]);
    return 0;
  }



Let’s now compile this code using “gcc -ggdb -m32 -mpreferred-stack-boundary=2 -fno-stack-protector fmtstr_info_leak.c -o fmtstr_info_leak.exe”



Figure 1: code being compiled. Note the compiler’s warning about “printf”

Now that we’ve compiled the code, let’s run it.

Figure 2: Code run and user input echoed.

Looking at figure 2, we see that when the word “SecurityNik” was entered this was echoed back to the user. So far so good, no harm done. However, what about if we were to enter “%s %s” as the input, what would happen? Let’s find out.

Figure 3: Information leaked

What just happen there?
Well what we did was to print the next two values on the stack. These values being 2 strings. “printf” expected its arguments to be represented via one or more format specifiers. As a result when we used “%s %s” specifiers the next two values on the stack were picked up. Look at it this way, if we had “%s” as in only one “%s”, we would have printed the next value on the stack.

Looking deeper
To get a better understanding of this let’s take a look at what the stack looks like at the time we called “printf”. Similar to the buffer overflow post, let’s load our code in GDB using “gdb ./fmtstr_info_leak.exe -q”. Once we “list” our code, let’s set a breakpoint at line 21.

Figure 4: Code listing in GDB with breakpoint set at line 21.

Once we have our code listing and breakpoint set. Let’s go ahead and “run “%s%s” the program, take a step (“s) and take a look at the stack.

Figure 5: Stack printed

Ok so what do we have above? Let’s break this down.
1 – First up run our code with two format specifiers %s%s
2 – We then stepped once through the program
3 – When we examined 8 hex words (x/8xw) on the stack from the perspective of the $esp register, we see those 8 hex words are printed. For the purpose of this post, the only ones that matter are the first 3 which are selected.

Let’s now analyze this.
4 – In 4, we examined 1 string (x/1s) at memory location ‘0xffffd22d’. Note this value is the same as the first item highlighted in 3. What we see here is our “%s%s”. These are the format specifiers we provided to “printf”. This now means it will pickup the next two strings on the stack.
5 – Here we pickup the next value on the stack which is at memory location “0x08048507”. When we examine that memory location – x/1s 0x08048507 - the value here points to our string “ Guess who's back again? \n”
6 – Similarly, when we examine the memory location at “0x080484e0” – x/1s 0x080484e0, we see our next string.

So as we stated, “printf” expects to have format specifiers. Thus when we provided our two %s%s “printf” picked up the next values from the stack and presented it to us.

Alternatively, we could have printed the stack in hex using “./fmtstr_info_leak.exe "%x %x %x %x"”. This would have produced “8048507 80484e0 0 f7e1caf3”

Defenses – Protecting yourself from this vulnerability
Now believe it or not, fixing this vulnerability is quite easy. Way too easy!! Our code above has “printf(argv[1])”. All we need to do to fix this is “printf("%s", argv[1])”. This would immediately invalidate any attempt to take advantage of this vulnerability.

Your turn! Fix the code and run it again. Post your output in the comments section after you run “./fmtstr_info_leak.exe %s%s” or “./fmtstr_info_leak.exe %x%x%x%x”.


References:
Tim Newsham - Guardent, Inc. - Format String Attacks
Syracuse University Lecture Notes – Format String Vulnerability
Stanford - scut / team teso – Exploiting Format String Vulnerabilities
Saif El-Sherei - Format String Exploitation - Tutorial
Format String Vulnerability I & II
Paul Haas - Advanced Format String Attacks
Stonybrook – Format String Attacks
Wei Wang - Format String Vulnerability
Format String Vulnerabilities
Blind Format String Attacks
SP&E – Buffer Overflow and Format String Overflow Vulnerabilities
USENIX: FormatGuard: Automatic Protection From printf  Format String Vulnerabilities
Yan Huang - Heap Overflows and Double-Free
Lok Kwong Yan - CS392/681 – Polytechnic University - An Introduction to Buffer Overflows and Format String Vulnerabilities
Format string exploitation on windows Using Immunity Debugger / Python
Andreas Thuemmel - Analysis of Format String Bugs

No comments:

Post a Comment