Perl webscript doubtful security - perl

Recently with a project I inherited a simple perl script that generates a PDF of the page:
#!/usr/bin/perl
use CGI;
my $file="showdata.pdf";
my $filepath= "/tmp/$file";
system("wkhtmltopdf \"sample.com/showdata.php?".$ENV{"QUERY_STRING"}."\" $filepath");
print ("Content-Type:application/x-download\n");
print ("Content-Disposition: attachment; filename=$file\n\n");
open FILE, "< $filepath" or die "can't open : $!";
binmode FILE;
local $/ = \10240;
while (<FILE>){
print $_;
}
close FILE;
unlink ($filepath);
I am concerned direct substitution variable $ENV{"QUERY_STRING"}. However, in a cursory testing, I did not reveal any problems. I was not able to create/delete files in a known writable directory. I tried not well or problems in the script should not be?

Yes, that's insecure. What if QUERY_STRING was "; rm -fr /;?
Then your system call would be:
wkhtmltopdf "sample.com/showdata.php?"; rm -fr /; /tmp/showdata.pdf

Accessing $ENV{"QUERY_STRING"} directly is insecure. In my case, my digital parameter 'o' must be forced to be integer. There is secure script version:
#!/usr/bin/perl
use CGI;
my $query = new CGI;
my $o = int($query->param('o'));
my $file="showdata.pdf";
my $filepath= "/tmp/$file";
system("wkhtmltopdf \"sample.com/showdata.php?o=".$o."\" $filepath");
print ("Content-Type:application/x-download\n");
print ("Content-Disposition: attachment; filename=$file\n\n");
open FILE, "< $filepath" or die "can't open : $!";
binmode FILE;
local $/ = \10240;
while (<FILE>){
print $_;
}
close FILE;
unlink ($filepath);

If you concern about security, run your Perl script with taint option -T.
For example, the following script will halt your script with warning: Insecure $ENV{PATH} while running with -T switch at ./foo.pl line 4.
#!/usr/bin/perl -T
my $foo = $ENV{FOO};
system("ls -l $foo");
Note: option -t can be used instead of -T if you just need warning.

Related

From inside a perl script can you know the name of the file you are redirecting output to?

So I have:
test.pl > test.log
is there a way to know inside test.pl that I am outputing to 'test.log'? At the end of my script I want to do some manipulation of test.log without hardcoding the name.
Maybe. The following works on Linux, but will not be very portable to other systems...
#!/usr/bin/env perl
use strict;
use warnings;
my $out = readlink("/proc/$$/fd/1");
print STDERR "I am being output to $out\n";
Naturally, this is probably a bad idea. Better to explicitly open the file and write to it in Perl, rather than having the shell set up redirections.
You can redirect standard output from perl, with minimal changes to your script,
test.pl test.log
my ($file) = #ARGV;
if (#ARGV) {
open STDOUT, ">", $file or die $!;
}
print "output is redirected to $file\n";
# use $file at the end

Downloading sequence file with perl

