幽灵猫 Tomcat文件读取/任意文件包含漏洞(CVE-2020-1938 / CNVD-2020-10487)

2024-01-31 18:10

本文主要是介绍幽灵猫 Tomcat文件读取/任意文件包含漏洞(CVE-2020-1938 / CNVD-2020-10487),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、漏洞简介

二、漏洞原理:

1.文件读取漏洞

2.任意代码执行漏洞

三、修复建议


学习该漏洞时我翻阅了大量的博客,但是感觉大部分没有说到点子上,所以写这篇博客,记录一下学习历程,接下来我会从代码和协议两个方面来分析这个漏洞。

一、漏洞简介

该漏洞是由长亭科技安全研究员发现的存在于 Tomcat 中的安全漏洞,由于 Tomcat AJP 协议设计上存在缺陷,攻击者通过 Tomcat AJP Connector 可以读取或包含 Tomcat 上所有 webapp 目录下的任意文件,例如可以读取 webapp 配置文件或源代码。此外在目标应用有文件上传功能的情况下,配合文件包含的利用还可以达到远程代码执行的危害。

影响版本:

                Apache Tomcat 6

                Apache Tomcat 7 < 7.0.100

                Apache Tomcat 8 < 8.5.51

                Apache Tomcat 9 < 9.0.31

二、漏洞原理:

首先还是了解这个漏洞要有一些基础知识

这个漏洞是tomcat的漏洞,所以我们要对tomcat的运行原理有一些概念。

tomcat的大致体系结构如下:

 Connector :用于在指定的端口上侦听客户请求,接收连接请求之后分配线程让 Container 来处理这个请求。 

Container :由四个自容器组件构成,分别是Engine、Host、Context、 Wrapper。

Engine :Engine 容器,定义了一些基本的关联关系。

Host :Host 是 Engine 的字容器,Host 在 Engine 中代表一个虚拟主机,其作用 就是运行多个应用。

Context :Context 容器,拥有 Servlet 运行的基本环境,且负责管理其中的 Servlet 实例。 Wrapper :Wrapper 是最底层的容器,负责管理一个 Servlet。

Servlet :服务程序。

(1) Tomcat Connector(连接器)

首先来说一下Tomcat的Connector组件,Connector组件的主要职责就是负责接收客户端连接客户端请求的处理加工。每个Connector会监听一个指定端口,分别负责对请求报文的解析和响应报文组装,解析过程封装Request对象,而组装过程封装Response对象。

上面说了那么多,其实意思就是Connector是tomcat的入口,一个其他博主的例子,如果把Tomcat比作一个城堡,那么Connector组件就是城堡的城门,为进出城堡的人们提供通道。当然,可能有多个城门,每个城门代表不同的通道。而Tomcat默认配置启动,开了两个城门(通道):一个是监听8080端口的HTTP Connector,另一个是监听8009端口的AJP Connector

Tomcat组件相关的配置文件是在conf/server.xml,配置文件中每一个元素都对应了Tomcat的一个组件(可以在配置文件中找到如下两项,配置了两个Connector组件):

    <Connector port="8080" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443" />
 <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

HTTP Connector很好理解,通过浏览器访问Tomcat服务器的Web应用时,使用的就是这个连接器;

AJP Connector是通过AJP协议和一个Web容器进行交互。在将Tomcat与其他HTTP服务器(一般是Apache )集成时,就需要用到这个连接器。AJP协议是采用二进制形式代替文本形式传输,相比HTTP这种纯文本的协议来说,效率和性能更高,也做了很多优化。

两个Connector的原理如下图所示: 

我们的浏览器肯定是不支持AJP协议的,所以要在AJP Connector前面加一个apache server的反向代理,我们先将http请求交到反向代理服务器,反向代理服务器再通过ajp协议在8009端口向tomcat发出请求。

(2)Servlet(服务程序)

Servlet意为服务程序,也可简单理解为是一种用来处理网络请求的一套规范。主要作用是给上级容器(Tomcat)提供doGet()和doPost()等方法,其生命周期实例化、初始化、调用、销毁受控于Tomcat容器。有个例子可以很好理解:想象一下,在一栋大楼里有非常多特殊服务者Servlet,这栋大楼有一套智能系统帮助接待顾客引导他们去所需的服务提供者(Servlet)那接受服务。这里顾客就是一个个请求,特殊服务者就是Servlet,而这套智能系统就是Tomcat容器。

tomcat默认配置了两个Servlet,一个是Jsp Servlert,另一个是Default Servlet,第一个是专门负责处理jsp类型的文件的,除了jsp文件的全都交给Default Servlet处理。Tomcat中Servlet的配置是在conf/web.xml 下面。

<!-- The default servlet for all web applications, that serves static    --><!-- resources.  It processes all requests that are not mapped to other   --><!-- servlets with servlet mappings. --><servlet><servlet-name>default</servlet-name><servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>............</servlet><!-- The JSP page compiler and execution servlet, which is the mechanism  --><!-- used by Tomcat to support JSP pages.  Traditionally, this servlet    --><!-- is mapped to the URL pattern "*.jsp". --><servlet><servlet-name>jsp</servlet-name><servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>............</servlet>............<!-- The mapping for the default servlet --><servlet-mapping><servlet-name>default</servlet-name><url-pattern>/</url-pattern></servlet-mapping><!-- The mappings for the JSP servlet --><servlet-mapping><servlet-name>jsp</servlet-name><url-pattern>*.jsp</url-pattern><url-pattern>*.jspx</url-pattern></servlet-mapping>

由以上配置文件也可以看出,如果是jsp文件的请求,回交给Jsp Servlert,其他的都交给Default Servlet进行处理。

(3)tomcat内部处理流程

在这里简单介绍一下处理流程就好,便于理解后续漏洞的分析。

  1. 用户点击网页内容,请求被发送到本机端口8080,被Connector获得(Connector中的Processor用于封装Request,Adapter用于将封装好的Request交给Container)。
  2. Connector把该请求交给Container中的Engine来处理,并等待Engine的回应。
  3. Engine获得请求localhost/test/index.jsp,匹配所有的虚拟主机Host。
  4. Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机),名为localhost的Host获得请求/test/index.jsp,匹配它所拥有的所有的Context。Host匹配到路径为/test的Context(如果匹配不到就把该请求交给路径名为" "的Context去处理)。
  5. path="/test"的Context获得请求/index.jsp,在它的mapping table中寻找出对应的Servlet。Context匹配到URL PATTERN为*.jsp的Servlet,对应于JspServlet类(匹配不到指定Servlet的请求对应DefaultServlet类)。
  6. Wrapper是最底层的容器,负责管理一个Servlet。构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet()或doPost(),执行业务逻辑、数据存储等程序。
  7. Context把执行完之后的HttpServletResponse对象返回给Host。
  8. Host把HttpServletResponse对象返回给Engine。
  9. Engine把HttpServletResponse对象返回Connector。
  10. Connector把HttpServletResponse对象返回给客户Browser。

在介绍漏洞之前还要配一下tomcat源码分析的环境,大家可以根据这篇博文Tomcat源码编译(IDEA)_tomcat 编译_ww0peo的博客-CSDN博客

来进行配置,配置的版本是apache-tomcat-8.5.46,配置好了之后就可以愉快的进行漏洞的代码分析了。

根据上文的Tomcat处理请求流程,请求首先到达Connector,Connector内使用AjpProcessor解析Socket,将Socket中的内容封装到Request中。然后经过一系列的处理,到达Servlet。根据上文我们可以了解到,tomcat默认配置两个Servlet,一个是Default Servlet,另一个是Jsp Servlet,而这这里就分别对应了文件读取漏洞和任意代码执行漏洞。

1.文件读取漏洞

当url未匹配到Servlet时,回给到Default Servlet处理。 

分析org.apache.catalina.servlets.DefaultServlet.java 。请求到达 DefaultServlet 后, 会执行 service() 方法,判断请求的 DispatcherType 是否为 ERROR ,若是则直接调用 doGet() 方法,否则调用父类的 Service() 方法。

 DefaultServlet 的父类为 HttpServlet (javax.servlet.http.HttpServlet.java)。其 service() 方法根据请求方法(method)决定调用 doGet() 或是 doPost() ,代码如下。此 处我们是读取文件,使用的是 doGet 方法。

然后回到子类,查询doGet方法。 通过serveResource方法来获取资源。

 在serveResource方法中,它定义了我们获取资源的路径

跟踪进去,

 我们发现了三个重要的参数,

