热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

CVE20201938/CNVD202010487漏洞调试

0x01漏洞背景CVE-2020-1938是Tomcat-Ajp协议漏洞分析,Tomcat是由Apache软件基金会属下Jakarta项目开发的Servlet容器&

0x01 漏洞背景

CVE-2020-1938 是 Tomcat-Ajp 协议漏洞分析,Tomcat是由Apache软件基金会属下Jakarta项目开发的Servlet容器,按照Sun Microsystems提供的技术规范,实现了对Servlet和JavaServer Page(JSP)的支持。由于Tomcat本身也内含了HTTP服务器,因此也可以视作单独的Web服务器。


0x02 影响版本


  1. Apache Tomcat 9.x <9.0.31
  2. Apache Tomcat 8.x <8.5.51
  3. Apache Tomcat 7.x <7.0.100
  4. Apache Tomcat 6.x

0x03 环境搭建


0x1 JDK 安装

cp -r jdk-8u161-linux-x64.tar.gz /usr/local/java
cd /usr/local/java
tar -zxvf jdk-8u161-linux-x64.tar.gz

在/etc/profile文件中写入

export JAVA_HOME&#61;/usr/local/java/jdk1.8.0_161
export JRE_HOME&#61;/$JAVA_HOME/jre
export CLASSPATH&#61;.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH&#61;$PATH:$JAVA_HOME/bin:$JRE_HOME/bin

执行生效
source /etc/profile


0x2 Tomcat 安装

tar -zxvf apache-tomcat-8.5.30.tar.gz

在/etc/profile文件中写入

export CATALINA_HOME&#61;/usr/local/tomcat/apache-tomcat-8.5.30
export CLASSPATH&#61;.:$JAVA_HOME/lib:$CATALINA_HOME/lib
export PATH&#61;$PATH:$CATALINA_HOME/bin

执行生效
source /etc/profile
启动
catalina.sh start


0x3 开启Tomcat调试

在tomcat bin 文件夹下的catalina.sh中添加如下代码

export JAVA_OPTS&#61;&#39;-agentlib:jdwp&#61;transport&#61;dt_socket,server&#61;y,suspend&#61;n,address&#61;5005&#39;
# OS specific support. $var _must_ be set to either true or false.

Tomcat 调试原理
分为两种情况&#xff1a;


  1. 调试器开端口&#xff0c;远程JVM连接本地端口
  2. 远程JVM开放端口&#xff0c;调试器连接

总的来说&#xff0c;两个VM之间通过debug协议进行通信&#xff0c;然后以达到远程调试的目的。两者之间可以通过socket进行通信。其中&#xff0c;调试的程序常常被称为debugger, 而被调试的程序称为 debuggee。两种调试情况如下图所示&#xff1a;

file

关于调试协议JDWP这里先不讲&#xff0c;等有机会在进行讲解。


0x4 添加tomcat源码

在调试过程中&#xff0c;intellij反编译代码会有出入&#xff0c;直接下载tomcat相对应版本的源代码
https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.30/src/apache-tomcat-8.5.30-src.zip

将文件夹中的java 添加到intellij中&#xff0c;就可以对着源代码进行调试了

file


0x5 开启Intellij调试

设置Use module classpath 为项目根目录&#xff0c;设置调试端口等信息&#xff0c;如下图所示&#xff1a;

file


0x03 知识补充


0x1 Tomcat Connector


Apache Tomcat服务器通过Connector连接器组件与客户程序建立连接&#xff0c;Connector表示接收请求并返回响应的端点。即Connector组件负责接收客户的请求&#xff0c;以及把Tomcat服务器的响应结果发送给客户。在Apache Tomcat服务器中我们平时用的最多的8080端口&#xff0c;就是所谓的Http Connector&#xff0c;使用Http&#xff08;HTTP/1.1&#xff09;协议.


在conf/server.xml文件里&#xff0c;他对应的配置为


而 AJP Connector&#xff0c;它使用的是 AJP 协议&#xff08;Apache Jserv Protocol&#xff09;是定向包协议。因为性能原因&#xff0c;使用二进制格式来传输可读性文本&#xff0c;它能降低 HTTP 请求的处理成本&#xff0c;因此主要在需要集群、反向代理的场景被使用。


Ajp协议对应的配置为


下图是tomcat 服务器开放连接端口情况。

file


0x2 Tomcat Servlet

在tomcat conf/web.xml中配置着tomcat的路由处理&#xff0c;主要有两个servlet分支

这个规则匹配/后没有后缀的

