Security Bulletin

Date: March 31, 2001
Affected releases: In an effort to make DCForum secure as possible, we are currently performing internal security audits. During an audit in march, we have discovered two potential exploits due to unchecked form parameters and file upload feature. Please make sure you update your files according to the following instruction.

Files affacted

-------------------------------------------------------
1. Edit dcadmin.cgi
-------------------------------------------------------

>>> Look for

$r_in = \%in;

>>> Add following line of code

$r_in = check_form_input($r_in);

>>> so that you have


$r_in = \%in;
$r_in = check_form_input($r_in);

-------------------------------------------------------
2. Edit dcboard.cgi
-------------------------------------------------------

>>>> DCF Version 6.x

>>> Look for

if ($r_in->{'az'} eq 'jump') {
	# create forum_links
	print "Location: $r_in->{'forum'}\n\n";
	exit;
}

>>> After this line of code, add

$r_in = check_form_input($r_in);

>>> so that you have

if ($r_in->{'az'} eq 'jump') {
   # create forum_links
   print "Location: $r_in->{'forum'}\n\n";
   exit;
}

$r_in = check_form_input($r_in);


>>>> DCF2000 1.x

>>> Look for

$r_in = \%in;

>>> After this line of code, add

if ($r_in->{'az'} eq 'jump') {
	# create forum_links
	print "Location: $r_in->{'forum'}\n\n";
	exit;
}
$r_in = check_form_input($r_in);

>>> so that you have

$r_in = \%in;

if ($r_in->{'az'} eq 'jump') {
   # create forum_links
   print "Location: $r_in->{'forum'}\n\n";
   exit;
}

$r_in = check_form_input($r_in);

>>>> DCF99 - EDIT ALL .cgi files.

>>> Look for

$r_in = \%in;

>>> After this line of code, add

$r_in = check_form_input($r_in);

>>> so that you have

$r_in = \%in;
$r_in = check_form_input($r_in);


-------------------------------------------------------
3. Edit dcforumlib.pl
-------------------------------------------------------

>>> Add following function to dcforumlib.pl:

###########################################
#--function check_form_input begin here --#

sub check_form_input {

   my $r_in = shift;
   
   # mod.2000.11.14.01 security patch
   # parameter forum should only be alphanumeric characters
   if ($r_in->{'forum'}) {
      $r_in->{'forum'} =~ s/\W//g;
   }

   if ($r_in->{'s_forum'}) {
      $r_in->{'s_forum'} =~ s/\W//g;
   }

   # parameter conf should only be alphanumeric characters
   if ($r_in->{'conf'}) {
      $r_in->{'conf'} =~ s/\W//g;
   }

   # mod.2001.03.30.01 security patch
   # parameter az should only be alphanumeric characters
   if ($r_in->{'az'}) {
      $r_in->{'az'} =~ s/\W//g;
   }
   
   # parameter command should only be alphanumeric characters
   if ($r_in->{'command'}) {
      $r_in->{'command'} =~ s/\W//g;
   }

   # parameter command should only be alphanumeric characters
   if ($r_in->{'quote'}) {
      $r_in->{'quote'} =~ s/\W//g;
   }

   # parameter om should only be numeric characters
   if ($r_in->{'om'}) {
      $r_in->{'om'} =~ s/\D//g;
   }

   # parameter omm should only be alphanumeric characters
   if ($r_in->{'omm'}) {
      $r_in->{'omm'} =~ s/\D//g;
   }

   # parameter mark should only be alphanumeric characters
   if ($r_in->{'mark'}) {
      $r_in->{'mark'} =~ s/\D//g;
   }

   # If body, strip off any HTML tags of the form
   # script, object, embeb, applet, form, input
   if ($r_in->{'body'}) {
      $r_in->{'body'} =~ s/\[\s*\/?(script|object|embed|applet|form|input|\n)[^\]]*\]//gi; 
      # Also remove any SSI tags
      $r_in->{'body'} =~ s/\[\!--\#([^\]]|\n)*--\]//gi;
   }

   # Remove any HTML tags in subject
   if ($r_in->{'subject'}) {
      $r_in->{'subject'} =~ s/\[(([^\]]|\n)*)\]//gi;
   }

   # Remove any HTML tags in name
   if ($r_in->{'name'}) {
      $r_in->{'name'} =~ s/\[(([^\]]|\n)*)\]//gi;
   }

   return $r_in;

}
#--function check_form_input end here --#
###########################################

