Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Never call any 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 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) Wiki MarkupFormatted 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]\].

Non-Compliant Code Example

...

In this 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 programillustrates the incorrect_password() function which is called during identification and authentication if user is not found or {password}} is incorrect to display an error message. The function accepts two strings that originated from an untrusted, unauthenticated user: user and password. The function constructs an error message which is then output to stderr using the C99 standard fprintf() function.

Code Block
bgColor#FFCCCC
char input[1000];
if (fgets(input, sizeof(input)-1, stdin) == NULL) {
void incorrect_password(const char *user, const char *password) {
  /* user names are restricted to 256 characters or less */
  size_t len = strlen(user) + sizeof("%s could not be authenticated.") - 1;
  char *msg = (char *)malloc(len);
  if (!msg) {
    /* handle error condition */
  }
input[sizeof(input)-1] = '\0';
fprintf(stdout, input);

Non-Compliant Code Example 2

  snprintf(msg, len, "%s could not be authenticated.", user);
  fprintf(stderr, msg);
  free(msg);
}

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

Code Block
bgColor#FFCCCC
void checkincorrect_password(const char *user, const char *password) {
  if (strcmp(lookup_password(user), password) != 0) {
  /* user names are restricted to 256 characters or less */
  size_t len = strlen(user) + 100sizeof("%s could not be authenticated.") - 1;
    char *msg = (char *)malloc(len);
    if (!msg) {
      /* handle error condition */
    }
    snprintf(msg, len, "%s password incorrectcould not be authenticated.", user);
    fprintf(stderr, msg);
    syslog(LOG_INFO, msg);
    free(msg);
  }
}

Compliant Solution

...

This example compliant solution outputs the string directly instead of building it and then outputting it.

...

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]\]

...