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.
Code Block | ||||
---|---|---|---|---|
| ||||
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:
Code Block |
---|
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:
Code Block |
---|
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.
Code Block | ||||
---|---|---|---|---|
| ||||
sub validate_password {
my ($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.
Tool | Diagnostic |
---|---|
Warnings | Missing argument in .*printf |
Taint mode | Insecure dependency in .*printf |
Related Guidelines
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 |
...