漏洞概述

Apache 在2017年9月19日发布并修复了CVE-2017-12616CVE-2017-12615两个高危漏洞,并且在Apache Tomcat 7.0.81进行了修复。

Tomcat 安全漏洞发布地址:
https://tomcat.apache.org/security-7.html

CVE-2017-12616(信息泄露):允许未经身份验证的远程攻击者查看敏感信息。如果tomcat开启VirtualDirContext有可能绕过安全限制访问服务器上的JSP文件源码。Apache security Team在2017年8月10号已经识别该漏洞,2017年9月19日已经发布修复该漏洞最新版本的tomcat 7.0.81。影响范围为:7.0.0 to 7.0.80

CVE-2017-12615(远程代码执行漏洞):360观星实验室(360-sg-lab)在2017年7月26向apache security Team报告了该漏洞。Tomcat7服务器允许进行HTTP PUTs操作(例如通过设置初始化参数readonly默认值为false),攻击者通过构造的恶意请求可以上传JSP的webshell,webshell可以在服务器上执行任意的操作。影响范围为:7.0.0-7.0.79

Apache security team本次发布的两个漏洞涉及到tomcat两个重要的处理Http请求的Servlet,分别为org.apache.catalina.servlets.DefaultServlet和org.apache.jasper.servlet.JspServlet。其中DefaultServlet主要用于处理静态资源如html、image等。JspServlet用于处理动态页面请求如JSP、JSPX等。


图1 conf/web.xml配置

什么时候调用哪个Servelt?这个决定取决于tomcat请求路由核心组件org.apache.tomcat.util.http.mapper.Mapper,Mapper定义了多个规则判断客户端的请求该使用哪个Servlet。

CVE-2017-12616(信息泄露)

漏洞触发的先决条件是需要在conf/server.xml配置VirtualDirContex参数,默认情况下tomcat7并不会对该参数进行配置。VirtualDirContex主要使用场景是在IDE开发环境,生产环境tomcat官方不建议开启。正常情况下一般不会配置该参数开启,因此该漏洞显得有点鸡肋。


图2 VirtualDirContext类关系图

VirtualDirContextFileDirContext的子类,它允许在单独的一个webapp应用下对外暴露出多个文件系统的目录。实际项目开发过程中,为了避免拷贝静态资源(如images等)至webapp目录下,tomcat推荐的做法是在server.xml配置文件中建立虚拟子目录。


图3 项目结构

例如:我们项目的webapp目录为F:\site\cve-2017-12616,静态资源的目录为F:\site\images。现在我们想将两个目录合并为一个名义上的一个目录,需要在tomcat的conf/server.xml的<Host></host>节点下增加虚拟目录配置。

<Context path="/site" docBase="F:\site\cve-2017-12616\src\main\webapp" reloadable="true" debug="1">
  <!-- 配置项目的资源 -->
  <Resources className="org.apache.naming.resources.VirtualDirContext" extraResourcePaths="/WEB-INF/classes=F:/site/cve-2017-12616/target/classes,/images=F:/site/images" />
  <!-- 配置项目的 classpath -->
  <Loader className="org.apache.catalina.loader.VirtualWebappLoader" virtualClasspath="/WEB-INF/classes=F:/site/cve-2017-12616/target/classes" />
  <!-- 扫描 jar 的内容 -->
  <JarScanner scanAllDirectories="true" />
</Context>

这个时候我们tomcat7服务器重启,打开浏览器访问以下地址,实际上就是完整在浏览器上展示出一张图片。


图4 通过虚拟目录访问静态资源

让我们重新回到漏洞本身,tomcat开启VirtualDirContext有可能绕过安全限制访问服务器上的JSP源码。如果我们临时对外开放了一个目录/temp=F:/site/cve-2017-12616/src/main/webapp,且该目录包含了很多敏感的JSP代码,那么敏感信息在不用授权的情况下将被泄露出去。因此生产环境不建议开启。另外tomcat本质上是Servlet容器引擎,tomcat访问所有资源都用Servlet来实现的,它的优势不在于处理静态资源,性能与响应时间与专门处理静态资源的服务器相比有差距。静态资源一般由前端代理服务器如nginx、apache来进行处理。

<Resources className="org.apache.naming.resources.VirtualDirContext" 
extraResourcePaths="/WEB-INF/classes=F:/site/cve-2017-12616/target/classes,/images=F:/site/images,/temp=F:/site/cve-2017-12616/src/main/webapp" />

JspServlet负责处理所有JSP和JPSX类型的动态请求,DefautServelt负责处理静态资源请求。因此,就算我们构造请求直接上传JSP webshell显然是不会成功的。

图5 构造请求

该漏洞实际上是利用了windows下文件名解析的漏洞来触发的。精心构造的恶意请求会绕过JspServelt,从而由DefaultServlet来处理该请求。

图6 DefaultServlet

图7 DefaultServlet

serverResource方法首先会根据请求的path查询缓存中是否存请求资源缓存CacheEntry。如果存在则直接返回,不存在则构建缓存条目。如果cacheEntry.contextnull而且path.endsWith(&quot;/&quot;) || (path.endsWith(&quot;\\&quot;)),则直接向客户端返回404,所以采用Malicious.jsp/方式并不能够成功触发获取服务端漏洞的JSP代码。

