漏洞背景
前一段时间Atlassian的bug跟踪里公开了一个Jira未授权SSRF漏洞,看一下官方的描述:
影响范围
< 8.4.0
官方说在7.6版本中引入,在8.4.0中修复。但是我经过测试发现至少6.4.14版本也受此漏洞影响。目前多数Jira是在8.4.0版本以下的。
漏洞分析
两个关键信息点:
- 漏洞点在/plugins/servlet/gadgets/makeRequest
- 原因在于JiraWhitelist这个类的逻辑缺陷
首先上直接去访问这个url,然而告诉我404:
有点绝望,都404了,还看啥!
然后开始按照以往Jira/Confluence的漏洞搜索方法,
|
然而通过这一点并没有搜出来直接到漏洞点的地方。
换另一条思路,搜索:JiraWhitelist
,
找到了这个类是在atlassian-jira/WEB-INF/classes目录下,于是在IDEA中直接将这个目录加到Library中(否则调试无法进入),然后在其可疑方法allows下断点:
发起一个/plugins/servlet/gadgets/makeRequest
的请求,但是这个时候没能直接触发到断点。后来找到了一个跟这个比较像的url:/plugins/servlet/gadgets/dashboard-diagnostics
深入跟进了一下,发现原来是所有/plugins/servlet
开头的url会交给某一个类处理,而这是在web.xml中配置的:
这里url中的/plugins/servlet
匹配到了servlet-module-container-servlet对应的servlet为:com.atlassian.jira.plugin.servlet.ServletModuleContainerServlet
。
然后后面通过request.getPathInfo()
来获取url后面的内容。参考:https://blog.csdn.net/turkeyzhou/article/details/3270289
获取到之后,去一个Map里查找:
这个pathInfo对应的Servlet descriptor
然后根据这个descriptor找到具体的Servlet类:
这里显示已经找到了:
这个Servlet为com.atlassian.gadgets.shindig.servlet.XsrfMakeRequestServlet
。至此终于定位到了处理具体请求的地方。
可以看到这里对请求中的请求头X-Atlassian-Token: no-check
做了判断,如果请求中没有这个请求头,则直接响应404了。
这个请求头是官方提供的一种绕过Jira自身CSRF防御的方式,用于告诉Jira不对此请求进行CSRF防御,方便在自动化脚本中使用。具体介绍可以参考:
https://developer.atlassian.com/server/jira/platform/form-token-handling/
到这里就解释了为什么直接访问这个url会响应404了。
带上这个请求头,继续调试。
跟进其父类即org.apache.shindig.gadgets.servlet.MakeRequestServlet
的doGet
方法。由于这个包我没有在Jira提供的jar包中找到,最后去这里:
https://repo1.maven.org/maven2/org/apache/shindig/shindig-gadgets/2.5.2/shindig-gadgets-2.5.2.jar
找了一个jar包作为Library供IDEA调试。
最后跟进到了atlassian-jira/WEB-INF/classes/com/atlassian/jira/dashboard/JiraWhitelist#allows
方法中,对请求中的url参数进行判断。如果请求中的url满足以Jira服务的canonicalBaseUrl开头(比如我的Jira是http://cqq.com:8091),
若满足,则认为这个url符合白名单的规则:
这里应该就是漏洞描述中atlassian-jira/WEB-INF/classes/com/atlassian/jira/dashboard/JiraWhitelist#allows
方法的逻辑缺陷了。
符合白名单的规则就接着使用atlassian-jira-6.4.14-standalone/atlassian-jira/WEB-INF/lib/httpclient-4.3.6.jar!/org/apache/http/client/utils/URIUtils
这个工具类将url中的协议名、Host名、端口等提取出来
通过跟踪代码,发现它只判断了url是否以 <jira服务的协议://ip:port>
开头,所以这个poc中能进行SSRF的协议只能是HTTP(s)。
最终的结果:
漏洞修复
在8.4.0版本中,使用这里使用了java.net.URI#getHost,getPort
等方法获取主机名和端口号,与Jira服务的协议、主机名、端口进行逐个对比。若不符合,返回False。
PoC
|
https://github.com/shadowsock5/Poc/blob/master/Jira/CVE-2019-8451.py
参考
- https://nvd.nist.gov/vuln/detail/CVE-2019-8451
- https://jira.atlassian.com/browse/JRASERVER-69793
- https://blog.csdn.net/caiqiiqi/article/details/101671094