discuz利用ssrf+缓存应用getshell漏洞分析
in 漏洞分析 with 0 comment

discuz利用ssrf+缓存应用getshell漏洞分析

in 漏洞分析 with 0 comment

0x01.准备工作

一哥发的discuz有条件远程命令执行,很多大站受影响,wooyun上还没公布细节
在某安全公众号上看到一哥简单的说了一下原理,是ssrf+redis/memcache的问题
本着学习的态度,顺着这个思路,还原了一下整个漏洞
http://www.wooyun.org/bugs/wooyun-2016-0214429
其中redis和memcache的原理是一样的,drops上有一篇利用memcache攻击的文章http://drops.wooyun.org/papers/8261我在这里就还原利用redis的攻击方法
讲原理之前先来说说redis/memcache是干嘛的呢?
其实可以把它们理解成一个高性能的数据库,当网站的缓存很大的时候
利用redis/memcache来处理缓存可以提高网站的性能,在dz的后台也可以看到是否在使用redis/memcache
QQ20170520-163439@2x.png
首先你要自己在服务器上安装redis
然后php默认没有redis扩展,还需要安装phpredis扩展
顺便说一下,phpredis的2.1版本兼容性不太好,安装上去后无法访问网站,用2.28版本就可以了
配置这个环境是花了我一下午的时间,其中很多曲折,都不是重点安装之后在phpinfo()中能看到redis
QQ20170520-150811@2x.png
在dz的配置文件config_global.php中填入redis的地址就可以了
端口都是默认的6379,prefix是dz中随机生成的,默认无密码
QQ20170520-150924@2x.png
都完成之后在dz后台能看到运行情况
QQ20170520-150956@2x.png
简单说一下redis的使用吧
启动之后在本机的6379端口会运行起来redis的服务,redis可以理解为一个数据库
数据以key=>value这样的形式储存,其实更像一个数组,使用如下
QQ20170520-151034@2x.png
Redis还支持eval “lua命令”这样来执行,我们在后面会用到,简单的例子如下
QQ20170520-151109@2x.png

0x02.漏洞原理与复现

简单的说,漏洞就是通过ssrf来操作redis,更改了全局变量的值,导致任意代码执行。
当dz设置使用缓存后,初始化时会把缓存内容加入全局变量$_G
Source/class/discuz/discuz_application.php中设置
QQ20170520-151345@2x.png
而在调用缓存的地方source/fucntion/function_core.php
QQ20170520-151429@2x.png
其中,关键点的两个变量我们都可以通过redis修改,来getshell为了方便测试,可改为

$_G['setting']['output']['preg']['search']=”/.*/e”;
$_G['setting']['output']['preg']['replace']=”phpinfo();”;