<servlet><servlet-name>defaultservlet-name><servlet-class>org.apache.catalina.servlets.DefaultServletservlet-class><init-param><param-name>debugparam-name><param-value>0param-value>init-param><init-param><param-name>listingsparam-name><param-value>falseparam-value>init-param><load-on-startup>1load-on-startup>servlet><servlet-mapping><servlet-name>defaultservlet-name><url-pattern>/url-pattern>servlet-mapping>

这个规则匹配路径中有.jsp的路由

<servlet><servlet-name>jspservlet-name><servlet-class>org.apache.jasper.servlet.JspServletservlet-class><init-param><param-name>forkparam-name><param-value>falseparam-value>init-param><init-param><param-name>xpoweredByparam-name><param-value>falseparam-value>init-param><load-on-startup>3load-on-startup>servlet><servlet-mapping><servlet-name>jspservlet-name><url-pattern>*.jspurl-pattern><url-pattern>*.jspxurl-pattern>servlet-mapping>

0x3 Tomcat 请求处理

该图介绍了Tomcat内部处理HTTP请求的流程
file


  1. 用户发送请求至8080端口&#xff0c;被Connector获取后&#xff0c;Connector中的Processor用于封装Request&#xff0c;Adapter用于将封装好的Request交给Container。
  2. Connector把该请求交给Container中的Engine来处理&#xff0c;并等待Engine的回应。
  3. Engine 获得请求localhost/test/index.jsp&#xff0c;匹配所有的虚拟主机Host。
  4. Engine搜索对应的主机&#xff0c;/test匹配到Context&#xff0c;
  5. path&#61;"/test"的Context获得请求/index.jsp&#xff0c;在它的mapping table中寻找出对应的Servlet。Context匹配到URL PATTERN为*.jsp的Servlet&#xff0c;对应于JspServlet类&#xff08;匹配不到指定Servlet的请求对应DefaultServlet类&#xff09;
  6. Wrapper是最底层的容器&#xff0c;负责管理一个Servlet。构造HttpServletRequest对象和HttpServletResponse对象&#xff0c;作为参数调用JspServlet的doGet()或doPost()&#xff0c;执行业务逻辑、数据存储等程序。
  7. Context把执行完之后的HttpServletResponse对象返回给Host
  8. Host把HttpServletResponse对象返回给Engine
  9. Engine把HttpServletResponse对象返回Connector
  10. Connector把HttpServletResponse对象返回给客户Browser

0x04 漏洞分析

该漏洞通过AJP协议端口触发&#xff0c;正是由于上文所述&#xff0c;Ajp协议的请求在Tomcat内的处理流程与我们上文介绍的Tomcat处理HTTP请求流程类似。我们构造两个不同的请求&#xff0c;经过tomcat内部处理流程&#xff0c;一个走default servlet(DefaultServlet)&#xff0c;另一个走jsp servlet(JspServlet)&#xff0c;可导致的不同的漏洞。


0x1 文件读取漏洞

# 请求url
req_uri &#61; &#39;/asdf&#39;# AJP协议请求中的三个属性
javax.servlet.include.request_uri &#61; &#39;/&#39;
javax.servlet.include.path_info &#61; &#39;WEB-INF/web.xml&#39;
javax.servlet.include.servlet_path &#61; &#39;/&#39;

在搭好的环境上&#xff0c;设置断点


Step 1 AjpProcessor->service()->prepareRequest()

file

进入prepareRequest函数&#xff0c;该函数处理Requests请求&#xff0c;重点在这一块

file

file

在该case分支request.setAttribute(n,v )函数是解析函数&#xff0c;通过三次循环可见下图效果

file

file

file

通过三个循环将attributes变量赋值成如下所示&#xff1a;

file

随后将请求传给CoyoteAdapter&#xff0c;对request进行封装&#xff0c;将请求抓发给Container&#xff1a;

file

通过多级反射和调用&#xff0c;到达Servlet路由分发

file




Step 2 DefaultServlet-> service() -> doGet()

从CoyoteAdapter到达doGet的调用链
file

Servlet 的service函数根据请求的方法&#xff0c;调用不同的处理函数如下图匹配Get 方法&#xff1a;
1588562393145.pngfile




Step 3 getRelativePath()

从get函数进入后执行serveResource函数
file

file

其中有个关键的函数getRelativePath

protected String getRelativePath(HttpServletRequest request, boolean allowEmptyPath) {String servletPath;String pathInfo;if (request.getAttribute("javax.servlet.include.request_uri") !&#61; null) {pathInfo &#61; (String)request.getAttribute("javax.servlet.include.path_info");servletPath &#61; (String)request.getAttribute("javax.servlet.include.servlet_path");} else {pathInfo &#61; request.getPathInfo();servletPath &#61; request.getServletPath();}StringBuilder result &#61; new StringBuilder();if (servletPath.length() > 0) {result.append(servletPath);}if (pathInfo !&#61; null) {result.append(pathInfo);}if (result.length() &#61;&#61; 0 && !allowEmptyPath) {result.append(&#39;/&#39;);}return result.toString();}

从代码中可以看出request.getAttribute的变量正好是我们POC中的变量&#xff0c;POC中的参数代入getRelativePath()方法&#xff0c;RequestDispatcher.INCLUDE_REQUEST_URI的值为’/’&#xff0c;不为空。pathInfo和servletPath参数的值拼接成result&#xff0c;getRelativePath()方法将result返回&#xff0c;返回内容为&#xff1a;’/WEB-INF/web.xml’。


Step 4 getResource() -> validate() -> normalize()

serveResource()方法继续往下&#xff0c;可以看到这行代码&#xff1a;

file

该函数功能从字面意思上就是获取内容

file

进入了valiate方法&#xff0c;该方法为路径检测方法&#xff0c;其中主要调用了normalize方法&#xff0c;重点关注该方法&#xff1a;

if (normalized.endsWith("/.") || normalized.endsWith("/..")) {normalized &#61; normalized &#43; "/";addedTrailingSlash &#61; true;}// Resolve occurrences of "//" in the normalized pathwhile (true) {int index &#61; normalized.indexOf("//");if (index < 0) {break;}normalized &#61; normalized.substring(0, index) &#43; normalized.substring(index &#43; 1);}// Resolve occurrences of "/./" in the normalized pathwhile (true) {int index &#61; normalized.indexOf("/./");if (index < 0) {break;}normalized &#61; normalized.substring(0, index) &#43; normalized.substring(index &#43; 2);}// Resolve occurrences of "/../" in the normalized pathwhile (true) {int index &#61; normalized.indexOf("/../");if (index < 0) {break;}

过滤掉了请求中的路径穿越符号 /…/&#xff0c;也就导致了该漏洞只能读取webapps目录下的文件。

Step5 ServletOutputStream.write()

file

经过Tomcat内部流程处理&#xff0c;经过Tomcat的Container和Connector&#xff0c;最终返回给客户端。


特别注意

关键参数req_uri决定了我们可以读取webapps下其他目录的文件。当为’asdf’时无法匹配到webapps下的路径&#xff0c;所以路由到tomcat默认的ROOT目录&#xff1b;二来是为了让tomcat将请求流到DefaultServlet&#xff0c;从而触发漏洞。


真实文件请求路径
webapps/managermanager/asdf
webapps/ROOT/asdf

0x2 文件包含漏洞

该漏洞的触发与上个相似&#xff0c;只不过servlet的分支不同&#xff0c;该漏洞走的是JspServlet&#xff0c;所有的jsp文件的路由
将漏洞利用代码修改为

file


Step 1 JspServlet -> service() -> serviceJspFile()

从CoyoteAdapter进行分发&#xff0c;这里分发到jspservlet路由&#xff0c;因此我们要在jspservlet上下断点

file

file


0x05 后续


  1. 自己编写ajp协议
  2. tomcat web服务器交互原理
  3. java 反射调用链分析

0x06 参考链接


  1. https://xz.aliyun.com/t/7683
  2. https://www.anquanke.com/post/id/199448#h2-7
  3. https://www.freebuf.com/column/227973.html
  4. https://www.jianshu.com/p/f902ac5d29e4

推荐阅读
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • 如何在服务器主机上实现文件共享的方法和工具
    本文介绍了在服务器主机上实现文件共享的方法和工具,包括Linux主机和Windows主机的文件传输方式,Web运维和FTP/SFTP客户端运维两种方式,以及使用WinSCP工具将文件上传至Linux云服务器的操作方法。此外,还介绍了在迁移过程中需要安装迁移Agent并输入目的端服务器所在华为云的AK/SK,以及主机迁移服务会收集的源端服务器信息。 ... [详细]
  • 本文介绍了在使用Python中的aiohttp模块模拟服务器时出现的连接失败问题,并提供了相应的解决方法。文章中详细说明了出错的代码以及相关的软件版本和环境信息,同时也提到了相关的警告信息和函数的替代方案。通过阅读本文,读者可以了解到如何解决Python连接服务器失败的问题,并对aiohttp模块有更深入的了解。 ... [详细]
  • WebSocket与Socket.io的理解
    WebSocketprotocol是HTML5一种新的协议。它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送 ... [详细]
author-avatar
min覀igreenr
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有