漏洞描述:

tomcat是Apache组织开发的中小型的JavaEE服务器,它实现了servlet,JSP等javaEE规范,可以提供web资源访问服务,tomcat主要提供了两种通信方式访问web资源:http协议和AJP协议。

AJP是一个基于tcp协议的应用层协议,tomcat服务器默认会在8009端口开放了一个AJP服务,客户端(浏览器)通过与tomcat服务器的8009端口建立AJP通信,可以访问服务器的web资源。但是tomcat的AJP协议在设计上存在一些缺陷,攻击者通过这点可以构造恶意的请求进行文件包含操作,从而读取tomcat服务器webapp目录下的任意文件。

漏洞环境:

apache-tomcat-8.0.50

apache-tomcat-8.0.50-src

漏洞复现:

tomcat的conf目录下有一个server.xml配置文件,该文件中有两个onnector,一个是用于处理http协议,另一个是处理AJP协议,tomcat服务器会根据客户端的请求使用对应的Connector来处理。

根据该漏洞的特点,可以通过网络工具扫描目标服务器8009端口来判断是否存在漏洞,我用nmap工具试了一下,可以扫出目标服务器的8009端口对应的ajp服务,nmap还是挺强大的。

启动tomcat服务器,然后执行poc读取tomcat服务器的目录/WEB-INF/web.xml文件,可以看到成功读取到web.xml文件,说明漏洞复现成功。

由于AJP协议是基于tcp协议无法使用burpsuite工具抓取其数据包,只能通过wireshark工具抓包,这里我们只需关注AJP协议数据包即可,通过wireshark的过滤规则把所有AJP数据包都过滤出来,可以看到AJP协议的数据包格式还是和HTTP协议有些类似的

从抓到的数据包来看AJP是一个应用层协议,整个通信过程可以分为三部分:建立tcp连接阶段,AJP通信阶段,释放tcp连接阶段,这里我们重点关注AJP通信过程。

Frame 61是客户端(浏览器)发送的第一个AJP数据包,选中Frame 61数据包查看其AJP数据包的详细信息,分析AJP数据包发送了哪些内容:

可以看到AJP请求的head部分中Method字段中指定了AJP协议的请求方式是GET,URI表示AJP请求的web资源,Version表示AJP请求的版本信息,最后是AJP请求的数据部分。

在整个AJP请求数据包中,这一部分是poc程序漏洞利用代码构造的恶意数据

漏洞分析:

当tomcat服务器收到AJP请求后会交由AjpProcessor类来处理,也就是说,AjpProcessor类是用于处理AJP协议的,但真正处理AJP请求数据的是AjpProcessor的父类org.apache.coyote.ajp.AbstractAjpProcessor。

AbstractAjpProcessor类中有一个process方法用于处理AJP请求,但是process方法内部逻辑过于复杂,无需深入分析,这里我们记住一点:该方法内部会循环调用一个prepareRequest方法处理AJP请求数据,如下所示:

在prepareRequest方法内部中,调用了setAttribute方法将AJP请求中的数据部分封装到request请求中的attributes属性中,然后tomcat会将AJP请求分发给Servlet处理,而tomcat服务器的web.xml默认有两个Servlet,分别为处理JSP请求的JspServlet和处理所有请求的DefaultServlet。

由于POC发送的AJP请求的URI字段的资源是jsp

根据tomcat服务器的web.xml文件中JSP请求的映射规则,这个请求会被JspServlet匹配到,那么这个AJP请求会分发给JspServlet处理。

然后JspServlet会调用service方法处理AJP请求:

    @SuppressWarnings("deprecation") // Use of JSP_FILE to be removed in 8.5.x@Overridepublic void service (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//判断jspFile是否为nullString jspUri = jspFile;if (jspUri == null) {// JSP specified via <jsp-file> in <servlet> declaration and// supplied through custom servlet container codeString jspFile = (String) request.getAttribute(Constants.JSP_FILE);if (jspFile != null) {jspUri = jspFile;request.removeAttribute(Constants.JSP_FILE);}}if (jspUri == null) {//从request域中获取servlet_pathjspUri = (String) request.getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH);if (jspUri != null) {//从request域中获取path_infoString pathInfo = (String) request.getAttribute(RequestDispatcher.INCLUDE_PATH_INFO);//将servlet_path和path_info拼接成uri路径if (pathInfo != null) {jspUri += pathInfo;}} else {jspUri = request.getServletPath();String pathInfo = request.getPathInfo();if (pathInfo != null) {jspUri += pathInfo;}}}if (log.isDebugEnabled()) {log.debug("JspEngine --> " + jspUri);log.debug("\t     ServletPath: " + request.getServletPath());log.debug("\t        PathInfo: " + request.getPathInfo());log.debug("\t        RealPath: " + context.getRealPath(jspUri));log.debug("\t      RequestURI: " + request.getRequestURI());log.debug("\t     QueryString: " + request.getQueryString());}try {boolean precompile = preCompile(request);//然后调用serviceJspFile方法serviceJspFile(request, response, jspUri, precompile);} catch (RuntimeException e) {throw e;} catch (ServletException e) {throw e;} catch (IOException e) {throw e;} catch (Throwable e) {ExceptionUtils.handleThrowable(e);throw new ServletException(e);}}

