Bugtraq mailing list archives

Re: CGI security: Escape newlines.


From: robertm () teleport com (Robert S. Muhlestein)
Date: Tue, 6 Feb 1996 11:49:45 -0800


On Tue, 6 Feb 1996, Lincoln Stein wrote:

In general I think that it's much better to search for and accept only
the good patterns rather than trusting things to work when you exclude
the bad characters.  People forget that the shell isn't the only
vulnerable program, and other programs may be subvertible by input
quite distinct from the set of shell metacharacters.

Lincoln

Ditto.  I use a simply "check" routine to check every acceptable form
variable.  Here are the subs I regularly use to accomplish this.  If you
spot a bug, I'd appreciate a note.  If you use my routines, please
leave a ref to me somewhere.

This example uses Lincoln's CGI.pm to grab form variables, then a few of
my own routines to check info, etc.  Although I use these routines all
the time, I haven't tested the actual example script itself, beware:


__BEGIN__
#!/usr/local/bin/perl

########
##  These routines are normally part of a package that I import:
########

$SENDMAIL    = '/usr/lib/sendmail -t -n';
$DATE        = localtime(time);

##  To keep the perl jobs from taking priority over regular httpd daemons
setpriority(0,0,4);

#------------------------------------------------------------------------
sub log_it {

  my $time    = localtime($^T);
  my $message = $_[0]; $message =~ tr/\n\"/ /;
  ($LOG = $_[1]) unless (defined $LOG);
  my $addr    = $ENV{'REMOTE_ADDR'} || 'LOCAL';
  my $host    = $ENV{'REMOTE_HOST'} || 'LOCAL';

  open(LOG, ">>$LOG") || die("Failed to open log file: $LOG\n");
  printf LOG ("[%s]  %s  %s  \"%s\"\n",$time,$host,$addr,$message);

}

#------------------------------------------------------------------------
sub check {
  my($pname,$OKstring,$OKpexp,$error) = @_;
  $OK{$pname} = $OKstring;
  printf ("%-15s\n%-15s %-20s\n","${pname}=${$pname}",$OKpexp,$OKstring)
    if (defined $DEBUG);
  (${$pname} =~ /^$OKpexp$/) ||
    &error("\"${pname}\" (${$pname}) $ERR  $OKstring\n");
  return 1;
}

#------------------------------------------------------------------------
## Beware of passing unchecked headers from the web!!!
sub send_mail {
  my($to,$from,$subject,$message,@headers) = @_;
  open (MAIL, "|-") || exec($SENDMAIL);
  print MAIL <<EOM;
Date: $DATE
To: $to
From: $from
Subject: $subject
@headers

$message

EOM
  close MAIL;
}

#------------------------------------------------------------------------
sub get_info {

  ## Take over form params
  for ($query->param){
     (s/M_//) ? (@{$_} = $query->param("${&}$_"))
       : (${$_} = $query->param($_));
  }
}

#------------------------------------------------------------------------
sub error {
  my $message = @_[0];
  print  <<EOM;
Content-type: text/html


<HTML>
<TITLE>Processing Error:</TITLE>
<BODY>

<H1>Processing Error:</H1>
<HR>
<PRE>$message
<HR>
Please make the necessary corrections.

</BODY>
</HTML>

EOM
  (defined $LOG) && &log_it($message);
  die($message);
}

#------------------------------------------------------------------------
sub redirect {
  my $url = @_[0];
  print <<EOM;
Status: 302 Moved Temporarily
Method: GET
URI: <$url>
Location: $url
Content-type: text/html

EOM
}
#------------------------------------------------------------------------
sub validpw {
  my $salt = (getpwnam($_[0]))[1];
  return (crypt($_[1], $salt) eq $salt) ? 1: 0 ;
}

#################################################################
###  End Subroutines
#################################################################

###  MAIN (Here's where the untested stuff begins)

use CGI;
$query = new CGI;
get_info;

### Just to check one paramter that might come a little close to a shell
check('PARAM','\w{2,20}','2-20 alphanumerics allowed.');

##  To check for form parameters that aren't going to be passed to a shell,
##  but are at least required:
$REQ = '.{1,1000}';
$REQtxt = 'This field is required (up to 1000 characters).';
for ('PARAM2','PARAM2','PARAM3','PARAM4','PARAM5','PARAM6') {
  check($_,$REQ,$REQtxt);
}

print $query->header;
print $query->start_html;
$PARAM2
$PARAM3
##  You get the idea ...
EOM
print $query->end_html;

__END__

Rob Muhlestein
CGI Guy
Teleport Internet Services
http://www.teleport.com/



Current thread: