Apache Tomcat漏洞分析及复现(CVE-2020-1938)

这两天Apache Tomcat爆出来的新漏洞,CVE-2020-1938,可远程读取web服务器下的文件,危害较大。

影响版本

  • Tomcat 6.*
  • Tomcat 7.* < 7.0.100
  • Tomcat 8.* < 8.5.51
  • Tomcat 9.* < 9.0.31

漏洞成因

Apache Tomcat默认启用了AJP协议,server.xml中配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
   <!-- A "Connector" represents an endpoint by which requests are received
and responses are returned. Documentation at :
Java HTTP Connector: /docs/config/http.html
Java AJP Connector: /docs/config/ajp.html
APR (HTTP/AJP) Connector: /docs/apr.html
Define a non-SSL/TLS HTTP/1.1 Connector on port 8080
-->
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="UTF-8" />
<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

第一个连接器监听8080端口,负责建立HTTP连接。在通过浏览器访问Tomcat服务器的Web应用时,使用的就是这个连接器。

第二个连接器监听8009端口,负责和其他的HTTP服务器建立连接。在把Tomcat与其他HTTP服务器集成时,就需要用到这个连接器。AJP连接器可以通过AJP协议和一个web容器进行交互。

攻击者通过AJP协议端口利用该漏洞进行文件读取或包含 Tomcat 上所有 webapp 目录下的任意文件,如:webapp 配置文件、源代码等。

漏洞验证

Apache Tomcat/9.0.20

因之前电脑上下载过tomcat,版本也在漏洞影响范围之内,直接拿来验证,在bin/start.bat启动服务。

image-20200222104320230

POC

1
https://github.com/hypn0s/AJPy

读取文件

1
python tomcat.py read_file --webapp=manager /secret.txt 127.0.0.1

image-20200222120327269

漏洞分析

源码下载

Apache Tomcat v9.0.20源码下载地址:

1
http://archive.apache.org/dist/tomcat/tomcat-9/v9.0.20/src/

代码分析

追踪到java\org\apache\coyote\ajp\AjpProcessor.java类,tomcat官网解释如下:

1
2
3
4
public class AjpAprProcessor
extends java.lang.Object
implements ActionHook
Processes HTTP requests.

AjpProcessor.java类中定位到prepareRequest()函数,此函数作用为一个请求删选器。接着来到代码704行左右:

可以看到,当属性值不等于Constants.SC_A_ARE_DONE时会进入判断,为Constants.SC_A_REQ_ATTRIBUTE时,接着进行if-else的判断,当没有匹配结果时,最终传入request.setAttribute()函数,各种属性值如下图:

QQ截图20200222171202

因此我们可以进行对Ajp设置特定的属性,封装为request对象的Attribute属性,比如以下三个属性可以被设置

1
2
3
javax.servlet.include.request_uri
javax.servlet.include.path_info
javax.servlet.include.servlet_path

读取文件

java\org\apache\catalina\servlets\DefaultServlet.java类中,service函数调用doGet方法处理request和response。

QQ截图20200222184059

doGet调用serverResource,在serverResource函数中读取request中的path,接着直接调用了resources.getResource()函数读取。

QQ截图20200222184458

QQ截图20200222184640)

跟进getRelativePath函数,看下是如何获取路径以及是否存在过滤,只要获取到request_uri不为null,然后从request对象中获取并设置pathInfo属性值和servletPath属性值。

QQ截图20200222195042

参考

1
https://www.anquanke.com/post/id/199448
Author: Sys71m
Link: https://www.sys71m.top/2020/02/22/Apache Tomcat漏洞分析及复现(CVE-2020-1938)/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.