service方法会判断jspFile是否为null,如果jspFile为null的话,就会调用getAttribute方法从request域的attribute属性中获取JSP资源路径(INCLUDE_SERVLET_PATH和INCLUDE_PATH_INFO这两个常量的值是可控的),最后得到一个这样的uri路径:/WEB-INF/web.xml 。

这两个常量的定义如下:

static final String INCLUDE_SERVLET_PATH = "javax.servlet.include.servlet_path";
static final String INCLUDE_PATH_INFO = "javax.servlet.include.path_info";

接着调用了一个preCompile方法,该方法会获取request请求中的参数部分,大多数情况下都会返回false

    boolean preCompile(HttpServletRequest request) throws ServletException {//获取request请求中的参数部分String queryString = request.getQueryString();//参数为空则直接返回falseif (queryString == null) {return (false);}//......}

将得到的uri路径传给了serviceJspFile方法参数jspUri

 private void serviceJspFile(HttpServletRequest request , HttpServletResponse response , String jspUri , boolean precompile)throws ServletException, IOException {//根据uri路径获取JSPJspServletWrapper wrapper = rctxt.getWrapper(jspUri);if (wrapper == null) {synchronized(this) {wrapper = rctxt.getWrapper(jspUri);if (wrapper == null) {//检查uri指定的jsp资源是否存在if (null == context.getResource(jspUri)) {handleMissingResource(request, response, jspUri);return;}//存在就解析jsp资源wrapper = new JspServletWrapper(config, options, jspUri,rctxt);rctxt.addWrapper(jspUri,wrapper);}}}try {wrapper.service(request, response, precompile);} catch (FileNotFoundException fnfe) {handleMissingResource(request, response, jspUri);}}

serviceJspFile方法主要是根据参数jspUri指定的jsp资源的路径解析JSP并进行展示,getResource方法会根据jspUri中的uri路径判断指定的文件是否存在,如果存在就会解析该路径指定的资源。

如何通过文件包含漏洞来达到RCE执行目的?

前提是必须上传一个嵌入RCE代码的JSP文件到目标tomcat服务器上,当我们访问这个JSP文件时,JspServlet会将指定的JSP文件转换成java代码的.class文件,然后执行该字节码文件时就会执行RCE代码弹出计算机(具体原理可参考JspServlet源码执行原理)。

新建一个123.jsp文件插入java代码上传到目标tomcat服务器的WEB-INF目录下

<%--Created by IntelliJ IDEA.User: ylDate: 2021/8/8Time: 9:51To change this template use File | Settings | File Templates.
--%><%@ page contentType="text/html;charset=UTF-8" language="java" %><%-- 嵌入RCE代码 --%>
<% Runtime.getRuntime().exec("calc.exe"); %>

成功弹出计算机

除了JspServlet之外,DefaultServlet也可以产生任意文件包含漏洞,这两种方式的利用思路大致相同,这里就不再继续分析了,感兴趣的同学可以自行分析。

漏洞修复:

1. 在server.xml中注释掉8009端口的Connector,禁用AJP协议

2. 升级最新版本

2-java安全——tomcat AJP协议文件包含分析[CVE-2020-1938]相关推荐

  1. Tomcat AJP协议文件读取漏洞

    漏洞描述: Tomcat在 server.xml中配置了两种连接器: 1.HTTP Connector:监听8080端口,负责建立HTTP连接.在通过浏览器访问Tomcat服务器的Web应用时,使用的 ...

  2. tomcat ajp协议安全限制绕过漏洞_Apache Tomcat文件包含漏洞(CVE20201938)复现

    一.漏洞背景2020年02月20日,国家信息安全漏洞共享平台(CNVD)发布了关于Apache Tomcat文件包含漏洞(CVE-2020-1938/CNVD-2020-10487)的安全公告.Tom ...

  3. tomcat ajp协议安全限制绕过漏洞_Apache tomcat 文件包含漏洞复现(CVE20201938)

    漏洞背景 Tomcat是由Apache软件基金会下属的Jakarta项目开发的一个Servlet容器,按照Sun Microsystems提供的技术规范,实现了对Servlet和JavaServer ...

  4. tomcat ajp协议安全限制绕过漏洞_国家信息安全漏洞共享平台发布Apache Tomcat漏洞安全公告...

    2月22日消息 国家信息安全漏洞共享平台(CNVD)近日发布了一份关于 Apache Tomcat 存在文件包含漏洞的安全公告,具体如下: 安全公告编号:CNTA-2020-0004 2020 年 1 ...

  5. [CNVD-2020-10487/CVE-2020-1938]: Tomcat AJP协议漏洞

    环境搭建 下载存在漏洞版本8.5.50: https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.50/bin/apache-tomcat-8.5.5 ...

  6. springboot需要tomcat服务器吗_嵌入式 Tomcat AJP 协议对 SpringBoot 应用的影响

    前言 2020 年 1 月 6 日,国家信息安全漏洞共享平台(CNVD)收录了由北京长亭科技有限公司发现并报送的 Apache Tomcat 文件包含漏洞.Tomcat AJP 协议由于存在实现缺陷导 ...

  7. 在Java中实现SFTP协议文件传输的两种解决方案

    在Java中实现SFTP协议文件传输的两种解决方案 1.1 背景 1.2 关于 FTP /FTPS 1.3 关于SFTP 解决方案一:使用 JSch 库 解决方案二:使用sshj 库 这篇博文来聊聊在 ...

  8. 墨者学院_phpMyAdmin后台文件包含分析溯源

    墨者学院_phpMyAdmin后台文件包含分析溯源 phpmyadmin 4.8.1 远程文件包含漏洞(CVE-2018-12613) phpMyAdmin是一套开源的.基于Web的MySQL数据库管 ...

  9. Java安全-Tomcat AJP 文件包含漏洞(CVE-2020-1938)幽灵猫漏洞复现

    Tomcat AJP 文件包含漏洞(CVE-2020-1938) CVE-2020-1938 又名GhostCat ApacheTomcat服务器中被发现存在文件包含漏洞,攻击者可利用该漏洞读取或包含 ...

最新文章

  1. 西游记里河水让人怀孕的秘密:是寄生虫!我往河里放了寄生虫!
  2. suse linux 命令 收藏
  3. The conversion of a varchar data type to a datetime data type resulted in an out-of-range value
  4. Android开发之旅:组件生命周期(二)
  5. MySQL查询表内重复记录
  6. python运行excel高级筛选怎么用_懂点EXCEL就行!教你利用Python做数据筛选(上)...
  7. 陶哲轩实分析习题9.1.1
  8. [总结]DataGrid 固定表头实现(纵向和横向滚动条滚动,而Header不动)
  9. java仔_Java基础语法吐血整理
  10. PreparedStatement批量执行sql
  11. 开源运维管理软件排名_车主无忧:为什么放弃开源Kafka?
  12. php 修改input内容,JS简单获取并修改input文本框内容的方法示例
  13. Algorithm——A*路径规划算法原理详解
  14. 华为交换机之间静态路由配置实例
  15. 传智黑马python18期_传智博客黑马Python就业14期资料
  16. python单因素方差分析_Python数据科学:方差分析
  17. 群晖NAS跨存储空间移动套件(应用)
  18. mac 版 Goland 使用教程一
  19. Lombok链式调用,子类对象set父类属性,返回父类对象
  20. Matlab读取和显示图像

热门文章

  1. php imagick生成图片,php Imagick 生成图片
  2. 云服务器虚拟机提示内存不足是什么情况?
  3. 驭势导读 | 通往深度学习之路,“杀鸡焉用宰牛刀”?
  4. 首行缩进字符计算机怎么弄,word首行缩进2字符是多少厘米
  5. 扫码还是NFC,哪一种乘车模式会“支付”未来?
  6. 什么是网络安全风险评估?
  7. poj 2942-圆桌骑士(点双连通分量+二分图)
  8. MATLAB车道偏离检测,车道线检测
  9. mysql2003错误10061_Mysql连接报2003-10061以及1045错误
  10. PAT乙级真题 1032 挖掘机技术哪家强 C++实现