Perl CGI To Write File - perl

I have written a Java Applet as a school project and I need a CGI file to create a file in the cgi-bin directory. The problem is when I run the code from the browser, the code executes but my file is not created with the variable name. Nothing is created. Here is the code
#!/usr/bin/perl -wT
use CGI;
print "content-type: text/plain\n\n";
my $q = CGI->new();
my $name = $q->param('username');
my $pw = $q->param('param');
my $bool = $q->param('bool');
my $rel = $q->param('rel');
my $ext = ".txt";
my $strt = "../cgi-bin/";
my $app = $strt . $name . $ext;
print $app;
open (FILE,'>',$app) or print "Error";
print FILE $pw . "\n";
print FILE $bool . "\n";
print FILE $rel;
close(FILE);
When I run the cgi it prints the $app variable and it is the correct address I want but the file is not created. If I change the line
open (FILE,'>',$app) or print "Error";
to
open (FILE,'>','../cgi-bin/test.txt') or print "Error";
it creates the file where I want it. Any ideas why this would happen when using the variable $app? Either way I never get Error printed to the browser.
SOLUTION:
Thanks guys for the help. When using:
use CGI::Carp qw(fatalsToBrowser);
I got this error:
Content-type: text/html
<H1>Software error:</H1>
<PRE>Insecure dependency in open while running with -T switch
</PRE>
<P>
For help, please send mail to the webmaster (or webmaster), giving this error message
and the time and date of the error.
It seems it was not liking the -T. Once I removed that it worked. Thanks again

Why you use ../cgi-bin to write into cgi-bin ?
Just use:
open (FILE, ">$name$ext") or die $!;
and use CGI::Carp qw(fatalsToBrowser); to carp fatals on the browser (suitable for this debug) with file creation

-T is Perl's "tainted data" flag. It stops you from doing unsafe operations with untrusted data. Yes, your script works without the -T flag, but now you have a very insecure script.
If someone passes in a username value of ../../../../../../../../home/badguy/secret, then you will write the username and password into secret.txt in badguy's home directory. -T prevents you from doing that. That's why -T exists.

Related

Perl webscript doubtful security

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.

Zipping a file with perl results in an invalid archive

