GitHub
CERT Secure Coding

IDS30-PL. Exclude user input from format strings

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 the Perl interpreter or cause a denial of service. She can also modify values, perhaps by using the %n|| conversion specifier, and use these values to divert control flow. Their capabilities are not as strong as in C [ Seacord 2005 ]; nonetheless the danger is sufficiently great that the formatted output functions {{sprintf() and printf() should never be passed unsanitized format strings.

Noncompliant Code Example

This noncompliant code example tries to authenticate a user by having the user supply a password and granting access only if the password is correct.

Non-compliant code
my $host = `hostname`;
chop($host);
my $prompt = "$ENV{USER}\@$host";

sub validate_password {
  my ($password) = @_;
  my $is_ok = ($password eq "goodpass");
  printf "$prompt: Password ok? %d\n", $is_ok;
  return $is_ok;
};


if (validate_password( $ARGV[0])) {
  print "$prompt: access granted\n";
} else {
  print "$prompt: access denied\n";
};

The program works as expected as long as the user name and host name are benign:

user@host:~$ ./authenticate.pl goodpass
user@host: Password ok? 1
user@host: access granted
user@host:~$ ./authenticate.pl badpass
user@host: Password ok? 0
user@host: access denied
user@host:~$

However, the program can be foiled by a malicious user name:

user@host:~$ env USER=user%n ./authenticate.pl badpass
user%n@host: Password ok? 0
user%n@host: access granted
user@host:~$

In this invocation, the malicious user name user%n was incorporated into the $prompt string. When fed to the printf() call inside validate_password() , the %n instructed Perl to fill the first format string argument with the number of characters printed, which caused Perl to set the $is_ok variable to 4. Since it is now nonzero, the program incorrectly grants access to the user.

Compliant Solution ( print() )

This compliant solution avoids the use of printf() , since print() provides sufficient functionality.

Compliant code
sub validate_password {
  my ($password) = @_;
  my $is_ok = ($password eq "goodpass");
  print "$prompt: Password ok? $is_ok\n";
  return $is_ok;
};

# ...

Risk Assessment

Rule Severity Likelihood Detectable Repairable Priority Level
IDS30-PL high probable Yes No P12 L1

Automated Detection

Perl's taint mode provides partial detection of unsanitized input in format strings.

Perl's warnings can detect if a call to printf() or sprintf() contains the wrong number of format string arguments.

ToolDiagnostic
WarningsMissing argument in .*printf
Taint modeInsecure dependency in .*printf
Security Reviewer - Static ReviewerPERL_D90
SEI CERT C Coding StandardFIO30-C. Exclude user input from format strings
SEI CERT C++ Coding StandardVOID FIO30-CPP. Exclude user input from format strings
CERT Oracle Secure Coding Standard for JavaIDS06-J. Exclude unsanitized user input from format strings
MITRE CWECWE-134 , "Uncontrolled format string"

Bibliography

[ Christey 2005 ]Format string vulnerabilities in Perl programs
[ Seacord 2005 ]Chapter 6, "Formatted Output"
[ VU#948385 ]Perl contains an integer sign error in format string processing
[ Wall 2011 ]perlfunc