PHP会话序列化程序数据注入漏洞

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

受影响系统:
PHP PHP <= 5.3.2
PHP PHP <= 5.2.13
描述:
--------------------------------------------------------------------------------
PHP是广泛使用的通用目的脚本语言,特别适合于Web开发,可嵌入到HTML中。

默认的会话还原序列化程序知道两个特殊字符:PS_DELIMITER和PS_UNDEF_MARKER。前者用于分隔所存储的会话变量,后者用于标记未定义的会话变量。以下代码实现上述功能:

while (p < endptr) {
        zval **tmp;
        q = p;
        while (*q != PS_DELIMITER) {
            if (++q >= endptr) goto break_outer_loop;
        }
        if (p[0] == PS_UNDEF_MARKER) {
            p++;
            has_value = 0;
        } else {
            has_value = 1;
        }

namelen = q - p;
        name = estrndup(p, namelen);
        q++;

if (zend_hash_find(&EG(symbol_table), name, namelen + 1, (void **) &tmp) == SUCCESS) {
            if ((Z_TYPE_PP(tmp) == IS_ARRAY && Z_ARRVAL_PP(tmp) == &EG(symbol_table)) || *tmp == PS(http_session_vars)) {
                goto skip;
            }
        }

if (has_value) {
            ALLOC_INIT_ZVAL(current);
            if (php_var_unserialize(&current, (const unsigned char **) &q, (const unsigned char *) endptr, &var_hash TSRMLS_CC)) {
                php_set_session_var(name, namelen, current, &var_hash  TSRMLS_CC);
            }
            zval_ptr_dtor(&current);
        }
        PS_ADD_VARL(name, namelen);
skip:
        efree(name);

p = q;
    }

问题是会话序列化程序仅正确处理了PS_DELIMITER,根本没有处理PS_UNDEF_MARKER:

PS_ENCODE_LOOP(
        smart_str_appendl(&buf, key, key_length);
        if (memchr(key, PS_DELIMITER, key_length)) {
            PHP_VAR_SERIALIZE_DESTROY(var_hash);
            smart_str_free(&buf);
            return FAILURE;
        }
        smart_str_appendc(&buf, PS_DELIMITER);

php_var_serialize(&buf, struc, &var_hash TSRMLS_CC);
    } else {
        smart_str_appendc(&buf, PS_UNDEF_MARKER);
        smart_str_appendl(&buf, key, key_length);
        smart_str_appendc(&buf, PS_DELIMITER);
);

以PS_UNDEF_MARKER开始的会话变量名称会迷惑会话还原序列化程序。也就是任何允许向会话中写入任意变量的PHP代码可以向会话中注入任意序列化的值,且类似于以下的代码等同于还原序列化用户输入。

<?php
   session_start();
   $_SESSION[$_POST['prefix'] . 'bla'] = $_POST['data'];
?>

<*来源:Stefan Esser (s.esser@ematters.de
 
  链接:
*>

测试方法:
--------------------------------------------------------------------------------

警 告

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

<?php
   session_start();
   $_SESSION[$_POST['prefix'] . 'bla'] = $_POST['data'];
?>

或:

<?php
   session_start();
   $_SESSION = array_merge($_SESSION, $_POST);
?>

通过提交prefix=!和data=|xxx|O:10:"evilObject":0:{}的POST请求,就可以向会话中注入任意序列化的数据。

建议:
--------------------------------------------------------------------------------
厂商补丁:

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

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwspsy.html