Tomcat Ghostcat - AJP协议文件读取/文件包含漏洞(CVE-2020-1938 / CNVD-2020-10487)
字数 2110 2025-08-25 22:58:35

Tomcat Ghostcat漏洞(CVE-2020-1938/CNVD-2020-10487)深入分析与教学文档

0x00 漏洞概述

Tomcat Ghostcat漏洞是Apache Tomcat服务器中AJP协议实现的一个高危漏洞,包含文件读取和文件包含两种攻击方式,可能导致敏感信息泄露和远程代码执行(RCE)。该漏洞编号为CVE-2020-1938和CNVD-2020-10487。

0x01 环境搭建

所需工具与环境

  • Tomcat 8.5.46源码:http://archive.apache.org/dist/tomcat/tomcat-8/v8.5.46/src/apache-tomcat-8.5.46-src.zip
  • IDEA开发环境

搭建步骤

  1. 下载并解压Tomcat源码
  2. 在IDEA中导入项目
  3. 解决500错误:
    • 找到org.apache.catalina.startup.ContextConfig
    • 增加代码:context.addServletContainerInitializer(new JasperInitializer(), null);
  4. 启动Tomcat后,默认会开放8009(AJP)和8080(HTTP)端口

0x02 基础知识

1. Tomcat Connector(连接器)

  • 功能:负责接收客户端连接和请求处理加工
  • 类比:如同城堡的城门,提供进出通道
  • 默认配置
    • HTTP Connector:监听8080端口
    • AJP Connector:监听8009端口

2. Servlet(服务程序)

  • 定义:处理网络请求的规范
  • 生命周期:实例化、初始化、调用、销毁受控于Tomcat容器
  • 默认Servlet
    • DefaultServlet:处理静态资源请求
    • JspServlet:处理JSP页面请求

3. Tomcat请求处理流程

  1. Connector接收请求并封装为Request对象
  2. Engine匹配虚拟主机Host
  3. Host匹配Context
  4. Context匹配Servlet
  5. Wrapper管理Servlet执行
  6. 返回响应

0x03 漏洞分析

漏洞触发条件

  • 通过AJP协议(8009端口)发送特制请求
  • 两种攻击方式:
    • 文件读取(走DefaultServlet)
    • 文件包含(走JspServlet)

1. 文件读取漏洞

关键参数

req_uri = '/asdf'  # 请求URL
javax.servlet.include.request_uri = '/'  # AJP属性
javax.servlet.include.path_info = 'WEB-INF/web.xml'  # AJP属性
javax.servlet.include.servlet_path = '/'  # AJP属性

漏洞流程

  1. AjpProcessor处理

    • service()prepareRequest()
    • 解析请求并将属性设置到request对象
  2. DefaultServlet处理

    • service()doGet()serveResource()
    • getRelativePath()拼接路径:'/WEB-INF/web.xml'
    • getResource()validate()normalize()进行路径校验
  3. 路径限制

    • normalize()方法会检查/../,因此只能读取webapps目录下的文件
  4. 文件读取

    • 通过ServletOutputStream.write()返回文件内容
  5. 目录控制

    • 修改req_uri可读取webapps下不同目录的文件
    • /manager/asdf可读取manager应用下的文件

漏洞复现

修改POC中的请求URL为/manager/asdf,可读取webapps/manager/status.xsd

2. 文件包含漏洞(RCE)

关键参数

req_uri = '/manager/ddd.jsp'  # 必须以".jsp"结尾
javax.servlet.include.request_uri = '/'
javax.servlet.include.path_info = 'test.txt'  # 包含的文件
javax.servlet.include.servlet_path = '/'

漏洞流程

  1. JspServlet处理

    • service()serviceJspFile()
    • servlet_pathpath_info拼接为jspUri
  2. JSP处理流程

    • 将包含的文件(test.txt)当作JSP处理
    • 编译为Servlet源代码(.java)
    • 编译为Servlet类(.class)
    • 执行Servlet
  3. RCE条件

    • 需要在webapps目录下上传恶意文件
    • 通过文件包含漏洞执行该文件

漏洞复现

  1. webapps/manager下创建test.txt
    <% Runtime.getRuntime().exec("calc.exe");%>
    
  2. 修改POC请求URL为/manager/ddd.jsp
  3. 执行test.txt中的代码

0x04 漏洞修复

官方在Tomcat 9.0.31版本中修复了该漏洞,主要措施包括:

  1. 限制AJP请求中的特殊属性
  2. 加强路径校验
  3. 默认禁用AJP Connector

