vADC Docs

Protecting against Java and PHP floating point bugs

by on ‎03-20-2013 07:57 AM - edited on ‎06-01-2015 09:54 AM by PaulWallace (2,083 Views)

Recent investigations have revealed an error in the PHP and Java floating point library that may be exploited to cause a denial of service against a web service. You can use Stingray Traffic Manager to filter incoming traffic and discard requests that may seek to exploit this fault.

 

Background

 

In January 2011, a bug was discovered in PHP's floating point library. Under certain circumstances, an attempt to convert the string '2.2250738585072011e-308' into a floating point value would hang the PHP runtime.

 

A similar problem was discovered in the Java runtime (and compiler). The two articles give a detailed description of the nature of the problem and its cause (relating to the parsing of a number close to DBL_MIN, the smallest non-zero number that can be represented as a floating point).

 

The implications

 

What are the implications to a web developer or security team? This fault can be exploited to mount a denial-of-service attack if an attacker can send a carefully-crafted request that causes the PHP or Java runtime to attempt to convert a string into the problematic floating-point value. Web developers are accustomed to treating user input with suspicion - for example, careful escaping to prevent SQL injection attacks - but who would have thought that an innocuous floating point number could pose a similar threat? Any application code that parses input into a floating point could be vulnerable; for example, a mapping API that takes coordinates as input may be vulnerable.

 

However, there's an even simpler potential problem that is inherent the HTTP protocol; the family of 'Accept' HTTP headers use floating point scores that may be exploitable in certain implementations.

 

Accept: text/*;q=0.3, text/html;q=0.7, text/html;level=1,
        text/html;level=2;q=0.4, /;q=0.5
Accept-Charset: iso-8859-5, unicode-1-1;q=0.8
Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0
Accept-Language: da, en-gb;q=0.8, en;q=0.7

 

The wisest solution to protecting against this vulnerability would be to deploy a Web Application Firewall (see Stingray Application Firewall) and verify that the baseline protection rules detect attempts to exploit this attack. It's also possible to detect and drop these attacks using a TrafficScript rule, and this article presents a couple of solutions.

 

Floating Point: Solution 1

 

The following TrafficScript request rule checks all of the headers in each HTTP request. If the headers contain the sequence of digits that are the signature of this number, then the rule logs a warning and drops the request immediately.

 

$headers = http.getHeaders();  
foreach( $header in hash.keys( $headers ) ) {  
   $value = $headers[$header];  
   # remove any decimal points  
   $value = string.replace( $value, '.', '' );  
   if( string.contains( $value, "2225073858507201" ) ) {  
      log.warn( "suspect request - dropping" );  
      connection.discard();  
   }  
}  

 

The result:

 

fpbug1.png

 

Floating Point: Solution 2

 

This more advanced solution checks both headers and form parameters, logs a more descriptive error message and illustrates the use of TrafficScript subroutines to minimise duplicated code:

 

# Checks the array of key-value (headers or form parameters)  
# If any value contains the suspect floating point value, return the  
# name of the header or form parameter  
sub check( $h ) {  
   foreach( $k in hash.keys( $h ) ) {  
      $v = $h[$k];  
      # remove any decimal points  
      $v = string.replace( $v, '.', '' );  
      if( string.contains( $v, "2225073858507201" ) ) return $k;  
   }  
}  
  
# Log the request and drop it immediately  
sub logAndDrop( $reason, $k, $v ) {  
   $ip = request.getRemoteIP();  
   $country = geo.getCountry( $ip );  
   if( !$country ) $country = 'unknown';  
   $msg = 'Request from ' . $ip . ' (' . $country . ') ' .  
      ' contained suspicious ' . $reason . ': ' . $k . ': ' . $v;  
   log.warn( $msg );  
   # Optional - raise an event to trigger a configured event handler  
   # event.emit( "FloatingPointAttack", $msg );  
   connection.discard();  
}  
  
$headers = http.getHeaders();  
if( $h = check( $headers ) ) logAndDrop( "header", $h, $headers[$h] );  
$params = http.getFormParams();  
if( $h = check( $params ) ) logAndDrop( "parameter", $h, $params[$h] );

 

The result, from an internal IP address (192.168.35.1) and using a querystring ?userid=2.2250738585072011e-308:

 

fpbug2.png

 

There is a very, very slim risk of false positives with these rules (dropping connections which would not have a malicious effect), but the probability of the string "2225073858507201" appearing is miniscule (except perhaps for blog posts about this very vulnerability...).

Contributors