Perl open() Security Issues

Security experts always advocated for validation of user input. Input validation acts like a defensive method to avoid unintended execution of the program to which the input is submitted. Programmers should have a keen understanding concepts how a called function of a programming language works to avoid software vulnerabilities.  This post discusses one such function open() in Perl used for file operations.

Introduction

Function open() is used to open a file using the specified file handle which can be an expression as well. Generally, the open() is used as

open(FILE_HANDLE, file_name);

The above form opens the file defined in ‘file_name’ in read-only mode. If ‘<‘ is used as a prefix to ‘file_name’, the file is opened in read mode, which is a default mode when there is no prefix to ‘file_name’. If the prefix is ‘>’, the file is opened as write mode and overwrites the existing file and finally if  ‘>>’ is prefixed to ‘file_name’, then the file is opened in append mode. If the filename begins with “|”, the filename is interpreted as a command to which output is to be piped, and if the filename ends with a “|”, the filename is interpreted as a command which pipes the output to us.

open() in Default Mode

Consider a scenario where a program takes a filename as input (say, input.txt) and reads its contents out.

use strict;
use warnings;
print "Enter the filename: ";
my $file = <STDIN>;
chomp $file;
open(DATA,$file);
print <DATA>;

Testing the scenario with input.txt

$root@kali:~# echo "this is from input.txt" > input.txt
$root@kali:~# perl read_from_file.pl 
Enter the filename: input.txt
this is from input.txt

Since the open() is called in default mode as per the source code, the file input.txt is opened in read mode and the contents are echoed. Now testing with ‘<input.txt’ as input.

$root@kali:~# perl read_from_file.pl 
Enter the filename: <input.txt
this is from input.txt

Again, the input is interpreted as the file input.txt is opened in read mode because of the prefix.  What if we prefix input.txt with ‘>’? Let’s check it out

$root@kali:~# perl read_from_file.pl 
Enter the filename: >input.txt
Filehandle DATA opened only for output at read_from_file.pl line 9.
$root@kali:~# cat input.txt
$root@kali:~# 

In this case, the file was opened in write mode and hence overwrote the existing file. This is a serious situation where an existing file can be overwritten with zero contents (in this scenario). And the prefix “>>”, opens the file in appending mode and hence changes are not noticed. But, here comes the serious prefix ‘|’. This prefix ll lead to command injection as discussed above which is used in piping out.

$root@kali:~# perl read_from_file.pl 
Enter the filename: |id
uid=0(root) gid=0(root) groups=0(root)
$root@kali:~# perl read_from_file.pl 
Enter the filename: |id
uid=0(root) gid=0(root) groups=0(root)

Notice even when ‘|’ is used as a suffix, the command injection works.
To avoid such issues, a simple modification is done with the prefix “<” being already introduced in the source code of reading files.

use strict;
use warnings;
print "Enter the filename: ";
my $file = <STDIN>;
chomp $file;
open(DATA,'<',$file);
print <DATA>;

Testing modified program with various inputs,

$root@kali:~# perl modified_read_from_file.pl 
Enter the filename: input.txt
this is from input.txt
$root@kali:~# perl modified_read_from_file.pl 
Enter the filename: <input.txt
readline() on closed filehandle DATA at modified_read_from_file.pl line 9.
$root@kali:~# perl modified_read_from_file.pl 
Enter the filename: |id
readline() on closed filehandle DATA at modified_read_from_file.pl line 9.
$root@kali:~# perl modified_read_from_file.pl 
Enter the filename: id|
readline() on closed filehandle DATA at modified_read_from_file.pl line 9.

open() in Write mode

Another scenario based on printing out contents to a file. Consider this source code which writes to a file

use strict;
use warnings;
print "Enter the filename: ";
my $file = <STDIN>;
chomp $file;
open(DATA,'>'.$file);
print DATA "Test to output\n";
close DATA;

Here, the file which is submitted as input is opened for writing because of ‘>’ prefix.

$root@kali:~# cat output.txt
cat: output.txt: No such file or directory
$root@kali:~# perl out_to_file.pl 
Enter the filename: output.txt
$root@kali:~# cat output.txt 
Test to output

However, the code is still vulnerable to write in an existing file in appending mode adding a prefix ‘>’ to the input as such.

$root@kali:~# cat output.txt
Test to output
$root@kali:~# perl out_to_file.pl 
Enter the filename: >output.txt
$root@kali:~# cat output.txt
Test to output
Test to output

This security problem might be very critical if the end user has control over what to be written in the file even. Hence, proper checks are needed on inputs. A real-world scenario is discussed in this post  CVE-2015-2079: Arbitrary Command Execution in Usermin.

So a good way to use to avoid such issues

use strict;
use warnings;
print "Enter the filename: ";
my $file = <STDIN>;
chomp $file;
#Notice the comma instead of dot
open(DATA,'>',$file);
print DATA "Test to output\n";
close DATA;

 

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *