rule
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 them supply a password, and only granting them access if the password is correct.
sub validate_password { my ($prompt, $password) = @_; my $is_ok = ($password eq "goodpass"); printf "$prompt: Password ok? %d\n", $is_ok; return $is_ok; }; my $host = `hostname`; chop($host); my $prompt = "$ENV{USER}\@$host"; if (validate_password( $prompt, $ARGV[0])) { print "$prompt: access granted\n"; } else { print "$prompt: access denied\n"; };
The program works as expected as long as the username and hostname 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 username:
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 username user%n
was incomprorated 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. This 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.
sub validate_password { my ($prompt, $password) = @_; my $is_ok = ($password eq "goodpass"); print "$prompt: Password ok? $is_ok\n"; return $is_ok; }; # ...
Risk Assessment
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
IDS30-PL | high | probable | low | P18 | 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.
Related Guidelines
CERT C Secure Coding Standard: FIO30-C. Exclude user input from format strings
CERT C++ Secure Coding Standard: FIO30-CPP. Exclude user input from format strings
The CERT Oracle Secure Coding Standard for Java: IDS06-J. Exclude user input from format strings
http://cwe.mitre.org/: http://cwe.mitre.org/data/definitions/134.html, "Uncontrolled Format String"
Bibliography
Full-disclosure: Christey, Steven M. Format String Vulnerabilities in Perl Programs Fri Dec 02 2005 - 02:56:14 CST
[Seacord 2005]] Chapter 6, Formatted Output
US-CERT Vulnerability Note VU#948385
[Wall 2011] perlfunc
Chapter 6, Formatted Output
02. Expressions EXP30-PL. Do not use deprecated or obsolete functions