CVE-2020-5410 Spring Cloud Config目录穿越漏洞

2020-06-15 约 147 字 预计阅读 1 分钟

声明:本文 【CVE-2020-5410 Spring Cloud Config目录穿越漏洞】 由作者 p0desta 于 2020-06-15 09:46:42 首发 先知社区 曾经 浏览数 222 次

感谢 p0desta 的辛苦付出!

漏洞描述

Spring Cloud Config,2.2.3之前的2.2.x版本,2.1.9之前的2.1.x版本以及较旧的不受支持的版本允许应用程序通过spring-cloud-config-server模块提供任意配置文件。恶意用户或攻击者可以使用特制URL发送请求,这可能导致目录遍历攻击。

Spring cloud Config已经出现过两次目录穿越漏洞,分别是CVE-2019-3799和CVE-2020-5405,可参考之前的文章:https://xz.aliyun.com/t/7558

漏洞补丁

这次补丁主要是两个部分,第一个部分是将对路径的检测方法单独的封装了出来,封装到了PathUtils类中,并且做了部分的修改,其中最主要的是检测了#,至于是为什么,后面来说。

第二部分,也就是漏洞的触发入口,在environment/EnvironmentController.java中,增加了对name、label字段的检测

漏洞细节

通过补丁我们可以大概知道漏洞应该是出在EnvironmentController,但是具体怎么触发并不知道,所以我们需要跟一遍正常逻辑看一下处理流程。
既然是目录穿越漏洞,我们先通过环境变量设置本地读取

profiles:
    active: native
  cloud:
    config:
      server:
        native:
          search-locations:
            - file:/test/config-repo-master

然后使用正确的请求来动态跟踪调用堆栈http://127.0.0.1:8889/111/222/333,将断点打在入口处,然后往下跟

在跟到environment/NativeEnvironmentRepository.java的时候发现参数进行了拼接,

重新跟进getArgs看一下

private String[] getArgs(String application, String profile, String label) {
        List<String> list = new ArrayList<String>();
        String config = application;
        if (!config.startsWith("application")) {
            config = "application," + config;
        }
        list.add("--spring.config.name=" + config);
        list.add("--spring.cloud.bootstrap.enabled=false");
        list.add("--encrypt.failOnError=" + this.failOnError);
        list.add("--spring.config.location=" + StringUtils.arrayToCommaDelimitedString(
                getLocations(application, profile, label).getLocations()));
        return list.toArray(new String[0]);
    }

主要在getLocations中对路径进行了下拼接,声称了一个将env中的uri拼接了label,生成新的location,那么这个点就是我们目录穿越的关键,继续往下跟,在environment/NativeEnvironmentRepository.java中会将args传入spring boot的ConfigurableApplicationContext context = builder.run(args),后面会使用loader.load函数加载资源,在加载资源的时候会遍历locations拼接name来获取资源,首先来判断是否存在文件,如果文件存在,则去使用url.openConnection来获取资源,通过分析我们知道label和name是我们可控的传入,

url = env-uri+label+name+extension

因为是借助的url.openConnection,结合补丁增加了#限制,我们可以清楚的知道通过在name中以#结尾,使extension成为锚点,也就绕过了后缀的限制。
在构造poc之前其实还有一个问题,就是这里我们知道一开始是没有对路径进行检测的,那么我们是否可以直接使用../../来穿越呢?答案是否,因为如果我们想要传入后端处理,必须二次url编码,但是二次编码后,首先经过的是判断文件是否存在,如果存在才调用url.openConnection来处理,经过一次解码后,显然该路径文件是不存在的。

这里就有了跟CVE-2020-5405一样的操作,将(_)替换成了/,处理方法在

public static String normalize(String s) {
        if (s != null && s.contains(SLASH_PLACEHOLDER)) {
            // "(_)" is uncommon in a git repo name, but "/" cannot be matched
            // by Spring MVC
            return s.replace(SLASH_PLACEHOLDER, "/");
        }
        return s;
    }

构造poc:

http://127.0.0.1:8889/flag.txt%23/222/..%28_%29..%28_%29..%28_%29..%28_%29..%28_%29..%28_%29..%28_%29tmp%28_%29

构造完这个poc会想到,既然是label+name来拼接的,我们是否可以不用管label,目录穿越的方法在name处构造呢?
答案是可以的,poc如下

http://127.0.0.1:8889/..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252Ftmp%252Fflag.txt%23/222/11

参考

关键词:[‘安全技术’, ‘漏洞分析’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now