I am currently trying to zip some files with perl. The resulting file is printed, so a user who calls the page which executes the script can download or open the zip file.
Looking at the size of the zip file it seems everything worked ok, but if I try to open the file on the server no contents are shown. If I open the file after downloading it, the archive is invalid.
Here's the code:
my $zip = Archive::Zip->new();
my $i;
foreach $i(#files)
{
my $fh = $zip->addFile("$directoryPath$i") if (-e "$directoryPath$i");
}
my $zipFilePath = "Test.zip";
die 'Cannot create $zip_file_name: $!\n' if $zip->writeToFileNamed("$zipFilePath") != AZ_OK;
open (DLFILE, "<$zipFilePath");
#fileholder = <DLFILE>;
close (DLFILE);
print "Content-Type:application/x-download\n";
print "Content-Disposition:attachment;filename=$zipFilePath\n\n";
print #fileholder;
Can you please tell me where the error is?
I am running the code using xampp on my local windows machine.
Edit: The same happens when I use
use strict;
use warnings;
use autodie;
Edit: The first problem is solved by ysth, thanks for that. Now the archive is not invalid after downloading, but still no files are shown if I open it, while the zip-file's size seems to be correct.
You are corrupting it here:
open (DLFILE, "<$zipFilePath");
#fileholder = <DLFILE>;
close (DLFILE);
by opening it such that it translates "\r\n" to just "\n".
Try this:
open( DLFILE, '<:raw', $zipFilePath );

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

CGI script doesn't run in browser

I am making a .cgi file which prints all values from database table on webpage in a table format.The problem is that when I run the file on putty terminal emulator it works fine but when I try to run the file on my browser I get an error message "file not found" even though T typed the correct location of the file on the server.
I can't understand what am I doing wrong? I set my file's permission to chmod 755 * using putty but it's still not working.Is this a problem of file permissions or table structure is wrong for running on browser something else?
Please help...
people.CGI File
#!/usr/bin/perl
use CGI;
use DBI;
use strict;
#use warnings;
#use diagnostics;
print "Content-type:text/html\r\n\r\n";
#$q = CGI->new;
#print $q->header;
my $dsn = "DBI:mysql:Demo:localhost"; # Data source name
my $username = "mint"; # User name
my $password = "MINT123"; # Password
my $dbh;
my $sth; # Database and statement handles
$dbh = DBI->connect($dsn, $username, $password);
$sth = $dbh->prepare("SELECT * from people");
$sth->execute();
print "<h1>ganesh</h1>";
print "<table >
<tr>
<th>ID</th>
<th>Name of People Involved</th>
<th>Position</th>
<th>Roles(A user can have multiple roles)</th>
<th>Notes</th>
</tr>";
while( my $href = $sth->fetchrow_hashref )
{
print "<tr>";
print "<td>$$href{'id'}</td>";
print "<td>$$href{'name'}</td>";
print "<td>$$href{'pos'}</td>";
print "<td>$$href{'role'}</td>";
print "<td>$$href{'notes'}</td>";
#print "<td><input type='text' value=\"$$href{'display_name'}\" id =\"dis-$$href{'windows_id'}\" readonly> </td>";
#print "<td><input type='text' value=\"$$href{'email_id'}\" readonly> </td>";
print "</tr>";
}
print "</table>";
$sth->finish();
$dbh->disconnect();
Database Table structure...
Table data...
Output when i run the file in putty...
Message when i try running the file on my browser..
The two answers you have received previously are complete nonsense. You don't need to to use a CGI object in order to run a CGI program. Of course, it makes it easier, but it's not necessary.
The only part of the CGI protocol that your program needs to handle is the Content-Type header. And you're doing that with your print line.
No, your problem is somewhere else completely. But, unfortunately, it's somewhere where we can be of very little help without knowing a lot more. You're getting a file not found error because the web server can't find your code. In other words, the address that you're typing into your browser (128.9.45.170/~pankaj.yadav/Test/cgi/people.cgi) doesn't match a filename on your web server.
This all comes down to how your web server is configured. How are web addresses mapped onto file paths? We don't know. Only your web server administrator will know the answer for sure.
You might get a clue if you look at the web server error log. You'll see a file not found error in the log which will (hopefully) contain the actual file path that the web server is trying to find. And that might help you work out where you should put your CGI program.

Display Output In Browser Perl CGI SSH

I'm executing remote commands using Net::OpenSSH using a web frontend. My commands return without failure on the command line, but I get nothing in a web browser. I've done a couple hour research to no avail--any ideas?
Here is some code to give you an example (some removed for obvious reasons).
#!/usr/bin/perl -w
use strict;
use CGI ':standard';
use Net::OpenSSH;
# Here in the code is just the header and standard tags
print "1";
print "2"; # both display
my $ssh = Net::OpenSSH->new($host, user => $uname, key_path => $key); # all works
$ssh- error and die "Can't ssh to host" . $ssh->error;
print "3";
$ssh->system("uname -a") or
die "remote command failed: " . $ssh->error;
my #lsa = $ssh->capture("ls -a");
$ssh->error and
die "remote ls command failed: ". $ssh->error;
print "4";
print "5";
print #lsa; # won't display in browser, just terminal/CLI
Cheers!
I maintain CGI.pm. I recommend these additions to your simple script:
Before you print anything else, print the standard HTTP header: print header();
Add this after the use CGI line: use CGI::Carp qw(fatalsToBrowser); ... that will display any run-time problems in the browser. If you don't get any output after these changes, check that the script compiles with perl -cw script.pl
Below is about the minimum Perl code that worked for me on Debian machine. I suggest you go through it and compare it to your actual code.
However, it did not work out-of-the box on my Debian, I had make some decisions most of which probably aren't very safe, but that's more about specific environment:
make home for user that server runs writable (/var/www)
add host to ~/.ssh/known_hosts beforehand
use the strict_mode => 0 to bypass Net::OpenSSH's security checks instead of finding proper
ctl_dir (Net::OpenSSH requires that the folder and all above folders are 0755 or more strict,
so /tmp I used is normally not good enough)
I believe there are much safer practices than that, but as I said, that's specific to environment.
So the code:
#!/usr/bin/perl
use strict;
use warnings;
use Net::OpenSSH;
use File::Temp qw/ tempdir /;
# necessary minimum for CGI
print "Content-type: text/plain\n\n";
# prepare temp dir
my $temp = tempdir("/tmp/sshme.pl-XXXXXXXX", CLEANUP => 1);
# open SSH session
my %opts = (
user => "user",
password => "password",
ctl_dir => $temp,
strict_mode => 0 ## NOT recommended - see my comments
);
my $ssh = Net::OpenSSH->new("host", %opts);
$ssh->error
and die "Couldn't establish SSH connection: ". $ssh->error;
# perform command and print output
my #lines = $ssh->capture("ls")
or die "remote command failed: " . $ssh->error;
print #lines;
Perhaps your errors get directed to standard error, not standard output. In that case, they'll usually end up in the server log, not the browser window. Perhaps you can use POSIX::dup2 to avoid this:
use POSIX;
# Make sure to send HTTP headers before redirecting streams!
POSIX::close(2); # close original stderr stream. No more output to apache logs!!!
POSIX::dup2(1,2); # redirect error stream to standard output, so errors will appear in browser.
Processes launched by perl, like e.g. some ssh binary, will inherit these streams.