
Understanding Format String Attacks and Functions
Learn about format string vulnerabilities, abusing format strings, reading and writing to memory, finding bugs, and defining functions with variable numbers of arguments using format strings in C/C++ programming. Explore examples and concepts to enhance your understanding.
Download Presentation

Please find below an Image/Link to download the presentation.
The content on the website is provided AS IS for your information and personal use only. It may not be sold, licensed, or shared on other websites without obtaining consent from the author. If you encounter any issues during the download, it is possible that the publisher has removed the file from their server.
You are allowed to download the files provided on this website for personal or commercial use, subject to the condition that they are used lawfully. All files are the property of their respective owners.
The content on the website is provided AS IS for your information and personal use only. It may not be sold, licensed, or shared on other websites without obtaining consent from the author.
E N D
Presentation Transcript
Outline What Is a Format String Format Functions Ellipsis and va_args Summary Using Format Strings Format Tokens Types of Format Specifiers Summary Format String Vulnerability Abusing Format Strings Reading Memory Writing to Memory Summary Finding Format String Bugs FlawFinder 2
What Is a Format String Printf( username:%s,userID:%d ,str,ID) This is a format string The Numbers of Arguments is Variable 4
C Functions with Variable Numbers of Arguments There are functions in C/C++ (printf() being one of them) that do not have a fixed list of arguments. Do you know how to defining a functions with Variable Numbers of Arguments? 6
Variable_args function Consider an Example format1.c: a function with variable numbers of arguments // #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v)) // #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) _INTSIZEOF(t)) ) // #define va_end(ap) ( ap = (va_list)0) 7
Variable_args function output: 8
Variable_args function Let s see what happens if we supply our function with an incorrect number of arguments for example, passing less values than count. To do this, we change the following lines: Why output this data? 9
Correct Stack Operation with va_args We know how a stack can be used to pass arguments to functions and store local variables. Let s see how stack is operated in case of correct and incorrect calls to the print_int function. 10
Stack of print_ints(4,1,2,3,4) Caller s data Direction of stack growth 4 3 2 arg_list 1 Tell the function print_ints to print 4 integers 4 Saved EIP Saved EBP ESP Locals for print_ints() 11
Incorrect Stack Operation with va_args Now compare this with the case when the number of arguments passed is less than the function thinks. Illustrates a few last iterations of print_ints (6, 1,2,3,4); in the call in format2.c. 12
Stack of print_ints(6,1,2,3,4) Caller s data Caller s data Direction of stack growth Caller s data 4 3 arg_list 2 1 Tell the function print_ints to print 6 integers 6 Saved EIP Saved EBP ESP Locals for print_ints() 13
Summary What Is a Format String? ANSI C standard defines a way of allowing programmers to define functions with a variable number of arguments. These functions use special macros for reading supplied arguments from the stack. Only a function itself may decide that it has exhausted the supplied parameters. No independent checks are done. Functions of formatted output belong to this category.They decide upon the number and types of arguments passed to them based on their special argument called the format string. 14
Using Format Strings Consider an Example format3.c : a function which contains only a printf() function: 1 2 3 4 5 6 7 8 9 /*------printf()-------*/ #include <stdio.h> #include <string.h> void function(int n) { printf("Number of patameters the stack : %d\n",n); } int main() { function(2); return 0; } 10 11 12 16
Assembly code Disassembling the function on dgb: 17
Assembly code <+0 and +1> Are the preface of the function. <+3 and +6> Allocate the space on the stack. <+9> Push the parameter n to the stack. <+12> Push the address of format string to the stack. On (gdb),we input x/s 0x80484f0 to watch what the address 0x80484f0 contains. 18
Format Tokens and printf() Arguments Formatting function interpret the input format string, whenever encountered a character % , fetch the data from memory(except %n). args Format string printf( int = %d. Str = %s\n , i, str); 19
Types of Format Specifiers There are many different format specifiers available for various types of arguments printed; each of them can also have additional modifiers and field-width definitions. Following is a few main tokens that are of interest to us in the study of format string attacks. 20
Types of Format Specifiers Argument Type int, short or char int, short or char unsigned int, short or char Token What Is Printed %i Integer value of an argument in decimal notation %d Same as %i Value of argument as an unsigned integer in decimal Notation %u unsigned int, short or char Value of argument as an unsigned integer in hex Notation %x %s Char *, char[] Character string pointed to by the argument Value of the pointer is printed in hex notation. For example, if used instead of %s for a string argument, it will output the value of the pointer to the string rather than the string itself Nothing is printed. Instead, the number of bytes output so far by the function is stored in the corresponding argument, which is considered to be a pointer to an integer. %p (void *) %n (Int *) 21
The token of %n 1 2 3 4 5 6 7 8 9 /*------------------------ Format4.c ---------------------------*/ #include <stdio.h> int main() { int num = 0x61616161; /*before write*/ printf("before : num = %#x \n",num); /*use %n write to num*/ printf("AAAAAAAAAAAAAAAAAAAA%n\n",&num); /*after above printf*/ printf("after1 : num = %#x\n",num); 10 11 12 13 14 15 16 17 18 19 20 /*use %xn write to num*/ printf("%40d%n\n",num,&num); /*after above printf*/ printf("after2 : num = %#x\n",num); return 0; } 22
Result Output for program is : Can be seen from the above picture, %d can control the length of the output. 23
Summary Using Format Strings A format string consists of format tokens. Each token describes the type of value being printed and the number of characters it will occupy. Each token corresponds to an argument of the function. One special token %n is not used for printing. Instead, it stores the number of characters that have been printed into a corresponding variable, which is then passed to the function as a pointer. 24
Abusing Format Strings for example: printf ("%x\n%x\n\%x\n%x"); will result in output similar to this: 26
Abusing Format Strings Sometimes programmers use printf(buf); instead of printf("%s", buf); to print a string. There will be a Vulnerability we can use. 27
Abusing Format Strings 1 2 3 4 5 6 7 8 9 //format5.c : Common Programming Mistakes /* the good, the bad and the ugly*/ #include "stdio.h" #include "stdarg.h" void main(int argc, char *argv[]) { char str[256]; if (argc < 2) { printf("usage: %s <text for printing>\n", argv[0]); exit(0); } strcpy(str, argv[1]); printf("The good way of calling printf:\n"); printf("%s\n", str); printf("The bad way of calling printf:\n"); printf(str); printf("\n"); } 10 11 12 13 14 15 16 17 18 19 28
Abusing Format Strings In this example, the second value in argument array argv[] (usually the first command-line argument) is passed to printf() as the format string. If format specifiers have been included in the argument, they will be acted upon by the printf function: 29
Reading Memory If the output of the formatting function is available for viewing, attackers can also exploit these vulnerabilities to read the process stack and memory. we can use %s,%x to read memory. 30
Example for Reading Memory 1 2 3 4 5 6 7 8 9 //format6.c : Common Programming Mistakes /* the good, the bad and the ugly*/ #include "stdio.h" #include "stdarg.h" void main(int argc, char *argv[]) { char str[256]; if (argc < 2) { printf("usage: %s <text for printing>\n", argv[0]); exit(0); } Let s see how this string is constructed in the case of our simple example based on format5.c program (namely format6.c): 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 char password[100]; printf("please input the password: "); scanf("%s", password); printf("The address of password is : %p\n", &password); strcpy(str, argv[1]); printf("The good way of calling printf:\n"); printf("%s\n\n", str); printf("The bad way of calling printf:\n"); printf(str); printf("\n\n"); } 31
Example for Reading Memory We will run our program first with the dummy: 32
Stack of format6.c at code line23 ..................... 0xfffffff (top of stack) AAAA_%x_%x...... arg[1] . . . AAAA_%x_%x...... str[256] main s stack frame . . . . . . password[100] Address of farmat string paramater of printf() return address ebp printf s stack frame 33
Parsing Format string ..................... printf 0xfffffff (top of stack) \0 AAAA_%x_%x...... . . . AAAA_%x_%x...... _%x main s stack frame address increase _%x_%x_%x_%x...... . . . . . . AAAA Address of farmat string return address printf s stack frame ebp AAAA_bfffef6c ...... _41414141 34
Example for Reading Memory As you can see, there is 41414141 in the output it is clearly the beginning of our format string. Now we can change the first four bytes of our string to the address we want to start dumping data from, and the last %x into %s. For example, we will dump contents of the password located at 0xbfffef08 35
Example for Reading Memory Using Perl to generate the required format string, we see: (note that we must close the ASLR) 36
Writing to Memory We can use %n to write the memory . printf( abcdefg%n ,&x) length of output=7 This while write the length of output to x. The value of x will be 7. 37
Example for Writing to Memory 1 2 3 4 5 6 7 8 9 /* --------------------- Format6.c ---------------*/ #include <stdio.h> #define SECRET1 0x44 #define SECRET2 0x00 int main(int argc, char *argv[]) { char user_input[100]; int *secret; int int_input; 10 11 12 13 14 15 16 17 18 /* The secret value is stored on the heap */ secret = (int *) malloc(2*sizeof(int)); /* getting the secret */ secret[0] = SECRET1; secret[1] = SECRET2; printf("The variable secret's address is 0x%8x (on stack)\n", &secret); printf("The variable secret's value is 0x%8x (on heap)\n", secret); printf("secret[0]'s address is 0x%8x (on heap)\n", &secret[0]); printf("secret[1]'s address is 0x%8x (on heap)\n", &secret[1]); 38
Example for Writing to Memory 1 2 3 4 5 6 7 8 9 printf("Please enter a decimal integer\n"); scanf("%d", &int_input); printf("Please enter a string\n"); scanf("%s", user_input); /* getting a string from user */ /* getting an input from user */ /* Vulnerable place */ printf(user_input); printf("\n"); 10 11 12 13 14 15 16 /* Verify whether your attack is successful */ printf("The original secrets: 0x%x -- 0x%x\n", SECRET1, SECRET2); printf("The new secrets: 0x%x -- 0x%x\n", secret[0], secret[1]); free(secret); return 0; } 39
Example for Writing to Memory AAAA 40
Example for Writing to Memory As you can see, there is 00000001 in the output it is clearly the variable of the int_input . Now we can change the int_input of our destination to the address we want to writting to memory, and the fifth %08x into %n. For example, we will modify the contents of the secret[1] located at 0x0804b00c, we can make the int_input as the decimal of the address of the secrete[1], and use the %d control the output length, and use the %n writting the length of output to the content of the address of secret[1]. 41
Example for Writing to Memory 134524940 0x804b00c Write to address 0x804b00c with (4 + 3 * 8 + 263) = 291 use %n 0x123 = 291 42
Question Can you write the return address through %n? For example, if we want to write the return address with 0x08048555 at 0xffff0f4 in the stack. The difficultity is that function printf() don't allow us to print a string with a very large length 43
Write the return address Write 0x08048555 to 0xffff0f4 meam: write X1(0x55) to 0xffff0f4 write X2(0x85) to 0xffff0f5 write X3(0x04) to 0xffff0f6 write X4(0x08) to 0xffff0f7 There is a constarint X4 > X3 > X2 > X1 ,do you know why? 44
Write the return address Because the string print on the screen is always increasing. We can write X1(0x55) to 0xffff0f4 write X2(0x85) to 0xffff0f5 write X3(0x104) to 0xffff0f6 write X4(0x208) to 0xffff0f7 00 00 01 00 00 04 00 85 55 00 00 00 + 00 00 02 08 = 08 04 85 55 45
Summary When the number of format tokens exceeds the number of supplied values, the functions of formatted output continue reading and writing data from the stack, assuming the place of missing values. When an attacker is able to supply his own format string, he will be able to read and write arbitrary data in memory. This ability allows the attacker to read sensitive data such as passwords, inject shellcode, or alter program behavior at will. 46
Finding Format String Bugs This step is comparatively easy. If source code is available, simply GREP (global regular expressions parser) for functions producing formatted output and have a look at their arguments. FlawFinder is a simple program that examines C/C++ source code and reports possible security weaknesses ( flaws ) sorted by risk level. 48
FlawFinder Flawfinder is specifically designed to be easy to install and use. After installing it, at a command line just type: 49
FlawFinder 50