SSRF 漏洞实例分析
0x00 漏洞信息简介
Crossday Discuz! Board(简称 Discuz!)是北京康盛新创科技有限责任公司推出的一套通用的社区论坛软件系统。自 2001 年 6 月面世以来,Discuz!已拥有 15 年以上的应用历史和 200 多万网站用户案例,是全球成熟度最高、覆盖率最大的论坛软件系统之一。目前最新版本 Discuz! X3.4 正式版于 2017 年 8 月 2 日发布,去除了云平台的相关代码,是 X3.2 的稳定版本。此次漏洞位于/source/module/misc/misc_imgcropper.php
中的 54 行处的$prefix
可控导致 SSRF。
2021最新整理网络安全/渗透测试/安全学习/100份src技术文档(全套视频、CTF、大厂面经、精品手册、必备工具包、路线)一>获取<一
0x01 漏洞详细分析
Discuz 开源地址为 Gitee,使用 git clone 克隆到本地
根据补丁提交记录来切换到漏洞修复前的前一个 commit 版本
本地搭建好运行环境之后首先访问页面http://www.a.com/dz/DiscuzX/upload/misc.php?mod=imgcropper
,然后点击裁切按钮并抓包
拦截之后重放数据包在提交内容位置添加参数cutimg
和picflag
,红框处填写需要请求的 IP 地址并发送数据包
这时服务器将成功收到请求
下面来看看后端是怎么处理的,断点地址为source/module/misc/misc_imgcropper.php
line 54。当传递的picflag
为2
时取$_G['setting']['ftp']['attachurl']
变量的值"/"
。接下来 55 行接收拼接可控变量cutimg
。
既然可控,那么就要看看它后面是怎么处理的,来到 Thumb 方法
进入init
方法,到达parse_url
方法后在source
中解析出了host
。此时就会进入dfsockopen
parse_url 支持//baidu.com/s 这种形式的 url 解析
继续跟进dfsockopen
方法,在该方法中又进行了解析,处理同上,由于不存在协议所以scheme
为null
,这样在最后拼接出来的 URL 就是://xx.com/
,这样的链接会自动补上协议,所以最后为http://://xx.com/
。
在 windows 中使用curl
请求该地址最终解析到了 192.168.163.1,也就是某个网卡的本地地址。请求路径为http://192.168.163.1/xx.com
此时我们能够进行内网请求,但是地址并不可控,所以需要找到一个 discuz 可以进行任意 url 跳转的漏洞,再请求该路径跳转出去。discuz 在退出的时候会取get
参数referer
中的值来进行跳转,下面来分析跳转处的代码。
在上面的代码中只要我们做到$_G['referer']
不被覆盖即可,首先解析的host
中存在协议则判断是否为http
和https
,不存在则不判断,所以我们可以不传入协议。第二处判断解析的host
是否为$_SERVER['HTTP_HOST']
,如果是则不进入 if 覆盖$_G['referer']
。但是这样的话在实际的 ssrf 跳转场景中$_SERVER['HTTP_HOST']
为空。
所以这个条件无法生效。后面的一个关键判断$domainroot = substr($reurl['host'], strpos($reurl['host'], '.')+1)
;会截取解析的host
第一个.
后面的所有内容,没有.
并且当长度为1
时则返回为空。返回为空时后面的!in_array($domainroot, $_G['setting']['domain']['root']))
这个条件就为 false。也就不会进入 if 判断覆盖$_G['referer']
了。但是这儿存在一个问题,如果我们 host 为a
那么最后通过curl
跳转的时候就往 a 跳转了。不能指定任意地址。此时可以利用parse_url
和curl
的解析差异来绕过这个限制。构造//a#[@1](https://github.com/1 "@1").1.1.1
,那么parse_url
将解析host
为a
,而curl
解析 host 为1.1.1.1
。所以就得到了构造的完整 url。
0x02 漏洞利用
最后的利用流程为:ssrf 访问本地接口进行 URL 跳转====301====>跳转到目标服务器,服务器上使用跳转脚本进行协议转换或者任意路径访问
=====302=====>
通过指定协议如gopher
,访问指定路径/_test…等
首先通过服务器搭建跳转脚本 index.php
本地进行 nc 监听
ssrf 跳转服务器地址
成功将请求转发到本地发送 test 消息
0x03 漏洞修复方法
官方在[补丁提交记录[2]的版本提交中对漏洞进行了修复,修复方式为重写了dfsockopen
中调用的parse_url
为_parse_url
,在该方法中判断了parse_url
是否能够解析出协议,无法解析则退出。
0x04 总结
这个漏洞的成功利用离不开对parse_url
解析特性的了解,parse_url
成功从cutimg
变量中解析出 host,才能调用dfsockopen
方法,在该方法中使用curl
请求拼接了前缀的地址://xx.com
。这将请求本地地址,通过寻找 discuz 的 url 跳转来将本地请求转发出去。而在 url 跳转的利用中使用到了parse_url
和curl
对//a#[@1](https://github.com/1 "@1").1.1.1
的解析差异来完成任意地址访问。最后在访问地址使用 302 跳转来达到使用指定协议请求指定路径或发送数据的目的。
评论