CGI security is a frequent topic of dicussion on this site so I thought I'd raise another issue that illustrates a variety of problems that people face when trying to write secure scripts. The following example is rather simple, but helps to illustrate the dangers involved (my information came from this Phrack article. tilly originally supplied me with the link).

I'm posting this here in part so that I can archive this and link to it from my online CGI course. I figured it would be a handy way to get people to use Perlmonks more :)

Consider the following code:

#!C:/perl/bin/perl.exe -wT use strict; use CGI; # Do not run this script on a server connected to the 'Net # It is supplied as a bad example my $cgi = CGI->new(); my $file = $cgi->param( 'file' ); # Bad taint checking! # This is, amongst other things, a deliberately incomplete list # of shell metacharacters my $data = $1 if $file =~ m#([^./\\`$"'&]+\.?[^./\\`$"'&]+)$#; $data .= '.dat'; my $userInfo; open FILE, "<$data" or die "Cannot open $data: $!\n"; { local $/; $userInfo = <FILE>; } close FILE; print $cgi->header, $cgi->start_html, $cgi->pre( $userInfo ), $cgi->end_html;
Hmm.... what's wrong with it? The author (me) uses warnings, strict, and taint checking. Users need to be able to get at the contents of .dat files on the server, but filenames can be very unpredictable. This script allows them to view those files from any browser. Therefore, we need to (gasp!) let user data near the shell.

The author, however, knows this is a security hole, so he conventiently supplies a list of shell metacharacters which he doesn't want. Further, he appends a ".dat" extension to guarantee that the user can only view files with said extension. Looks pretty secure to me!

I deliberately left the list of shell metacharacters incomplete so Monks wouldn't be tempted to use this technique.

So what's the problem? Perl, as many of you know, is written in C. C recognizes the null byte (ASCII zero) as the end of a string. Perl does not. If Perl tries to make a system call (such as open FILE, $somefile) with an embedded null byte in the data, the data is passed to the C underbelly, which happily ignores any information from the null byte on. So how does that affect our script?

I named the script insecure.cgi and ran it locally through a browser. I used the following URL:

See that embedded %00? Hmm... it's right after the name of my script. It passes our taint checking and Perl thinks it's trying to open insecure.cgi%00loser!.dat. However, the C underbelly tries to open insecure.cgi, and does! Then, the rest of the script happily dumps its source code to your browser.

This illustrates a couple of points:

Specifying what you won't allow forces you to go over everything that you missed and ensure that there are no security problems. How many would have guessed that ASCII zero would be a risk?

This node brought to you by the letter C


Join the Perlmonks Setiathome Group or just go the the link and check out our stats.