I am trying to download the sequence file from the gene bank database using perl but it shows error. I don't have any guide to correct my program.
Can any one help me with this? The error is in line 6 (use Bio::DB::GenBank;)
File accnumber.txt is on my desktop and I am running the program from desktop itself. I am using CentOS.
#!usr/bin/perl -w
use strict;
use warnings;
use Bio::DB::GenBank;
open (INPUT_FILE, 'accnumber.txt');
open (OUTPUT_FILE, 'sequence_dwnl.fa');
while()
{
chomp;
my $line = $_;
my #acc_no = split(",", $line);
my $counter = 0;
while ($acc_no[$counter])
{
$acc_no[$counter] =~ s/\s//g;
if ($acc_no[$counter] =~ /^$/)
{
exit;
}
my $db_obj = Bio::DB::GenBank->new;
my $seq_obj = $db_obj->get_Seq_by_acc($acc_no[$counter]);
my $sequence1 = $seq_obj->seq;
print OUTPUT_FILE ">"."$acc_no[$counter]","\n";
print OUTPUT_FILE $sequence1,"\n";
print "Sequence Downloaded:", "\t", $acc_no[$counter], "\n";
$counter++;
}
}
close OUTPUT_FILE;
close INPUT_FILE;
These are errors I get:
Bareword "Bio::DB::GenBank" not allowed while "strict subs" in use at db.pl line 6.
Bareword "new" not allowed while "strict subs" in use at db.pl line 27.
Bareword "seq" not allowed while "strict subs" in use at db.pl line 29.
Execution of db.pl aborted due to compilation errors.
Since line you mention loads external Perl module Bio::DB::GenBank from CPAN, first thing that came to my mind: Is the module installed on your system?
Try running command cpan Bio::DB::GenBank as root (e.g. by prepending it with sudo). This should not hurt even if the module is installed, in that case it will check CPAN for updates.
In addition to the above answer,
Please use die function to check whether the files are opened.
open (INPUT_FILE, 'accnumber.txt');
open (OUTPUT_FILE, 'sequence_dwnl.fa');
Like this:
open (my $input_file, '<', 'accnumber.txt') or die "Could not open because $!\n";
open (my $output_file, '<', 'sequence_dwnl.fa') or die "Could not open because $!\n";
Also, please specify the purpose of opening each file with these operators:
< to open file in read only mode.
> to overwrite the file content.
>> to append the file content.
Also please check whether you have Bio::DB::GenBank module installed or not.
You can do that by running this in command line:
perldoc -l Bio::DB::GenBank or perl -MBio::DB::GenBank -e 1

perl system command redirection to log files

I am trying to redirect perl system command to output file with the following code along with time but its not working ??
$cmd="echo hi";
($second, $minute, $hour) = localtime();
$time="$hour:$minute:$second";
system("$time>new.txt");
system("$cmd 1>>new.txt 2>>&1");
If you want to write the variable $time to a text file, open a writeable filehandle and print it to your file instead.
open(my $outfile, '>', 'new.txt');
print $outfile $time;
...
Secondly, your output redirection should read:
1>>new.txt 2>&1
Which means "append STDOUT (1) to new.txt, redirect STDERR (2) to STDOUT (1)". Having >> makes no sense for the second part.
Finally, I (and every other perl programmer) would strongly recommend using strict and warnings pragmas in your scripts. This will help you pick up on any errors or potential problems in your scripting. Once you've done this, all variables must be declared with my, which is a good habit to get in to anyway. So after all that, your script should look something like this:
# recommended pragmas:
use strict;
use warnings;
# declare all new variables with "my"
my $cmd="echo hi";
my ($second, $minute, $hour) = localtime();
my $time="$hour:$minute:$second";
# open a writeable filehandle and print to the filehandle
open(my $outfile, '>', 'new.txt');
print $outfile $time,"\n"; # I've added a newline character here so that
# the time and the command's output are on different lines ;)
system("$cmd 1>>new.txt 2>&1");

filehandle - won't write to a file