Here is the text file version of above code.

Click here to see this new file. Due to different versions of dcforumlib.pl, you must not use this copy of dcforumlib. You must cut and past above code as shown.

Following patch is only for the owners of DCF2000 and DCF6

-------------------------------------------------------
- Edit upload_file.pl (DCF2K, and DCFV6 only)
-------------------------------------------------------

>>> Look for:

   my $max_file_size = $r_setup->{'file_upload_size'} * 1024;
   print_header();
   print_header_end();

>>> Following this line, add

   unless ($r_setup->{'file_upload'} eq 'on') {
         $heading = "POSTING ERROR - PLEASE CONTACT YOUR ADMIN";
         $sub_heading = "File Upload Disabled.";
         return ($heading,$sub_heading,'','');
   }

>>> so that you have

   my $max_file_size = $r_setup->{'file_upload_size'} * 1024;
   print_header();
   print_header_end();

   unless ($r_setup->{'file_upload'} eq 'on') {
         $heading = "POSTING ERROR - PLEASE CONTACT YOUR ADMIN";
         $sub_heading = "File Upload Disabled.";
         return ($heading,$sub_heading,'','');
   }


>>> Look for:

   if ($r_in->{'command'} eq 'save') {

      unless ( $ENV{'HTTP_REFERER'} =~ /$cgiurl/i) {
         my $temp = join("::",$r_in->{'userdata'}->{'Username'},
            $ENV{'REMOTE_HOST'},$ENV{'REMOTE_ADDR'});
         check_datafile("$password_file_dir/$sec_file");
         appenddata("$password_file_dir/$sec_file",$temp);
         print_header();
         print_header_end();
         $heading = "POSTING ERROR - PLEASE CONTACT YOUR ADMIN";
      }

>>> Following this code add

      elsif (invalid_file_type($r_in->{'file_type'})) {
         my $temp = join("::",$r_in->{'userdata'}->{'Username'},
            $ENV{'REMOTE_HOST'},$ENV{'REMOTE_ADDR'});
         check_datafile("$password_file_dir/$sec_file");
         appenddata("$password_file_dir/$sec_file",$temp);
         $heading = "POSTING ERROR - PLEASE CONTACT YOUR ADMIN";
         $sub_heading = "INVALID FILE TYPE";
      }

>>> so that you have

      unless ( $ENV{'HTTP_REFERER'} =~ /$cgiurl/i) {
         my $temp = join("::",$r_in->{'userdata'}->{'Username'},
            $ENV{'REMOTE_HOST'},$ENV{'REMOTE_ADDR'});
         check_datafile("$password_file_dir/$sec_file");
         appenddata("$password_file_dir/$sec_file",$temp);
         print_header();
         print_header_end();
         $heading = "POSTING ERROR - PLEASE CONTACT YOUR ADMIN";
      }
      elsif (invalid_file_type($r_in->{'file_type'})) {
         my $temp = join("::",$r_in->{'userdata'}->{'Username'},
            $ENV{'REMOTE_HOST'},$ENV{'REMOTE_ADDR'});
         check_datafile("$password_file_dir/$sec_file");
         appenddata("$password_file_dir/$sec_file",$temp);
         $heading = "POSTING ERROR - PLEASE CONTACT YOUR ADMIN";
         $sub_heading = "INVALID FILE TYPE";
      }


>>> At the end of the program, before

1;

>>> add

sub invalid_file_type {
   my $file_type = shift;

   my @allowed = qw(html jpg zip txt gif tar);

   foreach (@allowed) {
      if ($file_type eq $_) {
         return 0;
      }
   }
   return 1;
}

>>> so that you have

sub invalid_file_type {
   my $file_type = shift;

   my @allowed = qw(html jpg zip txt gif tar);

   foreach (@allowed) {
      if ($file_type eq $_) {
         return 0;
      }
   }
   return 1;
}

1;

Click here to see this new file. If you are using DCForum2000 1.x or DCForum Version 6.x, you may save this file as upload_file.pl and replace your copy with this one.

If you have any questions, or need assistance, please contact David

Thank you for your continue support.

David Choi
DCScripts