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.
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.
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; }; # ... |
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
IDS30-PL | high | probable | low | P18 | L1 |
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.
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"
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
01. Input Validation and Data Sanitization EXP30-PL. Do not use deprecated or obsolete functions