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 crash a vulnerable process, 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. See \[[Seacord 05|AA. C References#Seacord 05]\] for a detailed explanation of how format string vulnerabilities may be exploited. |
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).
This non-compliant code example shows the {{incorrect_password()}} function, which is called during identification and authentication if the specified user is not found, or the password is incorrect, to display an error message. The function accepts the name of the user as a null-terminated byte string referenced by {{user}}. This is an excellent example of data that originates from an untrusted, unauthenticated user. The function constructs an error message which is then output to {{stderr}} using the C99 \[[ISO/IEC 9899:1999|AA. C References#ISO/IEC 9899-1999]\] standard {{fprintf()}} function. |
void incorrect_password(char const *user) { /* user names are restricted to 256 characters or less */ static char const *msg_format = "%s cannot be authenticated.\n"; size_t len = strlen(user) + sizeof(msg_format); char *msg = (char *) malloc(len); if (!msg) { /* handle error condition */ } snprintf(msg, len, msg_format, user); fprintf(stderr, msg); free(msg); msg = NULL; } |
The incorrect_password()
function constructs msg
in dynamically allocated memory by first calculating the size of the message, allocating dynamic storage, and then constructing the message in the allocated memory using the snprintf()
function. The addition operations are not checked for integer overflow because the length of the string referenced by user
is known to be have a length of 256 or less. Because the %s
characters are replaced by the string referenced by user
in the call to snprintf()
, one less byte is required to store the resulting string and terminating NULL-byte character. This is a common idiom for displaying the same message in multiple locations or when the message is difficult to build. The resulting code contains a format-string vulnerability, however, because the msg
includes untrusted user input and is passed as the format-string argument in the call to fprintf()
.
fputs()
)This code example fixes the flaw in by replacing the fprintf()
call with a call to fputs()
, which does not treat msg
like a format string, but outputs it to stderr
as is.
void incorrect_password(char const *user) { /* user names are restricted to 256 characters or less */ static char const *msg_format = "%s cannot be authenticated.\n"; size_t len = strlen(user) + sizeof(msg_format); char *msg = (char *) malloc(len); if (!msg) { /* handle error condition */ } snprintf(msg, len, msg_format, user); fputs(msg, stderr); free(msg); msg = NULL; } |
fprintf()
)A simpler compliant solution merely passes the untrusted user input as one of the variadic arguments to fprintf()
and not as part of the format string, eliminating the possibility of a format-string vulnerability.
void incorrect_password(char const *user) { fprintf(stderr, "%s cannot be authenticated.\n", user); } |
This non-compliant code example is exactly the same as the first non-compliant code example, but uses the POSIX function {{syslog()}} \[[Open Group 04|AA. C References#Open Group 04]\] instead of the {{fprintf()}} function, which is also susceptible to format-string vulnerabilities. |
void incorrect_password(char const *user) { /* user names are restricted to 256 characters or less */ static char const *msg_format = "%s cannot be authenticated.\n"; size_t len = strlen(user) + sizeof(msg_format); char *msg = (char *) malloc(len); if (!msg) { /* handle error condition */ } snprintf(msg, len, msg_format, user); syslog(LOG_INFO, msg); free(msg); msg = NULL; } |
The syslog()
function first appeared in BSD 4.2 and is supported by Linux and other modern UNIX implementations. It is not available on Windows systems.
This compliant solution passes the untrusted user input as one of the variadic arguments to syslog()
instead of including it in the format string.
void incorrect_password(char const *user) { syslog(LOG_INFO, "%s cannot be authenticated.", user); } |
Failing to exclude user input from format specifiers may allow an attacker to crash a vulnerable process, 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.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
FIO30-C |
high |
likely |
medium |
P18 |
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 file names 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. |
Fortify SCA Version 5.0 is able to detect violations of this rule.
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" \[[Open Group 04|AA. C References#Open Group 04]\] [{{syslog()}}|http://www.opengroup.org/onlinepubs/009695399/toc.htm] \[[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]\] |
FIO16-A. Limit access to files by creating a jail 09. Input Output (FIO) FIO31-C. Do not simultaneously open the same file multiple times