Jenkins 任意文件读取漏洞复现与分析 - 【CVE-2018-1999002】
SECURITY-914 / CVE-2018-1999002
|
|
漏洞影响版本:
漏洞复现
测试环境: win平台
通过查找commit记录可知需要将其检出至 29ca81dd59c255ad633f1bd86cf1be40a5f02c64之前
检查core/pom.xml
的第41行,确保版本为1.250
然后命令行下编译war包
在jenkins\war\target
目录下获得编译好的jenkins.war
,同目录下启动:
在管理员登陆(有cookie)的情况下
在没有登陆(未授权,cookie清空)的情况下,只有当管理员开启了allow anonymous read access
的时候,才能实现任意文件读取,否则仍需登陆。
开启:
未开启:
而在linux下利用条件会更加苛刻,见后文。
漏洞分析
以payload为例,请求的url为/plugin/credentials/.ini
。而在hudson/Plugin.java:227
doDynamic
函数用于处理类似/plugin/xx
的请求,serveLocalizedFile
在stapler-1.250-sources.jar!/org/kohsuke/stapler/ResponseImpl.java
第209行左右:
先看最里面的request.getLocale()
,然后再来分析stapler.selectResourceByLocale()
。
跟入request.getLocale()
,至jetty-server-9.2.15.v20160210-sources.jar!/org/eclipse/jetty/server/Request.java:692
:
这里用于处理HTTP请求中的Accept-Language
头部。比如zh-cn
,则会根据-
的位置被分为两部分,language
为zh
,country
为cn
,然后返回Locale(language,country)
对象。倘若不存在-
,则country
为空,language
即对应我们的payload:../../../../../../../../../../../../windows/win
,则此时返回一个Locale(language,"")
返回后即进入selectResourceByLocale(URL url, Locale locale)
,这里的locale
参数即上一步返回的locale对象。
urlLocaleSelector
对象的声明见stapler-1.250-sources.jar!/org/kohsuke/stapler/Stapler.java:390
:
在stapler-1.250-sources.jar!/org/kohsuke/stapler/Stapler.java:324
实现了LocaleDrivenResourceSelector
类的open
方法:
先看看开头的注释,这段代码本意是想根据对应的语言(Accept-Language)来返回不同的文件,比如在ja
的条件下请求foo.html
,则相当于去请求foo_ja.html
,这个过程会先把foo.html
分成两部分:文件名foo
和扩展名.html
,然后根据具体的语言/国家来组合成最终的文件名。
结合payload来看,我们请求的url为/plugin/credentials/.ini
,则base
为空,扩展名(ext变量)即为.ini
,然后通过一系列的尝试openURL,在此例中即最后一个情形con = openURL(map(base+'_'+ locale.getLanguage()+ext));
,会去请求_../../../../../../../../../../../../windows/win.ini
,尽管目录_..
并不存在,但在win下可以直接通过路径穿越来绕过。但在linux,则需要一个带有_
的目录来想办法绕过。
补丁分析
Jenkins官方修改了pom.xml,同时增加一个测试用例文件。真正的补丁在stapler
这个web框架中,见commit记录: https://github.com/stapler/stapler/commit/8e9679b08c36a2f0cf2a81855d5e04e2ed2ac2b3 :
对从locale
取出的language
,country
,variant
均做了正则的校验,只允许字母数字以及特定格式的出现。在接下来的openUrl中,根据三种变量的不同检查情况来调用不同的请求,从而防止了路径穿越漏洞造成的任意文件读取漏洞。