Use mod_rewrite to protect from “Apache Killer”

The last few days OSS Web Admins are very concerned about a recent Apache HTTPd Denial Of Service. “Apache Killer (written by Kingcope)” is a perl script causing remote DoS through memory exhaustion to an apache httpd server. The script sends large amounts of HEAD requests with lots of ranges, resulting in swapping memory to filesystem on the remote side, making the remote system unstable.

While the vulnerability is publicly known from August 19, an official advisory haven’t been published yet. Although, a temp workaround must be found in order to avoid regular system crashes. The most efficient and elegant solution that i have read is using the mod_rewrite engine.

Let’s get our hands dirty to see how we can deal with the DoS remote attack.

 

The target system is an Ubuntu 8.04 with Apache/2.2.8 installation. Initially, i run the perl script to confirm that the system is vulnerable.

 

Now that we have confirmed that the target is vulnerable, lets apply the rewrite rule. I create a .htaccess file in the httpd docs main folder with the following code:

1
2
3
4
5
6
RewriteEngine On
RewriteLog /var/log/apache2/rewrite.log
RewriteLogLevel 3
RewriteCond %{REQUEST_METHOD} ^(HEAD|GET) [NC]
RewriteCond %{HTTP:Range} ([0-9]*-[0-9]*)(\s*,\s*[0-9]*-[0-9]*)+
RewriteRule .* - [F]

This workaround uses mod_rewrite to forbid GET|HEAD request with multiple ranges in the Range HTTP header. I have also enabled the logging mechanism for debugging reasons.

 

Now lets see if we have succeed our goal.

 

Problem solved!

I have also tested the above solution in a Debian Squeeze 64-bit with Apache/2.2.16 installed, and it works like a charm.

Knowing that with the above rule Web Admins can deal with the “Apache Killer”, the final step is to copy it to the apache’s virtualhost configuration.

 

ps1: A more comprehensive discussion about the apache vulnerability can be found here.
ps2: If i come across with a more efficient workaround or an official patch, i will return with a post update.

 

update August 26, 2011 (request-range addition)

Regular expression has been revised and “Request-Range” case has been added (thanks to Gappy):

1
2
3
4
RewriteEngine on
RewriteCond %{HTTP:range} !(^bytes=[^,]+(,[^,]+){0,4}$|^$) [NC,OR]
RewriteCond %{HTTP:request-range} !(^bytes=[^,]+(,[^,]+){0,4}$|^$) [NC]
RewriteRule .* - [F]

The number 5 is arbitrary. Several 10′s should not be an issue and may be required for sites which for example serve PDFs to very high end eReaders or use things such complex http based video streaming.

Additionally here is an alert rule for Snort IDS:


alert tcp $EXTERNAL_NET any -> any 80 (msg:"INBOUND Apache Killer script: Local web server is under attack."; content:"Range:bytes=0-"; classtype: denial-of-service; threshold: type threshold, track by_src, count 5 , seconds 20; sid:3000005;)

Some other workarounds until the official patch can be found here.

 

update August 31, 2011

Apache version 2.2.20 fixed the bug. The relative official announcement can be found in the official site.

 

 

A. Bechtsoudis

4 Comments

GappyAugust 26th, 2011 at 11:00

What happens if you replace the “Range” header in the attack code with “Request-Range” – does that also need to be blocked?

anestisbAugust 26th, 2011 at 11:52

To be honest i have never heard about the “Request-Range” field. I searched the apache source and find out this:
if (!(range = apr_table_get(r->headers_in, “Range”))) {
range = apr_table_get(r->headers_in, “Request-Range”);
}

I have edited the attack perl script using the “Request-Range” instead of the “Range”. Victim apache served the request with the same way resulting in DoS too. Although the same workaround with the mod_rewrite is effective against “Request-Range” too.

ps. I have updated the rules to be fully complete.

GappyAugust 26th, 2011 at 12:08

Yes, everyone should update their instructions for working around this issue to include the Request-Range header also, otherwise attempts at blocking the exploit will be insufficient?

anestisbAugust 26th, 2011 at 13:50

You are right, coders should take into account the “Request-Range” too.

I have already sent a relevant email to the full-disclosure mailing list (credits to you of course):
http://seclists.org/fulldisclosure/2011/Aug/300

And Dirk-Willem has updated the previous advisory relatively:
http://seclists.org/fulldisclosure/2011/Aug/301