I cannot get the script below to write to the file, data.txt, using a FILEHANDLE. Both the files are in the same folder, so that's not the issue. Since I started with Perl, I have noticed to run scripts, I have to use a full path: c:\programs\scriptname.pl and also the same method to input files. I thought that could be the issue and tried this syntax below but that didn't work either...
open(WRITE, ">c:\programs\data.txt") || die "Unable to open file data.txt: $!";
Here is my script. I have checked the syntax until it makes me crazy and cannot see an issue. Any help would be greatly appreciated!. I'm also puzzled, why the die function hasn't kicked in.
#!c:\strawberry\perl\bin\perl.exe
#strict
#diagnostics
#warnings
#obtain info in variables to be written to data.txt
print("What is your name?");
$name = <STDIN>;
print("How old are you?");
$age = <STDIN>;
print("What is your email address?");
$email = <STDIN>;
#data.txt is in the same file as this file.
open(WRITE, ">data.txt") || die "Unable to open file data.txt: $!";
#print information to data.txt
print WRITE "Hi, $name, you are \s $age and your email is \s $email";
#close the connection
close(WRITE);
How I solved this problem solved.
I have Strawberry Perl perl.exe installed on the c: drive, installed through and using the installer with a folder also on c with my scripts in, which meant I couldn't red/write to a file (directional or using functions, ie the open one) and I always had to use full paths to launch a script. I solved this problem after a suggestion of leaving the interpreter installed where it was and moving my scripts file to the desktop (leave the OS command in the first line of the script where it is as the interpreter is still in the same place it was initially). Now I can run the scripts with one click and read/write and append to file with CMD prompt and using Perl functions with ease.
Backslashes have a special meaning in double-quoted strings. Try escaping the backslashes.
open(WRITE, ">c:\\programs\\data.txt") || die ...;
Or, as you're not interpolating variables, switch to single quotes.
open(WRITE, '>c:\programs\data.txt') || die ...;
It's also worth using the three-argument version of open and lexical filehandles.
open(my $write_fh, '>', 'c:\programs\data.txt') || die ...;
you must use "/" to ensure portability, so: open(WRITE, ">c:/programs/data.txt")
Note: I assume that c:/programs folder exists
You may want to try FindBin.
use strict;
use warnings;
use autodie; # open will now die on failure
use FindBin;
use File::Spec::Functions 'catfile';
my $filename = catfile $FindBin::Bin, 'data.txt';
#obtain info in variables to be written to data.txt
print("What is your name?"); my $name = <STDIN>;
print("How old are you?"); my $age = <STDIN>;
print("What is your email address?"); my $email = <STDIN>;
{
open( my $fh, '>', $filename );
print {$fh} "Hi, $name, you are $age, and your email is $email\n";
close $fh;
}
If you have an access problem when you try to print to data.txt you can change that line to:
print WRITE "Hi, $name, you are \s $age and your email is \s $email" || die $!;
to get more information. A read only file will cause this error message:
Unable to open file data.txt: Permission denied at perl.pl line 12, <STDIN> line 3.

How to create a file in remote host along with the creation of directory using ssh

I have a file say /a/b/c/file in my host. I want to create a file on remote host in directory say dest. Now the question is, how do I create a file in remote host as /dest/a/b/c/d/file using perl script and using ssh. Any idea how do I create directories in script.?
Thanks.
To reproduce the directory structure, use catfile and abs2rel from the File::Spec module: catfile joins pieces to make a path, and abs2rel gives the path relative to some base directory.
The File::Copy module's copy will copy to a handle. This fits nicely with how sshopen3 opens handles to the standard input, output, and error on the destination side.
The remote command has 3 parts:
mkdir -p $dst_dir, creates all directories preceding the file in the destination path
cat >$dst_file, connects the SEND handle to the destination file
md5sum $dst_file, shows that the data arrived safely
Sample program below:
#! /usr/bin/perl
use warnings;
use strict;
use File::Basename;
use File::Copy;
use File::Spec::Functions qw/ abs2rel catfile /;
use Net::SSH qw/ sshopen3 /;
my $HOST = "user\#host.com";
my $SRC_BASE = "/tmp/host";
my $SRC_FILE = "$SRC_BASE/a/b/c/file";
my $DST_BASE = "/tmp/dest";
system("md5sum", $SRC_FILE) == 0 or exit 1;
my $dst_file = catfile $DST_BASE, abs2rel $SRC_FILE, $SRC_BASE;
my $dst_dir = dirname $dst_file;
sshopen3 $HOST, *SEND, *RECV, *ERRORS,
"mkdir -p $dst_dir && cat >$dst_file && md5sum $dst_file"
or die "$0: ssh: $!";
binmode SEND;
copy $SRC_FILE, \*SEND or die "$0: copy failed: $!";
close SEND or warn "$0: close: $!"; # later reads hang without this
undef $/;
my $errors = <ERRORS>;
warn $errors if $errors =~ /\S/;
close ERRORS or warn "$0: close: $!";
print <RECV>;
close RECV or warn "$0: close: $!";
Sample run:
$ ./create-file
746308829575e17c3331bbcb00c0898b /tmp/host/a/b/c/file
746308829575e17c3331bbcb00c0898b /tmp/dest/a/b/c/file