Format String Vulnerability and Prevention with Example

A format string is an ASCII string that contains text and format parameters.

Example:

// A statement with format string
printf("my name is : %s\n", "Akash");

// Output
// My name is : Akash

There are several format strings that specify output in C and many other programming languages but our focus is on C.



Format string vulnerabilities are a class of bug that take advantage of an easily avoidable programmer error. If the programmer passes an attacker-controlled buffer as an argument to a printf (or any of the related functions, including sprintf, fprintf, etc), the attacker can perform writes to arbitrary memory addresses. The following program contains such an error:

filter_none

edit
close

play_arrow

link
brightness_4
code

// A simple C program with format
// string vulnerability
#include<stdio.h>
  
int main(int argc, char** argv)
{
    char buffer[100];
    strncpy(buffer, argv[1], 100);
  
    // We are passing command line
    // argument to printf
    printf(buffer);
  
    return 0;
}

chevron_right


Since printf has a variable number of arguments, it must use the format string to determine the number of arguments. In the case above, the attacker can pass the string “%p %p %p %p %p %p %p %p %p %p %p %p %p %p %p” and fool the printf into thinking it has 15 arguments. It will naively print the next 15 addresses on the stack, thinking they are its arguments:

$ ./a.out "%p %p %p %p %p %p %p %p %p %p %p %p %p %p %p"
0xffffdddd 0x64 0xf7ec1289 0xffffdbdf 0xffffdbde (nil) 0xffffdcc4 0xffffdc64 (nil) 0x25207025 0x70252070 0x20702520 0x25207025 0x70252070 0x20702520

At about 10 arguments up the stack, we can see a repeating pattern of 0x252070 – those are our %ps on the stack! We start our string with AAAA to see this more explicitly:

$ ./a.out "AAAA%p %p %p %p %p %p %p %p %p %p"
AAAA0xffffdde8 0x64 0xf7ec1289 0xffffdbef 0xffffdbee (nil) 0xffffdcd4 0xffffdc74 (nil) 0x41414141

The 0x41414141 is the hex representation of AAAA. We now have a way to pass an arbitrary value (in this case, we’re passing 0x41414141) as an argument to printf. At this point we will take advantage of another format string feature: in a format specifier, we can also select a specific argument. For example, printf(“%2$x”, 1, 2, 3) will print 2. In general, we can do printf(“%$x”) to select an arbitrary argument to printf. In our case, we see that 0x41414141 is the 10th argument to printf, so we can simplify our string1:

$ ./a.out 'AAAA%10$p'
AAAA0x41414141

Preventing Format String Vulnerabilities

  • Always specify a format string as part of program, not as an input. Most format string vulnerabilities are solved by specifying “%s” as format string and not using the data string as format string
  • If possible, make the format string a constant. Extract all the variable parts as other arguments to the call. Difficult to do with some internationalization libraries
  • If the above two practices are not possible, use defenses such as Format_Guard . Rare at design time. Perhaps a way to keep using a legacy application and keep costs down.Increase trust that a third-party application will be safe

References
https://www.owasp.org/index.php/Format_string_attack
https://www.exploit-db.com/docs/28476.pdf

This article is contributed by Akash Sharan. If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.



My Personal Notes arrow_drop_up