Tomcat文件读取&文件包含漏洞(CVE-2020-1938)

声明

好好学习,天天向上

漏洞简述

Java 是目前 Web 开发中最主流的编程语言,而 Tomcat 是当前最流行的 Java 中间件服务器之一,从初版发布到现在已经有二十多年历史,在世界范围内广泛使用。

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

详情可以在这个网址进行了解

https://www.chaitin.cn/en/ghostcat

影响范围
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

漏洞原理&复现

tomcat

提到tomcat,最先反应过来的就是web站点,一般都是通过tomcat去开放web服务,比起apache、IIS等专业HTTP服务器,tomcat主要功能是提供JSP/Servlet的容器,对静态资源像是html的处理速度远不及apache和IIS,这就意味着,tomcat管后台服务,前面的静态页面交给apache和IIS

第一种架构,是直接通过tomcat开放web服务,包括前后端了,那就是用户直接通过http访问tomcat也是我们调试或者说平时开发环境比较常见的方式

第二种架构,专业的事情交给专业的人,apache擅长静态前端页面,tomcat擅长后端,那就是客户通过http访问

apache提供的前端页面,apche通过tomcat专有协议AJP访问tomcat(8009)

在这里插入图片描述

无论是哪种架构,tomcat内部的机制都一样的,Connector和Container是最核心的,通过Connector去开放端口监听请求,封装成Request,经过下面一大串部件的努力,最后返回Response

在这里插入图片描述

通最常见的两个Connector

8080是直接提供http服务的第一种架构的形式

8009是第二种架构

可以在server.xml中理解tomcat的体系结构

在这里插入图片描述

在这里插入图片描述

tomcat处理请求的方式是通过servlet进行请求的分发的,熟悉j2ee开发的,最先接触的就是servlet,哪个请求哪个参数交给哪个类处理,最终返回什么页面等等

而tomcat有两个默认servlet,一个是default,一个是jsp,处理机制为:

1.请求的url里面有.jsp或者.jspx就进入jsp的servlet

2.如果没匹配到就进入default的servlet

在这里插入图片描述

tomcat的漏洞就是基于AJP协议的,我们可以先进行源码部署

https://blog.csdn.net/qq_15719169/article/details/120936516

tomcat下载地址,我就用8.5.46

https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.46

poc地址

https://github.com/YDHCUI/CNVD-2020-10487-Tomcat-Ajp-lfi

文件读取

源码部署完成后,我们来跟踪代码

可以看到,python发送的是AJP协议的请求,-f也就是我们读取的文件,对应请求体attributes里面的args.file,而发送的的url是/asdf,也就是让tomcat调用default的servlet

在这里插入图片描述

先执行poc

python2 ./tomcat.py 192.168.2.99 -p 8009 -f ./WEB-INF/web.xml

进入第一站org/apache/coyote/ajp/AjpProcessor.java的prepareRequest方法,这里会运行三次,会把我们刚刚在python里面写入的attributes传进来,给attributes进行赋值

在这里插入图片描述

注意第二次,已经把我们想要读取的文件注入到attribute里了

在这里插入图片描述

org/apache/coyote/ajp/AjpProcessor.java的service方法,而这里的requests已经变了

在这里插入图片描述

在这里插入图片描述

javax/servlet/http/HttpServlet.java的service方法,由于我们访问的url是/asdf,没匹配上jsp的servlet,那么自然会交给DefaultServlet处理

在这里插入图片描述

org/apache/catalina/servlets/DefaultServlet.java的service方法和doGet方法

在这里插入图片描述

org/apache/catalina/servlets/DefaultServlet.java的serveResource方法,会调用getRelativePath方法

在这里插入图片描述

org/apache/catalina/servlets/DefaultServlet.java的getRelativePath方法

要注意这一段代码了,要满足if条件才做,pathInfo和servletPath的赋值操作

        if (request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI) != null) {
            // For includes, get the info from the attributes
            pathInfo = (String) request.getAttribute(RequestDispatcher.INCLUDE_PATH_INFO);
            servletPath = (String) request.getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH);
        } else {
            pathInfo = request.getPathInfo();
            servletPath = request.getServletPath();
        }

在这里插入图片描述

而RequestDispatcher.INCLUDE_REQUEST_URI在javax/servlet/RequestDispatcher.java有定义

在这里插入图片描述

所以也就自然走if里面了,最后pathInfo和servletPath被赋值,并且字符串拼接后返回给刚刚的path变量,并通过getResource根据path获取资源

在这里插入图片描述

在这里插入图片描述

我们直接ctrl点击getResource方法后,会进入org/apache/catalina/WebResourceRoot.java,但它是个接口,我们得找实现了这个接口并且实现了这个方法的地方

在这里插入图片描述

org/apache/catalina/webresources/StandardRoot.java,实现了这个接口

在这里插入图片描述

并完成了这个方法,但是这个方法还对path进行了校验,我们得看看我们传入的path是否经得住考验

在这里插入图片描述

进入本类的validate方法,查看使用normalize方法进行了过滤,normalize方法会将…/进行处理,无法路径穿越,这也就是我们只能在webapp中读取任意文件的原因所在

在这里插入图片描述

再回到org/apache/catalina/servlets/DefaultServlet.java的serveResource方法,准备响应了

在这里插入图片描述

将resourceBody也就是根据我们给的文件名读取的内容写到输出流

在这里插入图片描述

可以看到我们读取的是ROOT下面的WEB-INF/web.xml

在这里插入图片描述

文件包含

先更改poc,url加入.jsp,期望让tomcat交给jsp的servlet处理

在这里插入图片描述

在ROOT下的随便目录下写入想要被包含的文件,shell.txt,内容为,这里是我们想要执行的代码

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

在这里插入图片描述

执行poc

python2 ./tomcat.py 192.168.2.99 -p 8009 -f shell.txt

org/apache/coyote/ajp/AjpProcessor.java的prepareRequest方法,跟文件读取一样的套路,先注入attribute,可以看到shell.txt已经注入,但是我们不是为了读取,我们目标是让shell.txt被当做jsp文件包含,从而执行calc

在这里插入图片描述

在这里插入图片描述

进入service方法,由于匹配到了.jsp,所以会交给JspServlet.java的service方法

在这里插入图片描述

org/apache/jasper/servlet/JspServlet.java的service方法,获取需要包含的文件名,保存在jspUri

在这里插入图片描述

根据jspUri调用我们熟悉的service

在这里插入图片描述

org/apache/jasper/servlet/JspServletWrapper.java的service方法,会调用compile,按住ctrl进入继续跟进

在这里插入图片描述

org/apache/jasper/JspCompilationContext.java的compile方法,会调用compile,按住ctrl进入继续跟进

在这里插入图片描述

org/apache/jasper/compiler/Compiler.java的compile方法,这里将shell.txt编译成class,不过我的断点为什么没有触发呢?

在这里插入图片描述

org/apache/jasper/servlet/JspServletWrapper.java的service方法,也就是最后执行代码的地方

在这里插入图片描述

在这里插入图片描述

执行了shell.txt中的代码

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/zy15667076526/article/details/131309648