转载

Traversal with Spring MVC on Windows复现分析【CVE-2018-1271】

Spring Framework versions 5.0 to 5.0.4, 4.3 to 4.3.14, and older unsupported versions allow applications to configure Spring MVC to serve static resources (e.g. CSS, JS, images). When static resources are served from a file system on Windows (as opposed to the classpath, or the ServletContext), a malicious user can send a request using a specially crafted URL that can lead a directory traversal attack.

触发这个漏洞的条件有三个:

  1. 要使用file协议打开资源文件目录
  2. Windows平台
  3. 不能使用Tomcat或者wildfy等中间件(本环境演示使用的是jetty服务器)

环境搭建

  1. 修改配置文件 org.springframework.samples.mvc.config.WebMvcConfig 中的 resources 目录,

       public void addResourceHandlers(ResourceHandlerRegistry registry) {
    	registry.addResourceHandler("/resources/**").addResourceLocations("file:///C:/static/","/resources/");
    }
    

    其中的 sourceLocations 中的目录地址是根据自己的实际情况进行定义。我的项目是桌面上,所以我将 sourceLocations 目录地址指向 C:/static/ (这个没有明确地要求,根据自己的实际环境设置即可)。

    C/static/ 下存在 123.txt 的文件,内容是 456

  2. 由于漏洞的环境要求是要求 jetty 服务器,我们需要通过 mvn jetty:run 这种方式启动,通过IDEA同样可以完成这样的功能。利用IDEA jetty插件就可以完成,具体的配置方法可以参考文章 idea jetty插件 。我的配置如下:

    Traversal with Spring MVC on Windows复现分析【CVE-2018-1271】

  3. 如果能够成功启动,没有报错。访问 localhost:8080 ,出现如下的界面说明环境搭建成功。

    Traversal with Spring MVC on Windows复现分析【CVE-2018-1271】

漏洞复现

由于我们已经在 WebMvcConfig 中已经设置了 resources 所对应的本地路径。当我们访问 resources 路径下的文件时访问实际上是 C:/static/ 下的文件。所以如果我们访问 http://127.0.0.1:8080/spring-mvc-showcase/resources/123.txt 实际上访问就是 static 目录下的123.txt。如下:

Traversal with Spring MVC on Windows复现分析【CVE-2018-1271】

但是这样也就意味着存在目录穿越的漏洞。如:

Traversal with Spring MVC on Windows复现分析【CVE-2018-1271】

成功地读取了 windows/win.ini 文件。

漏洞分析

首先需要说明的一个问题是,为什么不能使用Tomcat或者是wildfy服务器,是因为这些服务器是无法识别 ../ 。像我们POC中出现了 ..%5c/ 这种路径,Tomcat等服务器就会出现 404 的错误。但是Jetty却可以识别这种路径,这也就是为什么这个漏洞的触发要求是Jetty服务器的原因。

接下来就对漏洞进行详细地分析。在 org.springframework.web.servlet.resource.ResourceHttpRequestHandler:getResource() 地方下断点进行分析。此时的参数信息如下:

Traversal with Spring MVC on Windows复现分析【CVE-2018-1271】

request 中保存的路劲是 /spring-mvc-showcase/resources/static/..%5c/..%5c/windows/win.ini 。经过 request.getAttribute() 函数之后,对其中的 %5c 进行了解码,path的值是 static/..//..//windows/win.ini

Traversal with Spring MVC on Windows复现分析【CVE-2018-1271】

之后运行到 Resource resource = resolveChain.resolveResource(request, path, getLocations()) 。如下所示:

Traversal with Spring MVC on Windows复现分析【CVE-2018-1271】

其中 path 就是我们上一步得到的 static/..//..//windows/win.ini , getLocations() 就是之前在配置文件中配置的路径 C:/static/

之后通过层层调用,最终程序会运行到 org.springframework.web.servlet.resource.PathResourceResolver:getResource() 中:

Traversal with Spring MVC on Windows复现分析【CVE-2018-1271】

通过 Resource resource = location.createRelative(resourcePath); 拼接得到访问文件的绝对路径, file:/C:/static/static/..%5C/..%5C/windows/win.ini

进一步跟踪,进入到 org.springframework.core.io.AbstractFileResolvingResource:exists() 中,

Traversal with Spring MVC on Windows复现分析【CVE-2018-1271】

由于此时的url是 file:/C:/static/static/..%5C/..%5C/windows/win.ini 。通过了 ResourceUtils.isFileURL(url) 的判断,之后成功地读取了文件内容。

漏洞修复

我们修改 pom.xml 中的 org.springframework-version 为漏洞修复的版本5.0.6的版本。同时要注释其中一个插件(在5.0.6的版本下会存在一点问题),插件如下

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.20.1</version>
    <configuration>
        <includes>
            <include>**/*Tests.java</include>
        </includes>
        <excludes>
            <exclude>**/Abstract*.java</exclude>
        </excludes>
        <junitArtifactName>junit:junit</junitArtifactName>
        <argLine>-Xmx512m</argLine>
    </configuration>
</plugin>

再一次访问 http://127.0.0.1:8080/spring-mvc-showcase/resources/static/..%5c/..%5c/windows/win.ini

当程序运行至 path = this.processPath(path); ,可以看到path的值仍然是 static/..//..//windows/win.ini
Traversal with Spring MVC on Windows复现分析【CVE-2018-1271】

我们跟踪进入到 processPath() 方法中:

protected String processPath(String path) {
    path = StringUtils.replace(path, "//", "/");  // 替换反斜线为斜线,path此时为static/..//..//windows/win.ini
    path = this.cleanDuplicateSlashes(path);      // 去掉多余斜线,path此时为static/../../windows/win.ini
    return this.cleanLeadingSlash(path);
}

经过 processPath() 最终得到path值为 static/../../windows/win.ini 。之后程序经过 this.isInvalidPath(path) 对path的非法性进行分析。

protected boolean isInvalidPath(String path) {
        if (!path.contains("WEB-INF") && !path.contains("META-INF")) {
            if (path.contains(":/")) {
                String relativePath = path.charAt(0) == '/' ? path.substring(1) : path;
                if (ResourceUtils.isUrl(relativePath) || relativePath.startsWith("url:")) {
                    logger.trace("Path represents URL or has /"url:/" prefix.");
                    return true;
                }
            }

            if (path.contains("..")) {
                path = StringUtils.cleanPath(path);
                if (path.contains("../")) {
                    logger.trace("Path contains /"..//" after call to StringUtils#cleanPath.");
                    return true;
                }
            }

            return false;
        } else {
            logger.trace("Path contains /"WEB-INF/" or /"META-INF/".");
            return true;
        }
    }

程序会进入到 path.contains("..") 分支中。经过 path = StringUtils.cleanPath(path); 得到 ../windows/win.ini ,此时满足了 path.contains("../") 条件,被认为是非法路径。最终 getResource() 返回的就是 null ,程序无法读取到 win.ini 的内容返回404。

Traversal with Spring MVC on Windows复现分析【CVE-2018-1271】

漏洞的修复其实就是阻止了跨目录的方式读取文件。漏洞修复的两个位置是:1. 修改了 processPath() 对路径的处理;2. 增加了 isInvalidPath() 对路径的合法性判断。

原文  http://blog.spoock.com/2018/05/30/cve-2018-1271/
正文到此结束
Loading...