INCLUDE_REQUEST_URI,   INCLUDE_PATH_INFO,   INCLUDE_SERVLET_PATH

 发现这三个参数可以控制我们请求资源的路径,继续跟踪,发现这三个属性都有默认值

static final String INCLUDE_REQUEST_URI = "javax.servlet.include.request_uri";
static final String INCLUDE_CONTEXT_PATH = "javax.servlet.include.context_path";
static final String INCLUDE_PATH_INFO = "javax.servlet.include.path_info";

 这里就是我们利用的重点,我们可以通过发送数据包来伪造这几个默认值,从而控制路径,到后面我会用wireshark抓包看一下。

由上面截图中的代码可知,当 request 中 javax.servlet.include.request_uri 不为空时,将 request 的 javax.servlet.include.path_info 与 javax.servlet.include.servlet_path 分别赋值给 path_info 和 servlet_path。 而后只要 path_info 与 servlet_path 的值不为空,就将 path_info 与 servlet_path 拼接起来赋值给 result。

回到serveResource 方法,获取到路径后创建资源的实例并且获取资源。

 跟踪进去getResource方法,(位于 org.apache.catalina.webresources.StandardRoot.java中)

 我们发现上述代码调用了validate进行判断,继续跟着

在这里有主要用了normalize方法来进行校验,其主要功能如下:

1.判断path中是否有'\\',有就转换成'/';

2.判断path是否以'/'开头,若不是则在前面加上'/';

3.判断path是否以'/.'或'/..'结尾,若是则结尾加一个'/';

4.判断path是否含有'//',有则替换成'/';

5.判断path是否含有'/./',若有直接截断并重新拼接,如'/./abc'变为'/abc'

6.判断path是否含有'/../',若有则直接返回null;

首先补充一个知识,当我们访问tomcat时,它会默认访问取webapps下的默认文件,而在这里对相对路径的符号进行了限制,所以我们利用该漏洞只能访问webapps下的文件。

在验证完成之后 ,会继续将资源返回到输出流中,再交由tomcat的内部进行处理。

至此利用过程结束,而我们可以通过刚才在 DefaultServlet 的 getRelativePath() 中说过的三个参数进行访问资源路径的控制。而我们首先还需要让请求到达 DefaultServlet ,需要让请求的 url 为 “/asdf” ,此处的 asdf 为随机字符串,目的是让 Tomcat 找不到 webapps 下的至指定文件,从而请求会到 Tomcat 的默认目录。

若是想请求 webapps 目 录下的其他目录,则可以设置为 ‘/指定目录/asdf’,如’’/manager/asdf’。会访问到webapps/manager/下的目录,具体的文件看我们构造的参数。

如要访问”webapps/ROOT/WEB-INF/web.xml”,首先将请求 url 为’/asdf’,再将 javax.servlet.include.request_uri 值设置为’/‘(非空), javax.servlet.include.servlet_path 的值设置为 ‘/‘,javax.servlet.include.path_info 的值设置为 ‘WEB-INF/web.xml’。

poc的下载地址为GitHub - YDHCUI/CNVD-2020-10487-Tomcat-Ajp-lfi: Tomcat-Ajp协议文件读取漏洞

但是在python3.7.9的版本下运行会报错,这里我修改了poc,修改的poc放在了tomcat_Ghostcat/ at main · fengdianxiong/tomcat_Ghostcat · GitHub 上,大家可以自取。

成功获取文件 。

我们再来看一下对应的数据包:

发现在poc的数据包中携带了我们上面三个重要的参数,从而实现文件读取。

2.任意代码执行漏洞

这个漏洞稍微有一点点鸡肋,需要提前先自己上传木马文件,然后利用文件包含漏洞来实现代码执行。

由上文可知,我们知道当请求jsp文件时,会走Jsp Servlet来进行处理。

首先来到JspServlert.java(位于org.apache.jasper.servlet.JspServlet.java),经过service方法处理,由标红部分可以看出,jspUri由servlet_path和path_info拼接而成。

然后进入到serviceJspFile方法中,方法利用 jspUri 生成 JspServletWrapper 实例,再到调用实例的 service() 方法。

获取到对应的Servlet

调用该Servlet的service方法

请求执行,从而造成文件包含。

利用过程简单就是,我们通过传入 servlet_path 和 path_info ,让其去将指定的文件作为 jsp 文件处理,Tomcat 会将根据指定的文件生成 java 代码并编译成 class ,而后加载 class 类实例化一个 servlet 并执行,从而造成文件包含。

