I was reviewing a Perl CGI script a co-worker sent to me for troubleshooting last week, and came across this little gem (excerpted but not changed in any meaningful way):
use CGI;
use LWP;
my $ua = new LWP;
my $req = new CGI;
my $res_id = $req->param('rid');
my $img = $req->param('img');
my $url = "http://somehost/cgi-bin/fetch.cgi?id=$res_id";
$req->get($url, :content_file => $img);
open FH, $img;
unlink $img;
print $req->header(-type=>'application/octet-stream');
while (<FH>) {
print $_;
}
close FH;
How horribly bad is this script? Well, it allows no less than the deletion/overwriting of any file writable by the web server user. While that won’t allow injection of shellcode under most configurations, it would allow an attacker to delete logfiles, insert malicious replacements to files in upload directories, and generally mess with your system in all kinds of ways.
Even better, it completely misuses the Content-Type HTTP header to force download instead of inline view, instead of using the semantically-appropriate Content-Disposition: attachment route to force a download dialog box to appear on the client.
There are doubtless millions of lines of code like this out there in the world, and (at least in Perl-land) almost all of them could be caught with the simple addition of the -T (”taint check”) flag to the #!/usr/bin/perl line at the top of the script.