如何更加精准地检测AJP协议文件包含漏洞(CVE-2020-1938)

通过上篇文章 《CVE-2020-1938:Tomcat AJP协议文件包含漏洞分析》 ,我们知道这个漏洞出现在Tomcat默认的两个 Servlet ,一个是 DefaultServelt ,可以任意文件读取。第二个是 JspServlet ,可以用于文件读取和代码执行。所以我们漏洞利用的关键是让精心构造的数据包最终让这两个 Servlet 处理。但是在真实环境下的Web项目情况很复杂,会添加自定义的 ServletFilter ,使用各种框架和组件。它们的 ServletFilter 匹配规则会影响我们构造的数据包处理流向,导致我们无法检查成功。本文我们会针对常见的5种情况并一一解决!

0x01 知识储备

在分析前我们需要对Tomcat匹配规则优先级有一个了解,匹配的优先级如下,优先级从上到下:

  1. 精确匹配(例如: /admin/index.html
  2. 路径匹配 (例如:/*)
  3. 拓展名匹配 (例如: *.jsp , *.jspx )
  4. 缺省匹配 (比如: /

具体的匹配细节可以查看Tomcat源码 org.apache.catalina.mapper.Mapper#internalMapWrapper()

0x02 情况一:原生Servlet环境下

Tomcat下存在多个默认的web项目,由于它们没有使用任何框架

  • docs
  • examples
  • host-manager
  • manager

当没有默认的web项目,我们只能检查 ROOT 下的项目了。在使用原生Servlet开发的web应用,我们要考虑的是开发人员自定义 filter 和自定义 servlet 对漏洞影响。

按照开发经验,一般过滤器是不会过滤 .js , .css , .ico 等静态文件后缀的url,同时自定义的Servlet也不会去处理这些url。所以我们可以构造类似如下请求来绕过它们带来的影响。

RequestUri:/facvon.ico
javax.servlet.include.request_uri: /
javax.servlet.include.path_info: WEB-INF/web.xml
javax.servlet.include.servlet_path: /

0x03 情况二:Sping mvc环境下

Spring MVC的经典配置如下:

<servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:spring-mvc-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

虽然覆盖掉了 DefaultServlet 的比配路径,但是 *.jsp,*.jspx 依然会交给 JspServlet 处理,所以我们可以构造如下请求让JspServlet来触发漏洞。

RequestUri:/index.jsp
javax.servlet.include.request_uri: /
javax.servlet.include.path_info: WEB-INF/web.xml
javax.servlet.include.servlet_path: /

这里给大家提个问题

问题:如果已经知道某个contoller使用的是jsp为视图模版来渲染数据,我们能否通过它来触发漏洞?

答案:其实是不可以的。因为spring mvc会将模版渲染后,交个JspServlet去解析之前,调用 org.apache.catalina.core.ApplicationDispatcher#doInclude 方法对3个include属性进行重新赋值,也就是把我们之前设置的值覆盖掉了不再可控!

如何更加精准地检测AJP协议文件包含漏洞(CVE-2020-1938)

0x04 情况三:Spring boot

Srping boot结合Tomcat来部署有两种方式,分别是 外置内嵌

5.1 内嵌Tomcat

我们先来说内嵌,它是默认的部署方式。故名思义就是spring boot内部代码来调用Tomcat提供Web服务。这种方式默认AJP是不开启的。

若开启AJP, DefaultServlet 的比配路径也会 org.springframework.web.servlet.DispatcherServlet 覆盖,而 JspServlet 这个是没有被注册的,因为该类在 jasper.jar 中,Spring boot默认依赖中没有。

这里值得一提的是有一种情况时可以触发漏洞的,当Spring boot需要以JSP为视图模版时,jasper.jar需要被引入。通过调试Spring boot发现会自动注册一个将 *.jsp*.jspxJspservlet 的处理的 mapper ,具体参考一下两处源码。

org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#prepareContext

如何更加精准地检测AJP协议文件包含漏洞(CVE-2020-1938)

org.springframework.boot.web.servlet.server.AbstractServletWebServerFactory#shouldRegisterJspServlet

如何更加精准地检测AJP协议文件包含漏洞(CVE-2020-1938)

5.2 外置Tomcat

外置就是把 SpringBoot 项目打成war,部署到tomcat的webapps目录下。这种情况下的检测和Spirng MVC情况一样。

所以综合来看,内置情况下只有配置开启了 AJP 并引入了 jasper.jar 才可以被利用,这种情况少。外置情况下可以直接利用,这种情况也少。所以我认为Spring boot出现可以触发该漏洞的可能性不大。

0x05 情况四:shiro环境下

经典配置下shiro过滤器会对所有路径进行过滤。shiro内部对url的访问权限有如下5个属性进行管理

  • anon: 无需认证即可访问
  • authc: 需要认证才可访问
  • user: 点击“记住我”功能可访问
  • perms: 拥有权限才可以访问
  • role: 拥有某个角色权限才能访问

假设配置如下,在为登录情况下只能访问被配置为 anon 权限的 login.jsp ,访问其他链接都会302跳转至登录页面。所以只能请求这个页面来触发漏洞了。

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager"/>
    <property name="loginUrl" value="/login"/>
    <property name="unauthorizedUrl" value="/refuse.html"/>
    <property name="filterChainDefinitions">
        <value>
            /logout = logout
            /login.jsp = anon
            /** = authc
        </value>
    </property>
    <property name="successUrl" value="/index"/>
</bean>

但我们在自动化中如何发现被配置为 anon 权限的URL呢?实验室的背影师傅给了一条很重要的提示,可以通过该漏洞设置request对象属性 shiroFilter: 1 来“关闭”shiro的拦截功能。

如果 request 对象的属性名 alreadyFilteredAttributeName 的值不为空,那么将直接交给 Tomcatservlet 处理,相当于关闭了 shiro 的拦截!

如何更加精准地检测AJP协议文件包含漏洞(CVE-2020-1938)

alreadyFilteredAttributeName变量等于 shiro过滤器名 + .FILTERED

通过查看代码发现 shiroFilter 其实是 web.xml 设置的 shiro 过滤器名,这是由开发人员自定义的,故带来了新的问题。若不知道 shiro 过滤器名怎么办呢?

如何更加精准地检测AJP协议文件包含漏洞(CVE-2020-1938)

通过调试 shiro ,发现请求会被上面说的5种权限过滤器,依次匹配并处理。最重要的是它们的名字固定!于是按照同样的方法,都给它们设置上已过滤flag,即可绕过shiro的限制。具体请求构造如下:

RequestUri:/test.jsp
javax.servlet.include.request_uri: /
javax.servlet.include.path_info: WEB-INF/web.xml
javax.servlet.include.servlet_path: /
authc.FILTERED: 1
user.FILTERED: 1
perms.FILTERED: 1
role.FILTERED: 1

0x06 情况五:Struts2环境下

以下分析的是Struts2 2.5.22

使用Struts2框架一般需要设置如下的全局过滤器

<filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

该过滤器默认会将后缀为 .action 的URL请求,交给 Struts2Action 处理,而其他后缀就交给Tomcat默认Servlet处理,漏洞利用需要让其走后者。

如何更加精准地检测AJP协议文件包含漏洞(CVE-2020-1938)

然而在URL获取上Struts2由别于其他环境,这是导致于其他环境利用方式不同。它通过 request 对象的 javax.servlet.include.servlet_path 属性获取,而不是 request.getServletPath()

org.apache.struts2.dispatcher.mapper.DefaultActionMapper#getUri()

如何更加精准地检测AJP协议文件包含漏洞(CVE-2020-1938)

所以我们在这里必须设置该属性值为非空非 .action 的后缀 test.jsp ,才能让Tomcat的 JspServlet 来处理。但是如果我们还是使用原来的方式读 /WEB-INF/web.xml 是行不通的,因为最终构造的路径如下是错误的。

= javax.servlet.include.servlet_path + javax.servlet.include.path_info
= /test.jsp + '/WEB-INF/web.xml'
= /test.jsp/WEB-INF/web.xml (路径错误)

那我们能否将 javax.servlet.include.path_info 设置为 /../WEB-INF/web.xml 来吃掉 1.jsp 形成正确路径呢?答案是可以的!可能看过我对这个漏洞分析文章的朋友会说,不是说路径里不能使用 ../ 进行跳目录么?上一篇文章表述由问题,其实是可以跳目录,只是不能跳出 webapps 而已。这里重新说明下路径校验函数 normalized() 的功能。

如何更加精准地检测AJP协议文件包含漏洞(CVE-2020-1938)

该方法的功能是中和掉路径中的 ./../ ,比如 /a/.//b/../c 就会被中和为 /a/c 。如果最后依然存在 ../ 在开头,才会返回 null ,最终抛出非法路径的异常。

所以在 Struts2 框架下检测该漏洞,需要发包如下来绕过。

RequestUri:/
javax.servlet.include.request_uri: /
javax.servlet.include.path_info: /../WEB-INF/web.xml
javax.servlet.include.servlet_path: /1.jsp

0x07 演示

最后便可以将以上各个场景的特点综合起来,编写扫描工具了。这里我搭建了SpringMVC + Shiro的环境进行演示。可以发现其他的url都重定向了,只有我们针对shiro构造的请求是200,并成功触发漏洞!

如何更加精准地检测AJP协议文件包含漏洞(CVE-2020-1938)

0x08 最后的话

  1. 只对每种环境较新版本进行分析,调研范围不会很全
  2. 每种环境下的检测方案,只考虑使用Tomcat默认存在缺陷的两个Servlet( JspServletDefaultServlet )来检测,更完美的方案应该是去找每种环境下其他存在的缺陷的Servlet。
  3. 本文提供的扫描方案不可能适配所有环境,只对精确检测做一个抛砖引玉。

最后想说,涉及的环境有些多,分析得不够准确的欢迎联系我。

原文 

http://gv7.me/articles/2020/how-to-detect-tomcat-ajp-lfi-more-accurately/

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » 如何更加精准地检测AJP协议文件包含漏洞(CVE-2020-1938)

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址