漏洞概述
由于Tomcat
在处理AJP
请求时,未对请求做任何验证,通过设置AJP
连接器封装的request
对象的属性, 导致产生任意文件读取漏洞和代码执行漏洞
CVE-2020-1938 又名GhostCat, 之前引起了一场风雨,由e长亭科技安全研究员发现的存在于Tomcat中的安全漏洞,由于Tomcat AJP协议设计上存在缺陷,攻击者通过 Tomcat AJP Connector 可以读取或包含 Tomcat 上所有 webapp 目录下的任意文件,例如可以读取 webapp 配置文件或源代码。此外在目标应用有文件上传功能的情况下,配合文件包含的利用还可以达到远程代码执行的危害。
影响范围:
Apache Tomcat 9.x < 9.0.31
Apache Tomcat 8.x < 8.5.51
Apache Tomcat 7.x < 7.0.100
Apache Tomcat 6.x
本次漏洞与三个include
属性有关
- javax.servlet.include.request_uri
- javax.servlet.include.path_info
- javax.servlet.include.servlet_path
任意文件读取
任意文件读取问题出现在org.apache.catalina.servlets.DefaultServlet
这个Servlet
构造一个AJP请求,请求会走默认的DefaultServlet并交给DefaultServlet
的doGet
方法处理。doGet
会调用ServeResource
方法获取资源文件,调用getRelativePath
方法获取要读取资源的相对路径,通过getResources
方法就可以获取到了对应路径的Web资源对象。
然后再通过控制ajp控制的上述三个include属性来读取文件,通过操控上述三个属性从而可以读取到/WEB-INF下面的所有敏感文件,不限于class、xml、jar等文件。
任意代码执行
任意代码执行问题出现在org.apache.jasper.servlet.JspServlet
这个servlet
。
构造一个如下的AJP请求,让Tomcat执行/docs/test.jsp
,但实际上它会将code.txt当成jsp来解析执行。
1 | RequestUri:/docs/test.jsp |
code.txt内容如下:
1 | <% |
发送AJP请求,请求的是/docs/test.jsp
这个jsp,但是由于那三个include属性可控,可以将test.jsp
对应的服务器脚本文件改为code.txt
,导致tomcat把我们的code.txt当jsp文件编译运行,导致代码执行。
Tomcat AJP Connector以及AJP协议
Tomcat Connector 是 Tomcat 与外部连接的通道,它使得 Catalina 能够接收来自外部的请求,传递给对应的 Web 应用程序处理,并返回请求的响应结果。
默认情况下,Tomcat 配置了两个 Connector,它们分别是 HTTP Connector
和 AJP Connector
:
1 | HTTP Connector:用于处理 HTTP 协议的请求(HTTP/1.1),默认监听地址为 0.0.0.0:8080 |
HTTP Connector 就是用来提供我们经常用到的 HTTP Web 服务。而 AJP Connector,它使用的是 AJP 协议(Apache Jserv Protocol),AJP 协议可以理解为 HTTP 协议的二进制性能优化版本,它能降低 HTTP 请求的处理成本,因此主要在需要集群、反向代理的场景被使用。
AJP是Apache Tomcat web服务器用来与servlet容器通信的一个二进制协议。主要用于集群或逆向代理场景,其中web服务器与应用服务器或servelet容器进行通信。
简单来说,就是HTTP Connector暴露给客户端了,AJP是webserver (如Apache HTTPD)和Apache Tomcat服务器之间内部使用的,如下图所示。AJP在Apache HTTP服务器中是以模块的形式实现的,表示为mod_jk或mod_proxy_ajp。AJP本身并不会暴露到外部,这也是下一部分要讨论的RCE场景的先决条件之一。
漏洞修复
1.将Tomcat立即升级到9.0.31、8.5.51或7.0.100版本进行修复。
2.禁用AJP协议
具体方法:编辑 /conf/server.xml,找到如下行:
1
<Connector port="8009"protocol="AJP/1.3" redirectPort="8443" />
3.配置secret来设置AJP协议的认证凭证。
例如(注意必须将YOUR_TOMCAT_AJP_SECRET更改为一个安全性高、无法被轻易猜解的值):
1
<Connector port="8009"protocol="AJP/1.3" redirectPort="8443"address="YOUR_TOMCAT_IP_ADDRESS" secret="YOUR_TOMCAT_AJP_SECRET"/>