Taming the Beast – The Floating Point DoS Vulnerability

Originally posted as Taming the Beast

The recent multi-language numerical parsing DOS bug has been named the “Mark of the Beast“. Some claim that this bug was first reported as early as 2001.This is a significant bug in (at least) PHP and Java. Similar issues have effected Ruby in the past. This bug has left a number of servers, web frameworks and custom web applications vulnerable to easily exploitable Denial of Service.

Oracle has patched this vuln but there are several non-Oracle JVM’s that have yet to release a patch. Tactical patching may be prudent for environment.

Here are three approaches that may help you tame this beast of a bug.

1) ModSecurity Rules

Ryan Barnett deployed a series of ModSecurity rules and documented several options at http://blog.spiderlabs.com/2011/02/java-floating-point-dos-attack-protection.html

2) Java-based Blacklist Filter

Bryan Sullivan from Adobe came up with the following Java-based blacklist filter.

This rule is actually quite accurate in *rejecting input* in the DOSable JVM numeric range. This fix, while simple, does indeed reject a series of normally good values.

[sourcecode language=”java”]
public static boolean containsMagicDoSNumber(String s) {
return s.replace(“.”, “”).contains(“2225073858507201”);
}
[/sourcecode]

3) Double Parsing Code

The following Java “safe” Double parsing code was based on a proof of concept by Brian Chess at HP/Fortify. This approach detects the evil range before trying to call parseDouble and returns the IEEE official value  ( 2.2250738585072014E-308 ) for any double in the dangerous range.
[sourcecode language=”java”]
private static BigDecimal bigBad;
private static BigDecimal smallBad;

static {
BigDecimal one = new BigDecimal(1);
BigDecimal two = new BigDecimal(2);
BigDecimal tiny = one.divide(two.pow(1022));

// 2^(-1022) 2^(-1076)
bigBad = tiny.subtract(one.divide(two.pow(1076)));

//2^(-1022) 2^(-1075)
smallBad = tiny.subtract(one.divide(two.pow(1075)));
}

public static Double parseSafeDouble(String input) throws InvalidParameterException {

if (input == null) throw new InvalidParameterException(“input is null”);

BigDecimal bd;
try {
bd = new BigDecimal(input);
} catch (NumberFormatException e) {
throw new InvalidParameterException(“cant parse number”);
}

if (bd.compareTo(smallBad) >= 0 && bd.compareTo(bigBad) <= 0) {
// if you get here you know you’re looking at a bad value. The final
// value for any double in this range is supposed to be the following safe #
//return safe number
System.out.println(“BAD NUMBER DETECTED – returning 2.2250738585072014E-308”);
return new Double(“2.2250738585072014E-308”);
}

//safe number, return double value
return bd.doubleValue();
}
[/sourcecode]

DoS Attack After Action Report – Shell Scripts

I wrote up a quick after action report with details about the little DoS attack that hit us. I figure that it may be handy for others to know about it.For the full report see http://isc.sans.org/presentations/jan4ddos.pdf

I mention in the report that simple shell scripts are helpful to quickly get a look at your logs while under attack. So here for the appsec streetfighters out there, some of the shell scripts I keep around to summarize my logs in a case like that:

Most recent top referrers.Defaults to last 10000 lines, but you can override that via a command line parameter.

#!/bin/sh
r=$1
if [[ $r -lt 1 ]]; then
 r=10000
fi
tail -$r access_log | cut -f4 -d'"'  \
 |  egrep -v 'http[s]?:\/\/isc[12]?\.sans\.org' \
 | grep -v 'http:\/\/www.dshield.org\/' | sort | uniq -c | sort -n

Top hosts accessing the site:

#!/bin/sh
r=$1
if [[ $r -lt 1 ]]; then
 r=10000
fi
tail -$r access_log | cut -f1 -d' ' \
    | sort | uniq -c | sort -n

The top URLs accessed on the site

#!/bin/sh
r=$1
if [[ $r -lt 1 ]]; then
r=10000
fi
tail -$r access_log | cut -f2 -d'"' \
| sort | uniq -c | sort -n

and finally, the top user agents

#!/bin/sh
r=$1
if [[ $r -lt 1 ]]; then
 r=10000
fi
tail -$r access_log | cut -f6 -d'"' | sort | uniq -c | sort -n

Nothing magic here. Just some simple functional shell scripts that have proven themselves many times before. I am using a slightly cusotmized “combined” log format in Apache. The column numbers may differ for your install. You will have to replace ‘access_log’ with the file name for your log.