0

Perl and html, CGI on Linux. Issue with file path name, being passed in a form field, to a CGI on server. The issue is with the Linux file path, not the PC side.

I am using 2 programs, 1) program written years ago, dynamic html generated in a perl program, and presented to the user as a form. I modified by inserting the needed code to allow a the user to select a file from their PC, to be placed on the Linux machine.

Because this program already knew the filepath, needed on the linux side, I pass this filepath in a hidden form field, to program 2.

2) CGI program on Linux side, to run when form on (1) is posted.

Strange issue. The filepath that I pass, has a very strange issue. I can extract it using

my $filepath = $query->param("serverfpath");

The above does populate $filepath with what looks like exactly the correct path.
But it fails, and not in a way that takes me to the file open error block, but such that the call to the CGI script gives an error.

However, if I populate $filepath with EXACTLY the same string, via hard coding it, it works, and my file successfully uploads.

For example:

$fpath1 = $query->param("serverfpath");
$fpath2 = "/opt/webhost/ims/DOCURVC/data" 

A comparison of $fpath1 and $fpath2 reveals that they are exactly equal. A length check of $fpath1 and $fpath2 reveals that they are exactly the same length.

I have tried many methods of cleaning the data in $fpath1. I chomp it. I remove any non standard characters.

$fpath1  =~ s/[^A-Za-z0-9\-\.\/]//g;

and this:

my $safe_filepath_characters = "a-zA-Z0-9_.-/";
$fpath1 =~ s/[^$safe_filepath_characters]//g;

But no matter what I do, using $fpath1 causes an error, using $fpath2 works.

What could be wrong with the data in the $fpath1, that would cause it to successfully compare to $fpath2, yet not be equal, visually look exactly equal, show as having the exact same length, but not work the same?

For the below file open block.

$upload_dir = $fpath1 

causes complete failure of CGI to load, as if it can not find the CGI (which I know is sometimes caused by syntax error in the CGI script).

$uplaod_dir = $fpath2   

I get a successful file upload

$uplaod_dir = ""        

The call to the cgi does not fail, it executes the else block of the below if, as expected.

here is the file open block:

if (open ( UPLOADFILE, ">$upload_dir/$filename" ))   
{
binmode UPLOADFILE;

while ( <$upload_filehandle> )
{
print UPLOADFILE;
}

close UPLOADFILE;
$msgstr="Done with Upload: upload_dir=$upload_dir filename=$filename";
}
else
{
$msgstr="ERROR opening for upload: upload_dir=$upload_dir filename=$filename";
}

What other tests should I be performing on $fpath1, to find out why it does not work the same as its hard-coded equivalent $fpath2

I did try character replacement, a single character at a time, from $fpath2 to $fpath1. Even doing this with a single character, caused $fpath1 to have the same error as $fpath2, although the character looked exactly the same.

tshepang
  • 12,111
  • 21
  • 91
  • 136
user2234591
  • 13
  • 1
  • 3
  • 1
    At the risk of sounding stupid, but have you looked at the webservers error log? – tink Apr 03 '13 at 21:43
  • I too at the risk of sounding stupid are you sure you are comparing the values with the “eq” operator and NOT “==” ($fpath1 eq $fpath2) ? – jross Apr 03 '13 at 22:15
  • Reading the path to the server file location from the CGI request is a potentially serious vulnerability. Don't do it. – Sinan Ünür Apr 03 '13 at 23:54
  • Re "But no matter what I do, using $fpath1 causes an error" What error??? (Add `$!` to the error message) – ikegami Apr 04 '13 at 01:50
  • If it's a problem with the paths, `use Dumper; local $Data::Dumper::Useqq = 1; warn(Dumper($fpath1, $fpath2));` will reveal it. – ikegami Apr 04 '13 at 01:51

2 Answers2

0

But it fails, and not in a way that takes me to the file open error block, but such that the call to the CGI script gives an error.

Premature end of script headers? Try running the CGI from the command line:

perl your_upload_script.cgi serverfpath=/opt/webhost/ims/DOCURVC/data
Daniel Holz
  • 148
  • 5
0

Is your CGI perhaps running perl with the -T (taint mode) switch (e.g., #!/usr/bin/perl -T)? If so, any value coming from untrusted sources (such as user input, URIs, and form fields) is not allowed to be used in system operations, such as open, until it has been untainted by using a regex capture. Note that using s/// to modify it in-place will not untaint the value.

$fpath1  =~ /^([A-Za-z0-9\-\.\/]*)$/;
$fpath1 = $1;
die "Illegal character in fpath1" unless defined $fpath1;

should work if taint mode is your issue.

Brad Gilbert
  • 33,846
  • 11
  • 78
  • 129
Dave Sherohman
  • 45,363
  • 14
  • 64
  • 102
  • Thank you for the answers and insight. It turned out it was the use of the tainted flag. I was using -wT. Not using the T flag works. – user2234591 Apr 04 '13 at 18:41
  • @user2234591 Using the `-T` flag is actually a good idea in this case. It prevents you from doing something stupid; like reading a random file on your server. – Brad Gilbert Apr 13 '13 at 06:34
  • 1
    `unless( ($fpath1) = $fpath1 =~ /^([A-Z])$/ ){ die ... }` would also work. – Brad Gilbert Apr 13 '13 at 06:46