我们来看看哪些地方可以触发漏洞,搜索一下output_replace()
发现只在function output和function output_ajax中用到了
两个函数中应该都可以触发,挑output_ajax来看看
QQ20170520-151543@2x.png
一开始我准备在划线的if前面print_r一下if判断中的全局变量$_G['setting']['rewritestatus']
但是什么也打印不出来,最后发现是前面的ob_get_contents()这个函数的问题
这个函数会把输出的值存到缓存中,并不会打印到浏览器页面上
那怎么看这个变量的值呢?
还可以把这个变量写到txt文件中,再来查看。
发现正常运行情况下,if判断是不满足的,其中$_G['setting']['rewritestatus'] =0
所以我们在修改缓存值的时候还需要把它改为1,接着看看output_ajax()在哪些地方用到了。
/data/template/1_1_common_footer_ajax.tpl.php
QQ20170520-151733@2x.png
这个文件用到的地方很多,比如在forum_ajax中
QQ20170520-151849@2x.png
这个地方对应的地址是/forum.php?mod=ajax&action=getthreadtypes&inajax=yes
QQ20170520-151943@2x.png
然后我们看下如何通过redis修改缓存值
dz使用redis时,全局变量$_G[‘setting’]放在xxxx_setting中的
其中前缀就是前面config_global.php中的prefix的值
那我们这里的全局变量是放在5Z13gm_setting中的,我们来看看
QQ20170520-152047@2x.png
里面数据很多,我们可以看到这里是序列化之后再放进去的
格式是$a['output']['preg']['search']['plugins']这样的,那么我们写个脚本操作
QQ20170520-152143@2x.png
这里我们的redis是没有设置密码的,一般网站会设置密码
(通过dz的ssrf的话就不考虑密码的问题,在config_global.php中别人都帮我们设置过了)
运行脚本之后,我们再访问:/discuz/forum.php?mod=ajax&inajax=yes&action=getthreadtypes
成功getshell
QQ20170520-152249@2x.png
有的同学会注意到,前缀我们是不知道的啊,那不就不能修改数据了吗?
但是redis是支持模糊查询的,可以通过keys方法,举个例子
QQ20170520-152323@2x.png
我们是要通过ssrf来操作redis,怎么通过一个链接来操作呢?
dz的ssrf是默认调用curl请求,因此会支持gopher或者dict协议
这对我们已经足够了,我们写个脚本发送利用curl发送gopher请求
QQ20170520-152410@2x.png
%0D%0A是换行符,相当于执行下一条指令
我们执行的指令其实是set name cheng
QQ20170520-152451@2x.png
这里返回ok就是表示我们执行成功
这样就相当于在命令行中执行redis的指令
有个问题,还是前缀的问题,我们的前缀是可以通过指令keys *_setting获取到
但是ssrf的时候看不到返回值的,我们没有办法获取到返回值,那怎么办?
这里我们就要用到lua脚本,前面提到了,redis是可以通过eval来执行lua脚本的,我们看看我们的lua脚本
QQ20170520-152543@2x.png
通过keys方法把xxx_setting保存到v中,然后set v xxxx
这样就不会有前缀未知的问题了,gopher的链接就是
QQ20170520-152624@2x.png
执行结果
QQ20170520-152842@2x.png
最后return 1了,说明执行成功,刷新页面
QQ20170520-152912@2x.png
成功getshell,因为我们破坏了5Z13gm_setting中的数据,会导致网站访问异常
QQ20170520-152941@2x.png
利用flushdb命令重置redis中的数据,再刷新才能恢复访问。

0x03.感想

讲到这里整个漏洞基本复现完了,剩下结合ssrf的复现
我在脚本里已经是使用curl来发送请求的,所以通过ssrf来实现应该也不是问题
为什么说ssrf也要合适,因为我们看到我们的链接是
QQ20170520-153045@2x.png
当中包含了很多特殊字符,而且脚本在里面也不方便去构造满足条件的ssrf
比如dz最新版倒是有一个ssrf,是一哥之前发的一个http://www.wooyun.org/bugs/wooyun-2015-0151179还能利用
QQ20170520-153209@2x.png
但是这个利用起来就有条件,比如链接必须是图片链接,最后要是.jpg,协议必须是http
QQ20170520-153335@2x.png
因为是在链接中,还不能包含特殊字符,不然会被xss_check拦截
QQ20170520-153409@2x.png
但是,还是可以利用的,具体怎么利用这里不说
因为这个漏洞在时间上还属于0day,剩下的就留给各位自己分析
认真想了想,这个漏洞本质上是通过gopher协议操作redis修改全局变量,也不好去补
把全局变量不放到redis中处理?这是一个方法,但是又会降低使用redis后网站效率
dz能做的就是处理好ssrf的地方,不要提供跳板让攻击者能够getshell
以后dz出一个ssrf对于这些使用redis的大站来说都是一个getshell的威胁,这也挺难受的。
最后提一点,redis使用的时候一定要设置密码和访问权限
redis出现未授权访问可以很轻易的拿到root权限,
具体可以看wooyun实例http://www.wooyun.org/bugs/wooyun-2015-0152710

Comments are closed.