## 【漏洞分析】Jira未授权SSRF漏洞(CVE-2019-8451)
原创: 奇安信 CERT [奇安信 CERT](javascript:void(0);) *昨天*
本文作者:77 @奇安信A-TEAM
漏洞背景
前一段时间Atlassian的bug跟踪里公开了一个Jira未授权SSRF漏洞。看一下官方的描述:
Jira的/plugins/servlet/gadgets/makeRequest资源存在SSRF漏洞,原因在于JiraWhitelist这个类的逻辑缺陷,成功利用此漏洞的远程攻击者可以以Jira服务端的身份访问内网资源。经分析,此漏洞无需任何凭据即可触发。

### 影响范围
< 8.4.0
官方说在7.6版本中引入,在8.4.0中修复。但是我经过测试发现至少6.4.14版本也受此漏洞影响。而目前多数Jira是在8.4.0版本以下的。
修复建议
升级到8.4.0及以上版本。
### 漏洞分析
两个关键信息点:
- 漏洞点在/plugins/servlet/gadgets/makeRequest
- 原因在于JiraWhitelist这个类的逻辑缺陷
首先上直接去访问这个url,然而告诉我404:

有点绝望,都404了,还看啥!然后开始按照以往Jira/Confluence的漏洞搜索方法,
```
grep -rn "makeRequest" *
```

然而通过这一点并没有搜出来直接到漏洞点的地方。换另一条思路,搜索:`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`。
至此终于定位到了处理具体请求的地方。
跟进这个类atlassian-jira/WEB-INF/atlassian-bundled-plugins/atlassian-gadgets-opensocial-plugin-4.3.9.jar!/com/atlassian/gadgets/shindig/servlet/XsrfMakeRequestServlet的doGet方法。
可以看到这里对请求中的请求头`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。 
### Demo

### 参考
- https://nvd.nist.gov/vuln/detail/CVE-2019-8451
- https://jira.atlassian.com/browse/JRASERVER-69793
暂无评论