虚拟目录文件内容由VirtualDirContext处理,非虚拟目录文件内容由FileDirContext处理。FileDirContext存在一个名为file的检查文件路径的方法。file方法并不能阻止恶意构造的请求文件路径如:

protected File file(String name) {
    File file = new File(base, name);
    if (file.exists() && file.canRead()) {
        if (allowLinking)
            return file;
        // Check that this file belongs to our root path
        String canPath = null;
        try {
            canPath = file.getCanonicalPath();
        } catch (IOException e) {
            // Ignore
        }
        if (canPath == null)
            return null;
        // Check to see if going outside of the web application root
        if (!canPath.startsWith(absoluteBase)) {
            return null;
        }
        // Case sensitivity check - this is now always done
        String fileAbsPath = file.getAbsolutePath();
        if (fileAbsPath.endsWith("."))
            fileAbsPath = fileAbsPath + "/";
        String absPath = normalize(fileAbsPath);
        canPath = normalize(canPath);
        if ((absoluteBase.length() < absPath.length())
            && (absoluteBase.length() < canPath.length())) {
            absPath = absPath.substring(absoluteBase.length() + 1);
            if (absPath == null)
                return null;
            if (absPath.equals(""))
                absPath = "/";
            canPath = canPath.substring(absoluteBase.length() + 1);
            if (canPath.equals(""))
                canPath = "/";
            if (!canPath.equals(absPath))
                return null;
        }
    } else {
        return null;
    }
    return file;
}

图7 VirtualDirContext提供的file方法

如果将文件名修改成”click.jsp%20” 或者 “click.jsp::$DATA”成功获取JSP文件源码。

图8 构造恶意请求获取JSP

图9 构造恶意请求获取JSP

上述分析还遗留了一个问题,为什么Java 语言中的File对象能够正确处理下面三种路径的文件路径。

第一种方式”Malicious.jsp/”,在文件后缀名末尾处增加特殊字符”/”

调试源码发现,java.io.Win32FileSystem的normalize将文件后缀末尾进行规范化处理去掉了尾部的”\”。

第二种方式”Malicious.jsp ”,在文件名后缀末尾增加一个或多个空格。

Open是一个Java native方法,Java无法直接访问到操作系统底层(如系统硬件等),为此Java使用native方法来扩展Java程序的功能。open具体实现细节只能参考开源的JDK 的C源码了。

第三仲方式“Malicious.jsp::$DATA”,在文件名后缀末尾处增加“::$DATA”。

By default, the default data stream is unnamed. To fully specify the default data stream, use "filename::$DATA",
where $DATA is the stream type. This is the equivalent of "filename". You can
create a named stream in the file using the file naming conventions**. Note that "$DATA" is a legal stream name.

从执行结果可以看出,windows会将文件名后缀的所有空格去掉,在windows环境下载文件名的后缀增加特殊字符::$DATA对原文件名相等。

CVE-2017-12615(远程代码执行漏洞)

conf/web.xml默认配置 readOnly值为true,禁止HTTP进行 PUT和DELTE类型请求。

为了复现漏洞,将readOnly设置为false。

JspServlet负责处理所有JSP和JPSX类型的动态请求,从代码没有发现处理HTTP PUT类型的操作, PUT 以及 DELTE 等HTTP操作由DefautServelt实现。因此,就算我们构造请求直接上传JSP webshell显然是不会成功的。该漏洞实际上是利用了windows下文件名解析的漏洞来触发的。

说明:Http定义了与 服务器的交互方法,其中除了一般我们用的最多的GET,POST 其实还有PUT和DELETE。根据RFC2616标准(现行的HTTP/1.1)其实还有OPTIONS, HEAD, PUT,DELETE,TRACE,CONNECT等方法。

图4的请求测试结果表明了上诉的猜测结论是正确的。JspServlet负责处理所有JSP和JPSX类型的动态请求,不能够处理PUT方法类型的请求。

利用文件解析漏洞采用PUT方式上传jsp webshell文件。其中文件名设为/malicious.jsp%20。如果文件名后缀是空格那么将会被tomcat给过滤掉。

webshell执行结果
利用Java File的特性,将上传文件名设置为/malicious1.jsp/。Webshell也可以正常上传至tomcat服务器。Java的File对象会将末尾的”/”去掉,因此可以成功上传webshell。很显然这种绕过利用方式存在于所有版本的tomcat以及linux、windows等操作系统。

基于File特性上传webshell

webshell被成功上传
将文件名后缀修改为::$DATA,如malicous.jsp::$DATA会被JDK认为是malicous.jsp,也能够成功上传webshell。

搭建docker靶机环境

搭建及运行漏洞环境:

docker build -t cve201712615/tomcat:7.0.73 . --rm=true
docker images cve201712615/tomcat
docker run -it -p 1116:8080 镜像前4位

docker靶机webshell执行结果

docker配置Git地址:https://github.com/JavaPentesters/java_vul_target

相关资料Git地址:

https://github.com/JavaPentesters/java_vul_target

源链接

Hacking more

...