
Never call any call a formatted I/O function with a format string containing user input.
Wiki Markup |
---|
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. See \[[Seacord 05|AA. C References#Seacord 05]\] for a detailed explanation of how format string vulnerabilities may be exploited. |
Formatted a tainted value . 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. Consequently, the attacker can execute arbitrary code with the permissions of the vulnerable process [Seacord 2013b]. Formatted output functions are particularly dangerous because many programmers are unaware of their capabilities (for . For example, they can formatted output functions can be used to write an integer value to a specified address using the %n
conversion specifier).
...
Noncompliant Code Example
This non-compliant code example illustrates the The incorrect_password()
function which in this noncompliant code example is called during identification and authentication if to display an error message if the specified user is not found or {the password }} is incorrect to display an error message. The function accepts two strings that originated from an untrusted, unauthenticated user: user
and password
the name of the user as a string referenced by user
. This is an exemplar of untrusted data that originates from an unauthenticated user. The function constructs an error message which that is then output to stderr
using the C99 standard C Standard fprintf()
function.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h> #include <stdlib.h> #include <string.h> void incorrect_password(const char *user,) const{ char *password) {int ret; /* userUser names are restricted to 256 charactersor orfewer lesscharacters */ static const char msg_format[] = "%s cannot be authenticated.\n"; size_t len = strlen(user) + sizeof("%s could not be authenticated.") - 1msg_format); char *msg = (char *)malloc(len); if (!msg == NULL) { /* handleHandle error condition */ } ret = snprintf(msg, len, "%s could not be authenticated.", user);, msg_format, user); if (ret < 0) { /* Handle error */ } else if (ret >= len) { /* Handle truncated output */ } fprintf(stderr, msg); free(msg); } |
The incorrect_password()
function constructs msg
in dynamically allocated memory by first calculating calculates the size of the message, allocating allocates dynamic storage, and then constructing constructs 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 needs 1 byte less than is allocated. The snprintf()
function is commonly used for messages that are displayed in multiple locations or when the message is messages that are difficult to build. The However, 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()
.
Non-Compliant Code Example (POSIX)
Wiki Markup |
---|
This non-compliant code example is exactly the same as the previous 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. |
Compliant Solution (fputs()
)
This compliant solution fixes the problem by replacing the fprintf()
call with a call to fputs()
, which outputs msg
directly to stderr
without evaluating its contents:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
| ||||
Code Block | ||||
| ||||
void incorrect_password(const char *user,) const{ char *password) {int ret; /* userUser names are restricted to 256 charactersor orfewer lesscharacters */ static const char msg_format[] = "%s cannot be authenticated.\n"; size_t len = strlen(user) + sizeof("%s could not be authenticated.") - 1msg_format); char *msg = (char *)malloc(len); if (!msg == NULL) { /* handleHandle error condition */ } ret = snprintf(msg, len, msg_format, "%s could not be authenticated.", user); syslog(LOG_INFO, msg user); if (ret < 0) { /* Handle error */ } else if (ret >= len) { /* Handle truncated output */ } fputs(msg, stderr); free(msg); } |
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.
Compliant Solution
Compliant Solution (fprintf()
)
This compliant solution 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:This compliant solution outputs the string directly instead of building it and then outputting it.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h> void checkincorrect_password(const char *user, const char *password) { static if (strcmp(lookup_password(user), password) != 0) { fprintf (stderr, "%s password incorrect"const char msg_format[] = "%s cannot be authenticated.\n"; fprintf(stderr, msg_format, user); } } |
Compliant Solution 2
Noncompliant Code Example (POSIX)
This noncompliant code example is similar to the first noncompliant code example but uses the POSIX function syslog()
[IEEE Std 1003.1:2013] instead of the fprintf()
function. The syslog()
function is also susceptible to format-string vulnerabilitiesIn this example, the message is built normally but is then output as a string instead of a format string.
Code Block | |||||
---|---|---|---|---|---|
| |||||
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <syslog.h> void checkincorrect_password(const char *user, const char *password) { if (strcmp(lookup_password(user), password) != 0) { ) { int ret; /* User names are restricted to 256 or fewer characters */ static const char msg_format[] = "%s cannot be authenticated.\n"; size_t len = strlen(user) + 100sizeof(msg_format); char *msg = (char *)malloc(len); if (!msg == NULL) { /* handleHandle error condition */ } ret = snprintf(msg, len, "%s password incorrect"msg_format, user); if fprintf(stderr, "%s", user); (ret < 0) { /* Handle error */ } else if (ret >= len) { /* Handle truncated output */ } syslog(LOG_INFO, msg); free(msg); } |
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.
Compliant Solution (POSIX)
This compliant solution passes the untrusted user input as one of the variadic arguments to syslog()
instead of including it in the format string:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <syslog.h> void incorrect_password(const char *user) { static const char msg_format[] = "%s cannot be authenticated.\n"; syslog(LOG_INFO, msg_format, user); "%s", msg); free(msg); } } |
Risk Assessment
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 |
---|
Detectable | Repairable | Priority | Level |
---|---|---|---|
FIO30-C |
3 (high)
3 (likely)
3 (low)
P27
L1
High | Likely | Yes | No | P18 | L1 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Astrée |
| Supported via stubbing/taint analysis | |||||||
Axivion Bauhaus Suite |
| CertC-FIO30 | Partially implemented | ||||||
CodeSonar |
| IO.INJ.FMT | Format string injection | ||||||
Compass/ROSE | |||||||||
Coverity |
| TAINTED_STRING | Implemented | ||||||
Cppcheck Premium |
| premium-cert-fio30-c | |||||||
GCC |
| Can detect violations of this rule when the | |||||||
Helix QAC |
| DF4916, DF4917, DF4918 | |||||||
Klocwork |
| SV.FMTSTR.GENERIC | |||||||
LDRA tool suite |
| 86 D | Partially Implemented | ||||||
Parasoft C/C++test |
| CERT_C-FIO30-a | Avoid calling functions printf/wprintf with only one argument other than string constant | ||||||
PC-lint Plus |
| 592 | Partially supported: reports non-literal format strings | ||||||
Polyspace Bug Finder |
| CERT C: Rule FIO30-C | Checks for tainted string format (rule partially covered) | ||||||
PVS-Studio |
| V618 | |||||||
Splint |
|
Related Vulnerabilities
Two examples of format-string vulnerabilities resulting from a violation of this rule include Ettercap and Samba.
In Ettercap 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 {{the Wiki Markup ncurses
user interface suffers from a format-string defect. The curses_msg()
}} function in {{ function in ec_curses.c
}} calls {{ calls wdg_scroll_print()
}}, which takes a format string and its parameters and passes it to {{to vw_printw()
}}. The {{. The curses_msg()
}} function 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 .
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.
...
properly sanitize user-controlled file names that are used in a format specifier supplied to snprintf()
. This security flaw becomes exploitable when a user can 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.
References
Wiki Markup |
---|
\[[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]\] |
Related Guidelines
Key here (explains table format and definitions)
Taxonomy | Taxonomy item | Relationship |
---|---|---|
CERT Oracle Secure Coding Standard for Java | IDS06-J. Exclude unsanitized user input from format strings | Prior to 2018-01-12: CERT: Unspecified Relationship |
CERT Perl Secure Coding Standard | IDS30-PL. Exclude user input from format strings | Prior to 2018-01-12: CERT: Unspecified Relationship |
ISO/IEC TR 24772:2013 | Injection [RST] | Prior to 2018-01-12: CERT: Unspecified Relationship |
ISO/IEC TS 17961:2013 | Including tainted or out-of-domain input in a format string [usrfmt] | Prior to 2018-01-12: CERT: Unspecified Relationship |
CWE 2.11 | CWE-134, Uncontrolled Format String | 2017-05-16: CERT: Exact |
CWE 2.11 | CWE-20, Improper Input Validation | 2017-05-17: CERT: Rule subset of CWE |
Bibliography
[IEEE Std 1003.1:2013] | XSH, System Interfaces, syslog |
[Seacord 2013b] | Chapter 6, "Formatted Output" |
[Viega 2005] | Section 5.2.23, "Format String Problem" |
...
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