jetty文件下载漏洞分析

前言

​ 前段时间在分析Jetty漏洞时无意捡了个CVE,下面是当时分析该漏洞并挖掘到CVE的记录。

CVE-2021-28164

​ 该漏洞影响9.4.37.v202102199.4.38.v20210224版本,攻击者可通过/%2e/WEB-INF/绕过WEB-INF下文件的访问限制,读取WEB-INF下的文件内容。目前该漏洞我仅在9.4.38.v20210224复现成功。

漏洞复现

​ 首先使用IDEA创建一个maven的web项目,修改POM文件添加Jetty依赖,这个依赖使用阿里云的源是找不到的,可以修改为maven的官方源,并为maven设置socks代理来解决下载依赖的问题,下面是我的POM文件配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>
<name>jetty_CVE-2021-28169</name>
<groupId>org.example</groupId>
<artifactId>jetty_CVE-2021-28169</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.38.v20210224</version>
<configuration>
<httpConnector>
<port>8082</port>
</httpConnector>
<webApp>
<contextPath>/</contextPath>
</webApp>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
</dependencies>
</project>

​ 加载依赖后,通过mvn jetty:run命令运行jetty,访问/%2e/WEB-INF/web.xml读取xml文件,至此漏洞复现成功。

image-20210611115919722

漏洞分析

​ 根据Jetty官网的描述,这个漏洞是由于servlet和url解析产生了不一致导致的。所以当使用/%2e进行绕过时,一定会进入到servlet,由于在Jetty中所有HTTPservlet的请求都会过javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletRespons),所以可以在该函数打断点观察程序后续的执行逻辑。

image-20210611162904299 接下来会进入到org.eclipse.jetty.servlet.DefaultServlet#doGet,在该方法中又会调用org.eclipse.jetty.server.ResourceService#doGet方法。

image-20210611162957047

​ 在org.eclipse.jetty.server.ResourceService#doGet中会根据传入的路径获取文件内容。

image-20210611173821872

​ 当获取的内容为目录时,则列出目录结构,所以也可以通过/%2e/WEB-INF/读取WEB-INF下的目录image-20210617103728909

​ 当正常读取到文件内容时,则将读取到的文件内容发送到客户端。

image-20210617103814228

​ 通过上面的分析,之所以能进行文件读取操作,是因为DefaultServlet的处理导致的,通过查阅文档,DefaultServlet映射路径为/,主要作用为上下文提供对静态内容的处理。所以如果程序中将其他的servlet mapping设置为/,访问 /%2e/WEB-INF/web.xml将不会触发读取漏洞,因为请求不会交给DefaultServlet处理。

那么为什么直接访问/./WEB-INF/web.xml不会触发漏洞呢?

​ 在org.eclipse.jetty.server.Request#setMetaData中会对请求的URI进行解析,在这个过程中会获取URL解码后的url并通过setPathInfo进行设置。image-20210617113525349

​ 在org.eclipse.jetty.server.handler.ContextHandler#isProtectedTarget中会判断请求的路径是否以/WEB-INF开头,由于url解码后的url并不满足条件,因此绕过了此处黑名单的检测,才能顺利的执行到DefaultServlet的方法,否则会直接返回。image-20210617113724406

image-20210617114153492

为什么通过/./WEB-INF/web.xml可以顺利的请求到/WEB-INF/web.xml文件呢?

​ 这个取决于org.eclipse.jetty.server.handler.ContextHandler#getResource方法,在该方法中通过canonicalPath对路径进行处理,所有的/./都会被转换为/

image-20210617114648546

除了%2e编码绕过,能否通过其他方式绕过?

​ 在获取org.eclipse.jetty.http.HttpURI#getDecodedPath获取解码参数时,主要是通过获取_decodedPath属性的值来实现的,而这个属性在org.eclipse.jetty.http.HttpURI#parse(org.eclipse.jetty.http.HttpURI.State, java.lang.String, int, int)方法中别赋值,首先通过canonicalPath/.//../形式的url进行转换,再通过decodePath进行解码。

image-20210617140914230

​ 在decodePath中还会将%u002e,%2e;;;转换为.,因此也可以使用这种方式绕过。

image-20210617141322126

​ 我们知道,这个漏洞之所以使用url编码,是为了绕过canonicalPath/./的转换,但经过我们上面的分析也可以通过/.;/WEB-INF/web.xml来绕过,那么为什么不能使用这种方式绕过呢?

​ 首先确实可以通过/.;/来绕过canonicalPath方法,但是实际使用这种方式会爆400,这是为什么呢?

image-20210617143621772image-20210617143917629

​ 根据报错定位到org.eclipse.jetty.server.Request#setMetaData,isAmbiguous的返回结果是由_ambiguous决定的,所以要找到哪里给_ambiguous赋值。image-20210617144314517

​ 在org.eclipse.jetty.http.HttpURI#checkSegment中,当要处理的字符的前一个字符为.或者..时,会返回false,并给_ambiguous赋值。

image-20210617145147766

image-20210617145222043

​ 注意代码__ambiguousSegments.put("%2e", Boolean.TRUE);,这里如果改为false,那么就无法使用/%2e/WEB-INF/web.xml来绕过。

除了读取xml文件,能否读取WEB-INF下的class或者jsp文件?

​ 当读取jsp文件时,并不会得到jsp文件的内容,因为HTTPServlet会将请求交给JettyJspServlet,会去解析jsp的内容,但使用这种方式也可以让我们直接去执行WEB-INF下的jsp文件。

image-20210617152001682

​ 至于class或者jar文件,可以直接读取内容,所以利用该漏洞读取源码。

image-20210617153253099

漏洞修复

​ 最后看下官方是如何修复这个漏洞,有无绕过的可能。

image-20210617154935767

​ 只有当ambiguous为true时才会执行上面的代码,但如果我们用%u002e就可以绕过该限制。

image-20210617163502809

联系jetty获取CVE

image-20210621103311443

总结

​ 通过对这个漏洞的分析,一方面觉得花费时间去跟进漏洞是值得的,另外身为一个做漏洞挖掘的,深入分析漏洞的原理是必要的,这也是能挖掘到新漏洞的前提。最后总结下这个漏洞的利用

  • 目录遍历,枚举/WEB-INF下的目录结构

image-20210621103858903

  • 源码读取,除了可以读取配置文件,也可以读取class文件

image-20210621103934823

  • 执行/WEB-INF下的JSP文件

image-20210621104048112