Never call any formatted I/O function with a format string containing user input.
An attacker who can fully or partially control the contents of a format string, can exploit to crash the program, view the contents of the stack, view memory content, or write to an arbitrary memory location and consequently execute arbitrary code with the permissions of the vulnerable process.
Formatted output functions are particularly dangerous because many programmers are unaware of their capabilities (for example, they can write an integer value to a specified address using the {{%n}} conversion specifier) \[[Seacord 05|AA. C References#Seacord 05]\]. |
In this non-compliant code example, the input is output directly as a format string. By putting %n
in the input, the user can write arbitrary values to whatever the stack happens to point to. This can frequently be leveraged to execute arbitrary code. In any case, by including other point operations (such as %s
), fprintf()
will interpret values on the stack as pointers. This can be used to learn secret information and almost certainly can be used to crash the program.
char input[1000]; if (fgets(input, sizeof(input)-1, stdin) == NULL) { /* handle error */ } input[sizeof(input)-1] = '\0'; fprintf(stdout, input); |
In this example, the library function syslog()
interprets the string msg
as a format string, resulting in the same security problem as before. This is a common idiom for displaying the same message in multiple locations or when the message is difficult to build.
void check_password(const char *user, const char *password) { if (strcmp(lookup_password(user), password) != 0) { size_t len = strlen(user) + 100; char *msg = (char *)malloc(len); if (!msg) { /* handle error condition */ } snprintf(msg, len, "%s password incorrect", user); fprintf(stderr, msg); syslog(LOG_INFO, msg); free(msg); } } |
This example outputs the string directly instead of building it and then outputting it.
void check_password(const char *user, const char *password) { if (strcmp(lookup_password(user), password) != 0) { fprintf (stderr, "%s password incorrect", user); } } |
In this example, the message is built normally but is then output as a string instead of a format string.
void check_password(const char *user, const char *password) { if (strcmp(lookup_password(user), password) != 0) { size_t len = strlen(user) + 100; char *msg = (char *)malloc(len); if (!msg) { /* handle error condition */ } snprintf(msg, len, "%s password incorrect", user); fprintf(stderr, "%s", user); syslog(LOG_INFO, "%s", msg); free(msg); } } |
Failing to exclude user input from format specifiers may allow an attacker to execute arbitrary code.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
FIO30-C |
3 (high) |
3 (likely) |
3 (low) |
P27 |
L1 |
Two recent examples of format string vulnerabilities resulting from a violation of this rule include [Ettercap|http://ettercap.sourceforge.net/history.php] and [Samba|http://samba.org/samba/security/CVE-2007-0454.html]. In Ettercap v.NG-0.7.2, the ncurses user interface suffers from a format string defect. The {{curses_msg()}} function in {{ec_curses.c}} calls {{wdg_scroll_print()}}, which takes a format string and its parameters and passes it to {{vw_printw()}}. The {{curses_msg()}} function uses one of its parameters as the format string. This input can include user-data, allowing for a format string vulnerability \[[VU#286468|AA. C References#VU286468]\]. The Samba AFS ACL mapping VFS plug-in fails to properly sanitize user-controlled filenames that are used in a format specifier supplied to {{snprintf()}}. This [security flaw|BB. Definitions#security flaw] becomes exploitable when a user is able to write to a share that uses Samba's {{afsacl.so}} library for setting Windows NT access control lists on files residing on an AFS file system. |
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
\[[ISO/IEC 9899-1999|AA. C References#ISO/IEC 9899-1999]\] Section 7.19.6, "Formatted input/output functions" \[[MITRE 07|AA. C References#MITRE 07]\] [CWE ID 134|http://cwe.mitre.org/data/definitions/134.html], "Uncontrolled Format String" \[[Seacord 05|AA. C References#Seacord 05]\] Chapter 6, "Formatted Output" \[[Viega 05|AA. C References#Viega 05]\] Section 5.2.23, "Format string problem" \[[VU#286468|AA. C References#VU286468]\] \[[VU#649732|AA. C References#VU649732]\] |
FIO15-A. Avoid taking conditional actions based on path or file names 09. Input Output (FIO) FIO31-C. Do not simultaneously open the same file multiple times