在复现时,要修改一下poc的参数,然后在webapps目录下的ROOT下(apache-tomcat-8.5.46-source\catalina-home\webapps\ROOT),自己创建一个1.txt,

内容为

<%Runtime.getRuntime().exec("calc.exe");%>

然后再次利用poc,弹出计算器。

三、修复建议

(1)官方网站下载新版本进行升级。

(2)直接关闭 AJP Connector,或将其监听地址改为仅监听本机 localhost。

(3)若需使用 Tomcat AJP 协议,可根据使用版本配置协议属性设置认证凭证。

这篇关于幽灵猫 Tomcat文件读取/任意文件包含漏洞(CVE-2020-1938 / CNVD-2020-10487)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/664620

相关文章

Java读取InfluxDB数据库的方法详解

《Java读取InfluxDB数据库的方法详解》本文介绍基于Java语言,读取InfluxDB数据库的方法,包括读取InfluxDB的所有数据库,以及指定数据库中的measurement、field、... 首先,创建一个Java项目,用于撰写代码。接下来,配置所需要的依赖;这里我们就选择可用于与Infl

C#读取本地网络配置信息全攻略分享

《C#读取本地网络配置信息全攻略分享》在当今数字化时代,网络已深度融入我们生活与工作的方方面面,对于软件开发而言,掌握本地计算机的网络配置信息显得尤为关键,而在C#编程的世界里,我们又该如何巧妙地读取... 目录一、引言二、C# 读取本地网络配置信息的基础准备2.1 引入关键命名空间2.2 理解核心类与方法

最新版IDEA配置 Tomcat的详细过程

《最新版IDEA配置Tomcat的详细过程》本文介绍如何在IDEA中配置Tomcat服务器,并创建Web项目,首先检查Tomcat是否安装完成,然后在IDEA中创建Web项目并添加Web结构,接着,... 目录配置tomcat第一步,先给项目添加Web结构查看端口号配置tomcat    先检查自己的to

Apache Tomcat服务器版本号隐藏的几种方法

《ApacheTomcat服务器版本号隐藏的几种方法》本文主要介绍了ApacheTomcat服务器版本号隐藏的几种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需... 目录1. 隐藏HTTP响应头中的Server信息编辑 server.XML 文件2. 修China编程改错误

SpringBoot使用Apache POI库读取Excel文件的操作详解

《SpringBoot使用ApachePOI库读取Excel文件的操作详解》在日常开发中,我们经常需要处理Excel文件中的数据,无论是从数据库导入数据、处理数据报表,还是批量生成数据,都可能会遇到... 目录项目背景依赖导入读取Excel模板的实现代码实现代码解析ExcelDemoInfoDTO 数据传输

Python读取TIF文件的两种方法实现

《Python读取TIF文件的两种方法实现》本文主要介绍了Python读取TIF文件的两种方法实现,包括使用tifffile库和Pillow库逐帧读取TIFF文件,具有一定的参考价值,感兴趣的可以了解... 目录方法 1:使用 tifffile 逐帧读取安装 tifffile:逐帧读取代码:方法 2:使用

若依部署Nginx和Tomcat全过程

《若依部署Nginx和Tomcat全过程》文章总结了两种部署方法:Nginx部署和Tomcat部署,Nginx部署包括打包、将dist文件拉到指定目录、配置nginx.conf等步骤,Tomcat部署... 目录Nginx部署后端部署Tomcat部署出现问题:点击刷新404总结Nginx部署第一步:打包

Nginx、Tomcat等项目部署问题以及解决流程

《Nginx、Tomcat等项目部署问题以及解决流程》本文总结了项目部署中常见的four类问题及其解决方法:Nginx未按预期显示结果、端口未开启、日志分析的重要性以及开发环境与生产环境运行结果不一致... 目录前言1. Nginx部署后未按预期显示结果1.1 查看Nginx的启动情况1.2 解决启动失败的

tomcat在nginx中的配置方式

《tomcat在nginx中的配置方式》文章介绍了如何在Linux系统上安装和配置Tomcat,并通过Nginx进行代理,首先,下载并解压Tomcat压缩包,然后启动Tomcat并查看日志,接着,配置... 目录一、下载安装tomcat二、启动tomcat三、配置nginx总结提示:文章写完后,目录可以自动

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo