Testing for Format String Injection (WSTG-INPV-13)
Last updated
Last updated
WSTG-INPV-13
A format string is a null-terminated character sequence that also contains conversion specifiers interpreted or converted at runtime. If server-side code , an attacker can append additional conversion specifiers to cause a runtime error, information disclosure, or buffer overflow.
The worst case for format strings vulnerabilities occur in languages that don't check arguments and also include a %n
specifier that writes to memory. These functions, if exploited by an attacker modifying a format string, could cause :
C and C++ and similar methods fprintf, sprintf, snprintf
Perl and sprintf
These format string functions cannot write to memory, but attackers can still cause information disclosure by changing format strings to output values the developers did not intend to send:
Python 2.6 and 2.7 and Python 3 unicode can be modified by injecting strings that can point to in memory
The following format string functions can cause runtime errors if the attacker adds conversion specifiers:
Java and
PHP
The code pattern that causes a format string vulnerability is a call to a string format function that contains unsanitized user input. The following example shows how a debug printf
could make a program vulnerable:
The example in C:
The example in Java:
Assess whether injecting format string conversion specifiers into user-controlled fields causes undesired behavior from the application.
Tests include analysis of the code and injecting conversion specifiers as user input to the application under test.
Static analysis tools can find format string vulnerabilities in either the code or in binaries. Examples of tools include:
Static analysis may miss more subtle cases including format strings generated by complex code. To look for vulnerabilities manually in a codebase, a tester can look for all calls in the codebase that accept a format string and trace back to make sure untrusted input cannot change the format string.
The examples in the following subsections have a URL of this form:
https://vulnerable_host/userinfo?username=x
The user-controlled value is x
(for the username
parameter).
https://vulnerable_host/userinfo?username=%25s%25s%25s%25n
If the web site is vulnerable, the browser or tool should receive an error, which may include a timeout or an HTTP return code 500.
The Java code returns the error
java.util.MissingFormatArgumentException: Format specifier '%s'
Depending on the C implementation, the process may crash completely with Segmentation Fault
.
fuzz.txt:
The fuzz.txt
file contains the following:
A valid input alice
to verify the application can process a normal input
Two strings with C-like conversion specifiers
One Python conversion specifier to attempt to read global variables
To send the fuzzing input file to the web application under test, use the following command:
wfuzz -c -z file,fuzz.txt,urlencode https://vulnerable_host/userinfo?username=FUZZ
In the above call, the urlencode
argument enables the appropriate escaping for the strings and FUZZ
(with the capital letters) tells the tool where to introduce the inputs.
An example output is as follows
The above result validates the application's weakness to the injection of C-like conversion specifiers %s
and %p
.
In this particular example, if the attacker set their userName
to have one or more conversion specifiers, there would be unwanted behavior. The C example would if userName
contained %p%p%p%p%p
, and it can corrupt memory contents if there is a %n
in the string. In the Java example, a username
containing any specifier that needs an input (including %x
or %s
) would cause the program to crash with IllegalFormatException
. Although the examples are still subject to other problems, the vulnerability can be fixed by printf arguments of printf("DEBUG Current user: %s", userName)
.
C and C++:
Java: FindSecurityBugs rule
PHP: String formatter Analyzer in
Testers can check at the unit test or full system test level by sending conversion specifiers in any string input. the program using all of the conversion specifiers for all languages the system under test uses. See the page for possible inputs to use. If the test fails, the program will crash or display an unexpected output. If the test passes, the attempt to send a conversion specifier should be blocked, or the string should go through the system with no issues as with any other valid input.
Testers can perform a manual test using a web browser or other web API debugging tools. Browse to the web application or site such that the query has conversion specifiers. Note that most conversion specifiers need if sent inside a URL because they contain special characters including %
and {
. The test can introduce a string of specifiers %s%s%s%n
by browsing with the following URL:
Fuzzing tools including can automate injection tests. For wfuzz, start with a text file (fuzz.txt in this example) with one input per line: