Exploitation of formatted strings (Part 1)
The formatting string vulnerability is a software defect that allows attackers to perform read or write operations at any memory address. This tutorial focuses on C Programming programs and the use of formatted string functions.
Before we begin to understand Software defects, we must first know what a formatting string is. A formatted string is an ASCII string, which includes text and format parameters. For example,
printf("My name is: %s", "nops");
This function will return a string
My name is: nops
The first parameter of the printf function is to format the string. It mainly relies on a specifier to tell the program how to format the output. In the C program, we have many specifiers used to format strings. After these specifiers, we can fill in our content. Remember, the prefix of the specifier is always "%". In addition, the specifier has many different data types, the most common ones include:
% D-Decimal-output decimal integer % s-string-read string from memory % x-hexadecimal-output hexadecimal number % c-character-output character % p- pointer-pointer address % n-number of characters written so far
Functions that may have the formatting string vulnerability include (but are not limited to) fprintf, printf, sprintf, snprintf, etc.
This vulnerability is mainly caused by a programmer failing to filter user input. The following is an example:
#include
int main(int argc, char * argv[]) { char a[1024]; strcpy(a, argv[1]); printf(a); printf("\n"); }
This Code uses the received string as the parameter, creates a 1024 string buffer, copies the string to the buffer, and finally calls two printf functions to format the output. When the program is compiled and run normally, the first parameter obtained by the program is predictable (it is clear if you have noticed the buffer overflow vulnerability ).
root@localhost:~/#gcc test.c -o testroot@localhost:~/# ./test blahblah
However, if you carefully read the printf document, we know that the first parameter to be called is a special formatted string specifier. In our simple test code, we can see that argv [1] will be passed as a parameter to the printf function. Therefore, it is very dangerous for us to interpret the data provided by users (that is, the data provided by hackers) as formatted strings. Next, let's look at the examples of such attacks.
root@localhost:~/# ./test %s TERM_PROGRAM=Apple_Terminal
If we type % s as the attack parameter, it will expose some information about our terminal. Why? This is because the printf function considers that it is going to print the next stack address, and the data is understood as a string. This is because we use % s as the formatting string (in code it is just a variable). Next we will add more formatting strings in the vulnerability program to see what will happen.
root@localhost:~/# ./test %s.%s TERM_PROGRAM=Apple_Terminal.(null)
Currently, we have added the second formatted string parameter, which is separated by ".". The value of the next stack is null. Add the null value to the second parameter. We get the same terminal information as before. This attack directly reads values from the stack. If there are passwords and keys stored in the stack, you may want to be at risk. We try to use this technology to read more information, and the program will burst into a segmentation error.
root@localhost:~/# ./test %s.%s.%s Segmentation fault: 11
However, we can further exploit this vulnerability to push values into the stack. To better understand this working principle, we must understand the two features in the printf specification. "% n" can be used to store the number of characters written so far, the variable name is indicated by an integer in the corresponding parameter.
int i; printf("ABCDE%n", &i);
Does the printf function write 5 (the number of characters just written) to the I variable?
The second feature we need to know is the "$" operator, which allows us to select a specific parameter from the formatted string. For example,
printf("%3$s", 1, "b", "c", 4);
The result "c" is displayed ". This is because the formatted string "% 3 $ s" tells the computer "tell me the third parameter after the formatted string, and then interpret the parameter as a string ". So we can do the same.
printf("AAA%3$n");
The printf function writes the value "3" (number of input A) to the address pointed to by the third parameter. Wait. We don't have the third parameter here! Remember, printf uses consecutive parameters on the stack. In any case, printf writes "3" to an address in the stack.
Well, I personally think it's cool. We get the leaked data in the stack and an uncontrolled write-what-where (write-where ). To use this vulnerability to execute code, we can control the written content and where to write the content. We can only perform write operations at any position in the stack, which is not omnipotent. In the next section, we will talk about ShellCode development and add attack loads to this BUG so that we can control data.