CERT
Skip to end of metadata
Go to start of metadata

Never call a formatted I/O function with a format string containing 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 example, formatted output functions can be used to write an integer value to a specified address using the %n conversion specifier.

Noncompliant Code Example

The incorrect_password() function in this noncompliant code example is called during identification and authentication to display an error message if the specified user is not found or the password is incorrect. The function accepts 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 that is then output to stderr using the C Standard fprintf() function.

The incorrect_password() function calculates the size of the message, allocates dynamic storage, and then constructs the message in the allocated memory using the snprintf() function. The addition operations are not checked for integer overflow because the string referenced by user is known to have a length of 256 or less. Because the %s characters are replaced by the string referenced by user in the call to snprintf(), the resulting string needs 1 byte less than is allocated. The snprintf() function is commonly used for messages that are displayed in multiple locations or messages that are difficult to build. However, the resulting code contains a format-string vulnerability because the msg includes untrusted user input and is passed as the format-string argument in the call to fprintf().

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:

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:

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 vulnerabilities.

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:

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

Remediation Cost

Priority

Level

FIO30-C

High

Likely

Medium

P18

L1

Automated Detection

Tool

Version

Checker

Description

CodeSonar4.4

IO.INJ.FMT
MISC.FMT

Format string injection
Format string

Compass/ROSE 

 

 
Coverity2017.07

TAINTED_STRING

Implemented
GCC4.3.5 

Can detect violations of this rule when the -Wformat-security flag is used

Klocwork2017

SV.FMTSTR.GENERIC
SV.TAINTED.FMTSTR

 
LDRA tool suite9.5.6

86 D

Partially Implemented
Polyspace Bug FinderR2016aTainted string format

Input format argument is from an unsecure source

Splint3.1.1  

Related Vulnerabilities

Two examples of format-string vulnerabilities resulting from a violation of this rule include Ettercap and Samba.

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.

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 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.

Related Guidelines

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"

 


9 Comments

  1. I rewrote this rule because the old formulation was bothering me for a variety of reasons. Please let me know if you see any problems with this new revision. Thanks.

  2. (1) It's actually -2 not -1 (but the wasted byte doesn't hurt).  sizeof counts the terminator too.

    (2) The format string should end in newline.

    (3) A quicker fix would have been to change fprintf(stderr,msg) to fputs(msg,stderr), which directly addresses the real bug.

    1. (1) fixed

      (2) fixed, but I'm not sure the code is portable...should it be \r on Windows?

      (3) Added an example that uses fputs as you suggest. The previous correct example is simpler, but the fputs example illustrates the bugfix better, as you pointed out.

  3. I'm not really sure this rule deserves to be a "likely" probability and "low" remediation cost... "probable" probability is better since it is not very common to snprintf() into a buffer before printing... most people will just use printf() from the start instead of dealing with intermediate buffers... also, automatic correction? seems doubtful unless the checker can figure out why a buffer was being used, and why a call to snprintf() followed by printf() is not absolutely necessary

    1. this has been addressed

  4. In the Noncompliant Code Example, sizeof(msg_format) should always return 4 in IA-32 architecture, which is not what you want?

    1. Wow, that was ugly. I think I got it fixed. Please have another look and let me know if you see any problems.

  5. The incorrect_password() function constructs by calculating the size of the message...

    should be corrected back to something like

    The incorrect_password() function constructs msg in dynamically allocated memory by calculating the size of the message...

    1. I've made this change, thanks.