1. 项目概述一次高危漏洞的深度剖析最近在安全圈里Apache Tomcat 爆出的那个远程代码执行漏洞CNVD-2025-04973 / CVE-2025-24813闹得沸沸扬扬。作为一款应用最广泛的 Java Web 应用服务器Tomcat 的任何一个高危漏洞都足以让无数运维和安全工程师心头一紧。这个漏洞的编号一出来我第一时间就去研究了相关的公告和细节发现它并不是一个简单的、可以直接利用的“一键GetShell”漏洞而是一个需要特定配置组合才能触发的“条件型”高危漏洞。这反而更值得警惕因为很多历史教训告诉我们那些看似需要苛刻条件的漏洞往往在真实的、疏于管理的生产环境中恰好满足了所有条件。简单来说这个漏洞的核心攻击路径是攻击者能够通过精心构造的请求向一个开启了写权限的特定目录上传一个恶意序列化文件然后利用 Tomcat 的会话持久化机制在服务器重启或特定条件下触发该文件的加载与反序列化最终实现在服务器上执行任意代码。整个过程听起来有点绕但拆解开来每一步都踩在了 Tomcat 某些不常用但确实存在的默认或可选配置上。对于使用了 Tomcat 的企业无论你是开发、运维还是安全负责人理解这个漏洞的原理、影响范围和修复方案都是当下必须完成的功课。这篇文章我就结合自己的分析把这个漏洞的前因后果、技术细节、排查方法和修复建议给大家捋清楚。2. 漏洞原理与触发条件深度拆解要理解 CVE-2025-24813我们不能把它看作一个孤立的点而是一个由多个“齿轮”咬合才能运转起来的攻击链条。任何一个齿轮缺失攻击都无法成立。这正是它被称为“条件型”漏洞的原因。下面我们来逐一拆解这些必要的“齿轮”。2.1 核心漏洞链条三要素缺一不可根据漏洞公告和分析成功利用此漏洞需要同时满足以下三个关键条件它们环环相扣DefaultServlet 写权限被开启这是攻击的入口。Tomcat 的DefaultServlet负责处理静态资源请求。在默认配置下它只允许读取GET/HEAD操作不允许写入PUT/DELETE等。但是Tomcat 允许通过修改web.xml或应用自身的配置为DefaultServlet添加readonly参数并将其设置为false从而开启写权限。这通常用于一些需要支持 WebDAV 或特殊文件上传功能的应用场景。如果这个开关没打开攻击者就无法通过 HTTP 请求上传文件到服务器链条的第一步就断了。使用 Tomcat 默认的会话持久化机制与路径这是恶意文件的“储藏室”和“触发器”。Tomcat 提供了一种将会话HttpSession数据序列化后保存到磁盘的功能以便在服务器重启后能够恢复用户会话。这个机制默认是关闭的但可以通过配置Manager组件来启用。关键在于这个持久化会话数据的默认存储路径是$CATALINA_BASE/work/Catalina/[hostname]/[appname]/SESSIONS.ser。更致命的是如果应用配置了PersistenceManager且路径可控或者攻击者通过某些方式知晓或猜解了路径他们可能会尝试将恶意文件上传到会话持久化目录或相关路径下。部署的应用中包含可利用的反序列化利用链Gadget Chain这是最终引爆的“火药”。仅仅上传一个序列化文件是不够的这个文件在被反序列化时需要触发目标服务器ClassPath中存在的、可利用的第三方库漏洞例如旧版本的 Commons Collections, Beanutils, Groovy 等。如果应用依赖的库版本较新、没有危险的反序列化Gadget那么即使恶意文件被加载也只会导致一个反序列化异常而不会执行代码。攻击者需要精确知道目标环境中的依赖库情况才能构造出有效的攻击载荷。注意很多初步分析会让人误以为这是一个 Tomcat 本身的反序列化漏洞。实际上Tomcat 在这里更多是提供了一个“文件上传”和“自动加载”的通道真正的代码执行能力来自于应用本身依赖的、不安全的第三方库。这有点类似于“运载工具”和“弹药”的关系Tomcat 提供了运输和发射平台但弹药利用链需要攻击者自己准备并匹配目标。2.2 攻击场景模拟与流程推演让我们在脑海里模拟一下攻击者可能的操作流程这能帮你更直观地理解漏洞的威胁信息收集攻击者首先会探测目标 Tomcat 服务器。他们可能会尝试发送 PUT 请求到已知的静态资源路径或根目录根据响应判断DefaultServlet的写权限是否开启。同时通过扫描或猜测获取目标部署的应用名称Context Path。文件上传确认写权限开启后攻击者会精心构造一个 HTTP PUT 请求将一个包含恶意序列化对象的文件例如evil.ser上传到目标服务器。上传的路径极有可能会瞄准 Tomcat 的会话持久化目录例如/work/Catalina/localhost/myapp/。因为攻击者知道这个目录下的.ser文件有可能被 Tomcat 的会话管理器自动加载。触发执行攻击者等待或主动促使“触发条件”发生。这个条件可能是服务器重启例如运维进行日常维护也可能是会话管理器定期保存或加载会话数据。当 Tomcat 的PersistenceManager尝试从SESSIONS.ser文件或其所在目录加载数据时它会反序列化文件内容。如果上传的evil.ser文件被加载并且其内容利用了服务器ClassPath中存在的漏洞利用链那么反序列化过程就会触发远程代码执行。维持访问代码执行成功后攻击者通常会尝试建立反向 shell、上传 webshell 或执行其他恶意命令从而长期控制服务器。这个攻击流程隐蔽性较强因为文件上传和会话持久化都是服务器可能存在的合法功能。攻击痕迹可能混杂在大量的正常请求和日志中。3. 影响范围与版本排查指南不是所有 Tomcat 版本和所有部署方式都会受到这个漏洞的影响。准确评估自身风险是采取正确行动的第一步。3.1 受影响的 Tomcat 版本根据漏洞公告受影响的 Apache Tomcat 版本包括Apache Tomcat 8.5.x 系列Apache Tomcat 9.x 系列Apache Tomcat 10.x 系列Apache Tomcat 11.x 系列基本上目前所有在维护的主流版本都受到影响。需要注意的是漏洞的根源在于功能设计的组合风险而非某个版本引入的特定代码缺陷因此影响范围很广。3.2 如何判断你的环境是否暴露仅仅版本在受影响范围内并不意味着一定可被攻击。你需要进行以下配置检查检查 DefaultServlet 配置 找到你的应用或 Tomcat 全局的web.xml文件通常位于$CATALINA_BASE/conf/web.xml或应用自身的WEB-INF/web.xml。 搜索DefaultServlet的配置项。关键参数是readonly。如果配置中存在init-paramparam-namereadonly/param-nameparam-valuefalse/param-value/init-param那么写权限已被开启风险等级大幅提升。!-- 危险配置示例 -- servlet servlet-namedefault/servlet-name servlet-classorg.apache.catalina.servlets.DefaultServlet/servlet-class init-param param-namereadonly/param-name param-valuefalse/param-value !-- 此处为 false 表示开启写权限 -- /init-param ... /servlet检查会话持久化配置 检查context.xml全局的$CATALINA_BASE/conf/context.xml或应用单独的META-INF/context.xml或server.xml中关于Manager的配置。 如果配置了PersistentManager或StandardManager并设置了saveOnRestart等属性意味着会话持久化功能被启用。同时需要关注directory参数指定的路径。!-- 示例配置启用持久化会引入风险 -- Manager classNameorg.apache.catalina.session.PersistentManager saveOnRestarttrue directory${catalina.base}/work/sessions /检查应用依赖库 这是一个更复杂的步骤。你需要梳理你的 Web 应用所引入的所有第三方 JAR 包特别是那些历史上曾爆出过反序列化漏洞的库例如Apache Commons Collections (3.x, 4.x)Apache Commons BeanUtilsGroovySpring Framework/AOP (特定版本)JythonMozilla Rhino 可以使用工具如 OWASP Dependency-Check对项目进行依赖扫描找出已知存在漏洞的库版本。3.3 风险自评矩阵你可以根据下面的表格快速评估自己系统的风险等级检查项条件成立风险等级说明Tomcat 版本8.5.x, 9.x, 10.x, 11.x基础风险处于受影响范围是漏洞存在的必要条件。DefaultServlet readonlyfalse是高风险为攻击者打开了上传恶意文件的大门。会话持久化启用是中高风险提供了恶意文件被自动加载的潜在触发机制。存在危险依赖库是高风险提供了最终代码执行所需的“弹药”。三者同时满足是严重风险漏洞极有可能被成功利用需立即处置。实操心得在真实的运维环境中DefaultServlet开启写权限的情况并不少见。我见过一些老旧的后台管理系统或者一些图省事的开发为了方便上传静态文件就直接修改了全局web.xml。而会话持久化功能在需要保持用户登录状态的高可用集群中也可能被使用。最危险的是很多Java应用在迭代多年后其依赖库清单早已无人全面审计里面藏着老版本的漏洞库是常态。因此千万不要抱有侥幸心理认为自己的配置“应该没问题”。必须进行实际检查。4. 漏洞修复方案与加固措施面对这个漏洞修复的总体思路就是“打破攻击链条”。只要让上述三个条件中的任意一个不成立漏洞就无法被利用。以下是分层级的修复建议从紧急缓解到彻底根除。4.1 紧急缓解措施治标如果暂时无法升级或修改应用可以立即实施以下措施快速降低风险关闭 DefaultServlet 写权限最有效 这是切断攻击入口最直接的方法。检查所有web.xml文件确保所有DefaultServlet的readonly参数值均为true或者直接删除该参数因为默认值就是true。!-- 安全配置 -- init-param param-namereadonly/param-name param-valuetrue/param-value /init-param修改后需要重启 Tomcat 服务使配置生效。重启后立即尝试发送一个 PUT 请求进行验证应该收到403 Forbidden或405 Method Not Allowed响应。禁用或严格配置会话持久化 如果没有会话持久化的强需求建议在context.xml中移除PersistentManager相关配置使用默认的StandardManager非持久化。 如果必须使用请确保directory指向一个绝对路径并且该目录的权限严格受限仅允许 Tomcat 进程用户读写同时避免使用可能被 Web 访问到的路径。网络层访问控制 在防火墙或负载均衡设备上对 Tomcat 服务器的管理端口默认8080或应用访问路径设置严格的 IP 白名单策略仅允许可信的运维网络或用户访问。这可以极大缩小攻击面。4.2 根本解决方案治本升级 Tomcat 至安全版本 Apache Tomcat 官方已经发布了修复此漏洞的新版本。这是最推荐的根治方法。请根据你当前使用的分支升级到以下或更高版本Tomcat 8.5.x 用户升级至8.5.101或更高版本Tomcat 9.x 用户升级至9.0.88或更高版本Tomcat 10.x 用户升级至10.1.25或更高版本Tomcat 11.x 用户升级至11.0.0-M20或更高版本升级前务必做好完整的备份和测试因为主要版本之间如9到10可能存在不兼容的变更。清理和升级危险依赖库 对项目中的所有第三方依赖进行安全审计。使用mvn dependency:tree或gradle dependencies命令生成依赖树重点关注那些已知存在反序列化漏洞的库。 将诸如 Commons Collections 3.x 升级到 3.2.2 以上4.x 升级到 4.4 以上Commons BeanUtils 升级到 1.9.4 以上等。可以考虑引入SerialKiller或Apache Commons IO Serialization防护库在反序列化过程中进行过滤。安全加固配置遵循最小权限原则运行 Tomcat 的系统用户如tomcat应仅拥有必要的权限避免使用root用户运行。分离资源目录将用户可上传文件的目录如果业务需要与 Web 应用的部署目录、Tomcat 的工作目录work/完全分离开并设置正确的文件系统权限。定期安全审计将web.xml、server.xml、context.xml等核心配置文件的检查纳入日常安全巡检流程。4.3 修复操作步骤示例假设我们有一个 Tomcat 9.0.86 版本的应用需要实施紧急缓解和升级修复操作流程如下备份备份整个$CATALINA_BASE目录通常是tomcat安装目录下的conf,webapps,work等以及应用的数据库。检查并修改配置# 进入Tomcat配置目录 cd /opt/tomcat/conf # 检查全局web.xml grep -n -A2 -B2 readonly web.xml # 如果发现readonly为false使用vi或sed工具将其改为true sudo vi web.xml # 同样检查所有webapps/*/WEB-INF/web.xml下载并升级Tomcat# 停止当前Tomcat服务 sudo systemctl stop tomcat9 # 下载Tomcat 9.0.88请从官网获取最新链接 wget https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.88/bin/apache-tomcat-9.0.88.tar.gz # 解压到新目录 tar -xzf apache-tomcat-9.0.88.tar.gz -C /opt/ # 将旧版本的配置文件、应用、日志目录复制到新版本注意不要覆盖新版本的bin和lib cp -r /opt/tomcat-old/conf /opt/apache-tomcat-9.0.88/ cp -r /opt/tomcat-old/webapps /opt/apache-tomcat-9.0.88/ cp -r /opt/tomcat-old/logs /opt/apache-tomcat-9.0.88/ # 修改环境变量或服务脚本指向新的Tomcat目录 sudo vi /etc/systemd/system/tomcat9.service # 将ExecStart等路径中的旧目录改为 /opt/apache-tomcat-9.0.88验证与启动# 重新加载systemd配置 sudo systemctl daemon-reload # 启动新版本Tomcat sudo systemctl start tomcat9 # 查看启动日志确认无报错 tail -f /opt/apache-tomcat-9.0.88/logs/catalina.out # 访问应用进行功能验证 curl -I http://localhost:8080/yourapp5. 漏洞检测与验证方法在修复前后进行有效的检测和验证是确保安全措施到位的关键。以下是一些可操作的方法。5.1 手动检测与POC验证警告以下检测方法仅限在你自己拥有完全控制权的测试环境进行严禁对非授权目标进行测试。检测写权限是否开启 使用curl或Burp Suite等工具向目标应用的一个已知静态资源路径或根目录发送一个 PUT 请求。curl -X PUT http://target-server:8080/yourapp/test.txt -d test data如果返回201 Created或204 No Content说明写权限很可能已开启风险极高。如果返回403 Forbidden或405 Method Not Allowed说明写权限未开启此漏洞的入口被阻断。如果返回404 Not Found需要尝试其他路径但这本身不是一个安全风险。模拟漏洞利用仅供理解原理 在满足所有条件的测试环境中漏洞利用过程复杂需要构造特定的序列化载荷。公开的漏洞利用代码POC可能会在漏洞披露后期出现。强烈建议不要直接运行来源不明的 POC而是通过搭建与生产环境一致的测试环境使用安全扫描工具进行检测。5.2 使用自动化安全扫描工具手动检测效率低且不全面。对于企业环境建议使用专业的漏洞扫描工具或 Web 应用扫描器WAS。商业/开源漏洞扫描器Nessus, Qualys, OpenVAS这些综合漏洞扫描器通常会很快将 CVE-2025-24813 纳入其插件库可以对整个 IP 段进行扫描识别存在漏洞的 Tomcat 服务。Nexpose, InsightVM同样提供全面的资产发现和漏洞管理功能。Web 应用专项扫描器Burp Suite Professional可以手动配置扫描或使用其主动扫描引擎。专业的渗透测试人员会使用 Burp 结合自定义插件或扩展来检测此类配置缺陷。OWASP ZAP开源免费可以配置进行主动扫描虽然对复杂逻辑漏洞的检测能力可能稍弱但用于检测DefaultServlet写权限这类基础配置问题是足够的。Acunetix, AppScan商业级的 Web 应用安全扫描器检测深度和广度都很好。配置审计与基线检查工具编写脚本或使用 Ansible/SaltStack 等配置管理工具定期检查所有 Tomcat 服务器的web.xml和context.xml配置文件确保readonlytrue且没有启用不安全的会话管理器。使用CIS Apache Tomcat Benchmark等安全基线标准来加固和检查你的 Tomcat 配置。5.3 日志监控与入侵检测即使修复了漏洞持续的监控也必不可少。在 Tomcat 的access_log和catalina.out日志中关注以下可疑行为access_log频繁出现PUT、DELETE等非GET/POST方法的请求尤其是针对不常见的文件路径如尝试访问/work/...目录下的文件。catalina.out出现大量的反序列化相关异常堆栈例如java.io.InvalidClassException、java.lang.ClassNotFoundException攻击者尝试加载不存在的利用链时可能产生或者来自org.apache.catalina.session包下的异常。系统日志监控服务器上是否在非计划时间出现了新的、可疑的进程或网络连接。可以考虑使用 ELK StackElasticsearch, Logstash, Kibana或 Splunk 搭建集中式日志分析平台设置告警规则对上述可疑日志模式进行实时告警。6. 常见问题与排查技巧实录在实际的应急响应和加固过程中我遇到并总结了一些典型问题和处理技巧。6.1 修复过程中的典型问题问题场景可能原因排查与解决思路修改web.xml后PUT 请求依然成功1. 修改了错误的web.xml文件如只改了全局的但应用自身的覆盖了配置。2. 修改未生效未重启 Tomcat 或浏览器/代理缓存了旧配置。3. 存在其他 Servlet 或 Filter 处理了 PUT 请求。1. 检查所有可能的web.xml全局的conf/web.xml和每个应用WEB-INF/web.xml。2. 重启 Tomcat 服务并使用curl或Burp Repeater禁用缓存重新测试。3. 审查应用的web.xml看是否有其他 Servlet 映射到了/*或/。升级 Tomcat 后应用启动报错1. 版本不兼容特别是从 Tomcat 9 升级到 10/11Jakarta EE 包名从javax.*变为了jakarta.*。2. 复制旧配置时覆盖了新版本的关键库或配置文件。3. 应用依赖的库与新版本 Tomcat 的内置库冲突。1. 查看catalina.out日志中的具体错误信息。如果是包名错误需要对应用代码进行迁移或使用兼容性库。2.切记升级时只复制conf,webapps,logs等目录不要复制bin和lib。3. 检查应用的WEB-INF/lib下是否有与 Tomcatlib目录同名的 JAR 但版本不同尝试移除或统一版本。无法确定应用是否使用了危险依赖项目庞大依赖关系复杂手动梳理困难。1. 使用 Maven 命令mvn dependency:tree -Dincludescommons-collections,commons-beanutils,groovy过滤查看特定依赖。2. 使用OWASP Dependency-Check对项目进行扫描生成包含 CVE 信息的报告。3. 在 IDE如 IntelliJ IDEA中查看项目的依赖图。业务确实需要文件上传功能关闭DefaultServlet写权限后合法的文件上传功能失效。绝对不要重新开启DefaultServlet的写权限正确的做法是1. 为文件上传功能编写专门的 Servlet 或 Controller。2. 在该接口中实施严格的安全控制文件类型白名单校验、病毒扫描、重命名、存储到 Web 根目录之外的特定路径。6.2 安全加固的进阶技巧使用安全管理器Security Manager 启用并正确配置 Java 安全管理器可以为 Tomcat 提供一个更细粒度的沙箱环境。即使攻击者上传了恶意文件或触发了某些代码执行安全管理器也可以限制其操作如文件读写、网络访问、执行命令等。配置较为复杂但能极大提升安全性。# 在 catalina.sh 中启动Tomcat时加入安全策略 export CATALINA_OPTS$CATALINA_OPTS -Djava.security.manager -Djava.security.policy$CATALINA_BASE/conf/catalina.policy然后需要精心编写catalina.policy文件为不同的代码源授予最小必要权限。对序列化数据实施过滤 如果应用确实需要使用 Java 原生序列化例如 RMI 调用可以考虑引入防护库。例如使用SerialKiller库它允许你定义一个白名单或黑名单在反序列化过程中过滤掉危险的类。// 示例使用SerialKiller进行反序列化 ObjectInputFilter filter new SerialKiller(new ClassWhiteList(Arrays.asList(safe.package.*))); // ... 在反序列化时应用此filter定期进行渗透测试与代码审计 配置加固和漏洞修复是被动防御。主动邀请专业的安全团队或使用自动化工具对你的 Web 应用和 Tomcat 服务器进行定期的渗透测试和代码审计可以发现更深层次的逻辑漏洞和配置问题。将安全测试纳入 DevOps 流程DevSecOps实现安全左移。6.3 一个真实的排查案例我曾遇到一个案例客户报警说服务器疑似被入侵发现catalina.out日志中有大量奇怪的类加载错误。登录服务器检查发现DefaultServlet的readonly确实是true版本也是较新的 9.0.80。一时陷入僵局。后来仔细检查access_log发现攻击者并没有直接使用 PUT而是先发送了一个POST请求到某个应用接口该接口存在文件上传功能但未做任何过滤允许上传.ser文件。攻击者将恶意文件上传到了应用指定的一个临时目录。接着攻击者又发送了另一个请求触发了应用的某个功能该功能会读取指定目录下的文件并进行反序列化操作。这个案例给我的教训是CVE-2025-24813 的核心风险模式是“写文件反序列化”这个模式可能以多种形式存在。它不一定严格按照 Tomcat 默认的DefaultServlet和会话持久化路径来走。任何允许用户控制文件内容并最终导致该文件被 Java 反序列化机制加载的地方都可能构成类似的漏洞。因此在排查时思维不能局限于公告里提到的特定配置而要抓住“不受控的文件写入”和“不安全的反序列化”这两个本质风险点对全网应用进行排查。