Article

PHP vunerability in floating point numbers

January 6th, 2011

This morning, we received a notification from Zend, regarding a PHP vunerability. This is an excerpt of the message:

A critical vulnerability in the PHP engine has just been identified...

Due to the way the PHP runtime handles internal conversion of floating point numbers, it is possible for a remote attacker to bring down a web application simply by adding a specific parameter to a query string in their web browser.

Without stating actual examples from existing projects like Wordpress and Drupal (what would the script-kiddies do with the rest of the afternoon if we enlightened them, right?), you would actually be very hard-pressed to find a project that does not have a variable that is used somewhere in the code. And, this is not limited to the query string. Posting variables would be just as hazardous, in fact any user input can cause this.

Testing locally we confirmed this, and it is clear that this exploit could potentially have a huge impact on many major websites out there. PHP, 32 bits, running on Linux or Windows, can be forced to loop forever when asked to create a float with value 2.2250738585072011e-308.

How can PHP be forced to do this by query string?? Well.. since it's a loosely typed language, all you need to do is set the right value to a variable thet will be compared to something else in the script. While the variable is initially a string, comparing for equality ( with " == " not, not to be confused with identical-icity-ness with "=== ") will force a type change and an infinite loop for that process.

How to reproduce:

In a PHP script, run

echo 2.2250738585072011e-308;

On the commandline, run

php -r "echo 2.2250738585072011e-308;"

How can this become a problem on websites? Consider a script that uses a query string parameter like this:

// input is a string at this point.
// Either from POST or GET or COOKIE
$input = $_REQUEST["input"];

if ( $input == 'page' ) {
    // we hang if the value of $input was
    // 2.2250738585072011e-308
}

// the same goes for a switch statement
switch ( $input ) {
case "page":
    // we hang if the value of $input was
    // 2.2250738585072011e-308
    break;
}

Zend has updated Zend Server, and the community editions of PHP have been patched, but if you are running php from FreeBSD port like me, there is no update yet... So here is a temporary fix to clean up the malicious input (author included in the script):

<?php
// *************************************************************
// QUICK FIX / WORKAROUND FOR PHP FLOATING POINT DOS ATTACK
// provided by AirCraft24.com / www.aircraft24.com
// version 1.4, released 2011-01-06 13:00 GMT+1
// *************************************************************

if ($_REQUEST) {

  function php_53632_workaround(&amp;$requestVal) {
    // recurse if value is an array
    if (is_array($inputVal)) {
      return array_walk($requestVal, 'php_53632_workaround');
    }

    // check for signature in value, die if found<br />
    if (strstr(str_replace('.','',$requestVal),'22250738585072011')) {
      header("Status: 422 Unprocessable Entity");
      die ("Script interrupted due to Floating point DoS attack.");
    }

  }

  // send $_REQUEST - array into function
  array_walk($_REQUEST, 'php_53632_workaround');
}

// *************************************************************
// END QUICK FIX / WORKAROUND FOR PHP FLOATING POINT DOS ATTACK
// *************************************************************
?>

References:

Ramon de la Fuente

Pointy haired boss