0x05 防御建议

  1. 升级Tomcat到安全版本
  2. 如不使用AJP协议,关闭8009端口
  3. conf/server.xml中注释或删除AJP Connector配置
  4. 加强文件上传限制
  5. 设置适当的文件权限

附录:参考资源

  1. 官方漏洞公告
  2. POC代码:https://github.com/YDHCUI/CNVD-2020-10487-Tomcat-Ajp-lfi
  3. 趋势科技分析报告:Busting Ghostcat: An Analysis of the Apache Tomcat Vulnerability
Tomcat Ghostcat漏洞(CVE-2020-1938/CNVD-2020-10487)深入分析与教学文档 0x00 漏洞概述 Tomcat Ghostcat漏洞是Apache Tomcat服务器中AJP协议实现的一个高危漏洞,包含文件读取和文件包含两种攻击方式,可能导致敏感信息泄露和远程代码执行(RCE)。该漏洞编号为CVE-2020-1938和CNVD-2020-10487。 0x01 环境搭建 所需工具与环境 Tomcat 8.5.46源码:http://archive.apache.org/dist/tomcat/tomcat-8/v8.5.46/src/apache-tomcat-8.5.46-src.zip IDEA开发环境 搭建步骤 下载并解压Tomcat源码 在IDEA中导入项目 解决500错误: 找到 org.apache.catalina.startup.ContextConfig 增加代码: context.addServletContainerInitializer(new JasperInitializer(), null); 启动Tomcat后,默认会开放8009(AJP)和8080(HTTP)端口 0x02 基础知识 1. Tomcat Connector(连接器) 功能 :负责接收客户端连接和请求处理加工 类比 :如同城堡的城门,提供进出通道 默认配置 : HTTP Connector:监听8080端口 AJP Connector:监听8009端口 2. Servlet(服务程序) 定义 :处理网络请求的规范 生命周期 :实例化、初始化、调用、销毁受控于Tomcat容器 默认Servlet : DefaultServlet :处理静态资源请求 JspServlet :处理JSP页面请求 3. Tomcat请求处理流程 Connector接收请求并封装为Request对象 Engine匹配虚拟主机Host Host匹配Context Context匹配Servlet Wrapper管理Servlet执行 返回响应 0x03 漏洞分析 漏洞触发条件 通过AJP协议(8009端口)发送特制请求 两种攻击方式: 文件读取(走DefaultServlet) 文件包含(走JspServlet) 1. 文件读取漏洞 关键参数 漏洞流程 AjpProcessor处理 : service() → prepareRequest() 解析请求并将属性设置到request对象 DefaultServlet处理 : service() → doGet() → serveResource() getRelativePath() 拼接路径: '/WEB-INF/web.xml' getResource() → validate() → normalize() 进行路径校验 路径限制 : normalize() 方法会检查 /../ ,因此只能读取webapps目录下的文件 文件读取 : 通过 ServletOutputStream.write() 返回文件内容 目录控制 : 修改 req_uri 可读取webapps下不同目录的文件 如 /manager/asdf 可读取manager应用下的文件 漏洞复现 修改POC中的请求URL为 /manager/asdf ,可读取 webapps/manager/status.xsd 2. 文件包含漏洞(RCE) 关键参数 漏洞流程 JspServlet处理 : service() → serviceJspFile() 将 servlet_path 和 path_info 拼接为jspUri JSP处理流程 : 将包含的文件(test.txt)当作JSP处理 编译为Servlet源代码(.java) 编译为Servlet类(.class) 执行Servlet RCE条件 : 需要在webapps目录下上传恶意文件 通过文件包含漏洞执行该文件 漏洞复现 在 webapps/manager 下创建 test.txt : 修改POC请求URL为 /manager/ddd.jsp 执行 test.txt 中的代码 0x04 漏洞修复 官方在Tomcat 9.0.31版本中修复了该漏洞,主要措施包括: 限制AJP请求中的特殊属性 加强路径校验 默认禁用AJP Connector 0x05 防御建议 升级Tomcat到安全版本 如不使用AJP协议,关闭8009端口 在 conf/server.xml 中注释或删除AJP Connector配置 加强文件上传限制 设置适当的文件权限 附录:参考资源 官方漏洞公告 POC代码:https://github.com/YDHCUI/CNVD-2020-10487-Tomcat-Ajp-lfi 趋势科技分析报告:Busting Ghostcat: An Analysis of the Apache Tomcat Vulnerability