dedecms为什么经常爆出严重漏洞?

[复制链接]
lanxueling 发表于 2023-8-25 06:45:01|来自:北京 | 显示全部楼层 |阅读模式
自从知晓dedecms这个程序以来,经常听到的消息就是,dedecms又爆出了XX漏洞,尤其是今年以来接连不断的爆出严重漏洞,而dedecms的反应却是奇慢无比,不仅对于乌云上面提交的额漏洞没有回应更迟迟拿不出解决办法;对于dedecms经常爆出严重漏洞这个问题之前在论坛上看见有人说是因为使用的人多,但是同样是cms程序,wordpress的使用范围更广,为什么wordpress却很少像dedecms这样,我觉得对于一个想做大做好产品的公司这是不应该的,对于这个问题不知道大家怎么看
全部回复2 显示全部楼层
moneypk 发表于 2023-8-25 06:45:52|来自:北京 | 显示全部楼层
DedeCMS的include目录下common.ini.php的_RunMagicQuotes函数对用户的输入进行较为严格的过滤,但是并未对_SERVER和_FILE 进行过滤。
include/common.inc.php
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|_SESSION)#', $svar)) {
exit('Request var not allow!');
            }
$svar = addslashes($svar);
        }
    }
return $svar;
}
回到漏洞本身,文件包含的漏洞触发点位于plus/flink.php 文件的ShowMsg函数。
if ($dopost == 'save') {
$validate = isset($validate) ? strtolower(trim($validate)) : '';
$svali = GetCkVdValue();
if ($validate == '' || $validate != $svali) {
        ShowMsg('验证码不正确!', '-1');
exit();
    }
ShowMsg函数又由include/common.func.php 定义。
function ShowMsg($msg, $gourl, $onlymsg = 0, $limittime = 0)
{
if (empty($GLOBALS['cfg_plus_dir'])) {
$GLOBALS['cfg_plus_dir'] = '..';
    }
if ($gourl == -1) {    #1
$gourl = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''; #2
if ($gourl == "") {
$gourl = -1;
        }
    }

$htmlhead = "
    <html>\r\n<head>\r\n<title>DedeCMS提示信息
    ...
    <script>\r\n";
$htmlfoot = "
    </script>
    ...
    </body>\r\n</html>\r\n";

$litime = ($limittime == 0 ? 1000 : $limittime);
$func = '';

//...

if ($gourl == '' || $onlymsg == 1) {
//...
    } else {
//...
$func .= "var pgo=0;
      function JumpUrl(){
        if(pgo==0){ location='$gourl'; pgo=1; }
      }\r\n";
$rmsg = $func;
//...
if ($onlymsg == 0) {
if ($gourl != 'javascript:;' && $gourl != '') {
$rmsg .= "<br /><a href='{$gourl}'>如果你的浏览器没反应,请点击这里...</a>"; #3
$rmsg .= "<br/></div>\");\r\n";
$rmsg .= "setTimeout('JumpUrl()',$litime);";
            } else {
//...
            }
        } else {
//...
        }
$msg = $htmlhead . $rmsg . $htmlfoot; #4
    }

$tpl = new DedeTemplate();
$tpl->LoadString($msg); #5
$tpl->Display(); #6
}
在include/common.func.php文件中有几个关键点;
当$gourl==-1时,$gourl=$SERVER['HTTP_REFERER'],$SERVER不在过滤文件中,而$_SERVER['HTTP_REFERER']用户可控。
$rmsg中包含$gourl;
$msg = $htmlhead . $rmsg . $htmlfoot;
$msg传入LoadString中,$tpl->LoadString($msg);<==>$gourl传入LoadString中;
最后调用Display函数;
LoadString函数和Display函数位于
include/dedetemplate.class.php
class DedeTemplate
{
//...
public function LoadString($str = '')
    {
$this->sourceString = $str; #1
$hashcode = md5($this->sourceString);
$this->cacheFile = $this->cacheDir . "/string_" . $hashcode . ".inc";
$this->configFile = $this->cacheDir . "/string_" . $hashcode . "_config.inc";
$this->ParseTemplate();
    }

//...
public function Display()
    {
global $gtmpfile;
extract($GLOBALS, EXTR_SKIP);
$this->WriteCache(); #2
include $this->cacheFile; #3
    }
在LoadString中,将接收到的$msg赋值给$this->sourceString变量;
在Display函数中,调用了WriteCache函数,同时包含了cacheFile;
继续跟进WriteCache函数;
public function WriteCache($ctype = 'all')
    {
if (!file_exists($this->cacheFile) || $this->isCache == false
            || (file_exists($this->templateFile) && (filemtime($this->templateFile) > filemtime($this->cacheFile)))
) {
if (!$this->isParse) {
//...
            }
$fp = fopen($this->cacheFile, 'w') or dir("Write Cache File Error! ");
flock($fp, 3);
$result = trim($this->GetResult()); #1
$errmsg = '';
if (!$this->CheckDisabledFunctions($result, $errmsg)) { #2
fclose($fp);
@unlink($this->cacheFile);
die($errmsg);
            }
fwrite($fp, $result);
fclose($fp);
//...
        }
在WriteCache中,调用了GetResult函数,将函数返回值赋值$result变量
而在GetResult中,最后返回$this->SourceString赋值$result;
在LoadString函数中,在LoadString中,将接收到的$msg赋值给$this->sourceString变量,$msg中又包含$gourl,也就是用户可控的referer头;
然后调用了CheckDisabledFunctions函数,并将$result传入。
/**
     *  把分析模板输出到一个字符串中,并返回
     *
     * @access public
     * @return string
     */
public function GetResult()
    {
$ResultString = '';
if ($this->Count == -1) {
return $this->SourceString;
        }
$this->AssignSysTag();
$nextTagEnd = 0;
$strok = "";
for ($i = 0; $i <= $this->Count; $i++) {
$ResultString .= substr($this->SourceString, $nextTagEnd, $this->CTags[$i]->StartPos - $nextTagEnd);
$ResultString .= $this->CTags[$i]->GetValue();
$nextTagEnd = $this->CTags[$i]->EndPos;
        }
$slen = strlen($this->SourceString);
if ($slen > $nextTagEnd) {
$ResultString .= substr($this->SourceString, $nextTagEnd, $slen - $nextTagEnd);
        }
return $ResultString;
    }
CheckDisabledFunctions函数主要功能利用in_array函数是对输入的$str进行过滤,不允许出现对应的危险函数。
public function CheckDisabledFunctions($str, &$errmsg = '')
    {
global $cfg_disable_funs;
$cfg_disable_funs = isset($cfg_disable_funs) ? $cfg_disable_funs : 'phpinfo,eval,exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,file_put_contents,fsockopen,fopen,fwrite';
// 模板引擎增加disable_functions
if (!defined('DEDEDISFUN')) {
$tokens = token_get_all_nl($str);
$disabled_functions = explode(',', $cfg_disable_funs);
foreach ($tokens as $token) {
if (is_array($token)) {
if ($token[0] = '306' && in_array($token[1], $disabled_functions)) {
$errmsg = 'DedeCMS Error:function disabled "' . $token[1] . '" <a href="http://help.dedecms.com/install-use/apply/2013/0711/2324.html" target="_blank">more...</a>';
return false;
                    }
                }
            }
        }
return true;
    }
最后回到WriteCache函数,将$result写入缓存文件中;
并在LoadString函数中包含该缓存文件
而referer头中并未过滤双引号,所以可以使用双引号绕过in_array函数;


RCE漏洞的利用链如图所示:


dedecms已经对漏洞修复,用户无法无法控制gourl变量,并去掉了模板渲染,改成echo。但挖掘的思路和思考的方式很值得学习,功能越复杂,漏洞越容易产生。
ytey3j47r4 发表于 2023-8-25 06:46:13|来自:北京 | 显示全部楼层
我们刚刚发布了一个  DedeCMS顽固木马后门专杀工具 2.0版本 就想看看zhihu上有没有相关困惑的朋友,一搜索果然有。 下载及使用教程:
DedeCMS顽固木马后门专杀工具 V 2.0 发布及使用教程  其实漏洞是程序都会有,dedecms 使用的多 研究的人也多。不过dedecms最主要的问题 是他们对待安全漏洞的态度,很多时候 我们报告他们漏洞 他们都不搭理 甚至不修补,另外一个就是很多站长不知道怎么更新和补丁,所以导致这样的局面。这个也是开发“DedeCMS顽固木马后门专杀工具” 主要原因 :)

快速回帖

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则