Apache Tomcat Partial PUT漏洞与文件会话持久化漏洞分析
CVE-2025-24813: Partial PUT漏洞
漏洞描述
Apache Tomcat的Partial PUT原始实现使用基于用户提供的文件名和路径生成的临时文件,当处理不完整的PUT请求时,会将文件路径中的分隔符/替换为.。当应用使用了Tomcat的文件会话持久化功能并使用了默认的会话存储位置时,攻击者可以通过partial PUT请求将包含恶意序列化数据的文件上传至会话目录,并完成反序列化。
影响版本
- Apache Tomcat 1.0.0-M1至11.0.1
- Apache Tomcat 10.1.0-M1至10.1.33
- Apache Tomcat 9.0.0.M1至9.0.97
利用条件
- DefaultServlet启用了写入功能(ReadOnly=False)
- 支持Partial PUT请求
- 应用程序开启了Tomcat基于文件的会话持久化功能,并采用默认的存储位置
- 应用程序存在能被用于反序列化的库
漏洞复现步骤
- 在
context.xml中开启Session的持久化存储:
<Manager className="org.apache.catalina.session.PersistentManager">
<Store className="org.apache.catalina.session.FileStore" directory="session"/>
</Manager>
- 开启DefaultServlet的默认写入功能:
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
</servlet>
- 如果Tomcat本地依赖中存在Jackson链,可以尝试上传反序列化文件
漏洞分析
-
在DefaultServlet处理
doPut请求时,当readOnly为False且开启parseContentRange分块传输字段后,会进入executePartialPut方法 -
在
executePartialPut中:- 从上下文获取临时目录对象
- 将资源路径中的
/替换为. - 以读写模式打开新创建的临时文件
- 从请求输入流中读取数据(每次4096字节)
- 将数据写入临时文件
-
临时目录默认位置:
${CATALINA_BASE}/work/Catalina/${HOST_NAME}/${CONTEXT_PATH} -
由于开启了Session持久化存储,session文件的默认存储点正好位于上述临时文件夹
-
当加载session时,会从临时文件夹中查找session命名的文件,通过流读取文件内容,最终通过
readObjectData对内容进行反序列化,导致RCE
CVE-2024-50379: 文件大小写条件竞争漏洞
漏洞描述
由于MacOS和Windows平台的Tomcat在加载JSP文件时使用File.exists()检查文件是否存在,而平台不区分大小写,导致可以通过条件竞争方式加载xxx.Jsp文件并成功写入DefaultServlet中,可能导致服务器权限被接管。
影响版本
- 1.0.0-M1 <= Apache Tomcat <= 11.0.1
- 10.1.0-M1 <= Apache Tomcat <= 10.1.33
- 9.0.0.M1 <= Apache Tomcat <= 9.0.97
利用条件
DefaultServlet启用了默认HTTP PUT写入功能,或存在任意文件上传漏洞。
漏洞分析
-
Tomcat通过
getResource方法安全访问Web应用资源:- 首先验证路径获取资源
- 资源不存在则返回空资源对象
DirResourceSet从WebResourceSet继承实现接口
-
在
file方法中:- 对资源文件进行安全检查(阻止符号链接,检查文件合法性)
- 通过
normalize统一平台路径分隔符
-
关键问题:
- 访问
test.jsp时,file.getCanonicalPath()得到test.Jsp getCanonicalPath是区分大小写的,但底层FindFirstFileWAPI不区分大小写absPath获取到的是test.jsp,与canPath(test.Jsp)比较时因大小写差异返回空对象
- 访问
-
当文件夹中不存在
test.Jsp时,访问test.jsp:canPath和absPath都获取到test.jsp- 文件判断通过,返回文件
-
利用方式:
- 当
readonly=False时,并发执行PUT和GET方法 - 由于没有锁机制,可能导致
f.exists通过资源检查 - 通过并发PUT
xxx.Jsp和GETxxx.jsp,当PUT请求文件落地时,GET可能读取xxx.Jsp并交给JspServlet处理
- 当
-
修复方式:增加了锁机制,在write操作未完成时阻塞read操作
总结对比
-
CVE-2025-24813:
- Partial PUT处理不完整PUT请求时替换文件路径分隔符
- 利用session持久化机制,PUT上传文件到临时文件夹
- 通过session完成反序列化
-
CVE-2024-50379:
- MacOS/Windows平台因
File.exists()检查及大小写忽略问题 - 通过条件竞争加载
xxx.Jsp文件写入DefaultServlet - GET
xxx.jsp可能加载到xxx.Jsp并由JspServlet处理
- MacOS/Windows平台因
-
CVE-2017-12615:
- 构造特殊后缀名绕过检测
- 让DefaultServlet处理请求上传JSP文件
- 导致Webshell上传
参考
- https://mp.weixin.qq.com/s/ewvMUC7CFNMmwexVLVOAzA