浅析CVE-2020-5405

之前就有师傅在先知发表过,这里跟进了一下。

漏洞信息

Spring Cloud Config 程序内部在处理客户端传入的资源时存在自动将 (_) 转换为 / 的隐藏转换,当 profile 设置为 native时,则会导致服务端路径穿越,因此攻击者可以利用此机制来穿越到其它路径,读取任意文件。

影响范围

1
2
Spring Cloud Config 2.2.0 - 2.2.1
Spring Cloud Config 2.1.0 - 2.1.6

环境搭建

以 2.1.5 版本为例,从官方 Git 仓库下载 v2.1.5.RELEASE 版本:

https://github.com/spring-cloud/spring-cloud-config/archive/v2.1.5.RELEASE.zip

解压缩后,进入解压缩之后的 spring-cloud-config-2.1.5.RELEASE 代码目录,找到下列文件,修改其中的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
info:
component: Config Server
spring:
application:
name: configserver
autoconfigure.exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
jmx:
default_domain: cloud.config.server
profiles:
active: native
cloud:
config:
server:
native:
search-locations:
- file:///Users/xianyu123/IdeaProjects/CVE-2020-5405spring-cloud-config-2.1.5.RELEASE

server:
port: 9999
management:
context_path: /admin

设置profiles-activenative

1
2
profiles:
active: native

设置search-locations为任意文件夹。

1
2
3
4
5
cloud:
config:
server:
native:
search-locations:

主文件入口位置为org.springframework.cloud.config.server.ConfigServerApplication,运行spring-cloud-config-server模块,环境开启成功运行在127.0.0.1:9999

maven依赖安装

我是在idea中直接打开的,maven依赖会自动安装,不是使用ide的话参考下面的方法

执行下面的命令启动 Spring Cloud Config 服务端(注:必须要安装 maven,并且加入 PATH 环境变量):

1
2
cd spring-cloud-config-server
../mvnw spring-boot:run

项目启动成功后,通过浏览器即可访问。

1
http://127.0.0.1:9999/

漏洞利用

POC

1
2
3
4
5
6
7
# Linux
/b/a/..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)etc/resolv.conf
/b/a/..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)etc/hosts.allow

# Windows
/b/a/..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)windows/system.ini
# 仅在 configserver.yml 的 search-locations 指向 C 盘下路径时有效

漏洞分析

Config-Client可以从Config-Server提供的HTTP接口获取配置文件使用,Config Server通过路径/{name}/{profile}/{label}/{path}对外提供配置文件,POC就会通过路由到这个接口

根据spring官方文档可知,解析下路由的结构:

name,应仓库名称。
profile,应配置文件环境。
label,git分支名。
**,通配子目录。

所以我们从HTTP入口org/springframework/cloud/config/server/resource/ResourceController.java第71行这里开始调试,请求url为http://127.0.0.1:9999/b/a/..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)etc/resolv.conf。76行,我们的path被解析为resolv.conf。然后跟进第77行retrieve方法

先跟进105行解析name的resolveName方法

替换name中存在的(_),这里name没有变化,然后我们继续跟进上述代码的resolveLabel方法

这里label中所有的(_)被替换成了/,所以最终返回../../../../../../../../../etc,然后我们接着跟进107行的findOne方法

到达org/springframework/cloud/config/server/resource/GenericResourceRepository.java,跟进64行getLocations方法

到达org/springframework/cloud/config/server/environment/SearchPathCompositeEnvironmentRepository.java,这里跟进47行getLocations方法

到达org/springframework/cloud/config/server/environment/NativeEnvironmentRepository.java文件的,this.searchLocations;是生成file://开头的代码

最终上述org/springframework/cloud/config/server/resource/GenericResourceRepository.java文件的64行代码会返回对应的file协议的绝对路径地址且为有两个元素的数组,然后接着去跟进69行getProfilePaths方法

这里返回是个Set集合,返回结果为resolv-a.confresolv.conf,这段代码不难理解

然后上面的返回的值resolv-a.confresolv.conf分别迭代。然后跟进org/springframework/cloud/config/server/resource/GenericResourceRepository.java的第70行isInvalidPath方法,这里主要是检测path中是否包含一些字符的,比如限制了WEB-INFMETA-INF

然后接着跟进org/springframework/cloud/config/server/resource/GenericResourceRepository.java的第70行isInvalidEncodedPath方法,这里主要是检测是否为有效url编码的,影响也不是很大

然后就根据反射读取文件了

1
2
3
4
Resource file = this.resourceLoader.getResource(location)
.createRelative(local);
if (file.exists() && file.isReadable()) {
return file;

参考链接

CVE-2020-5405 Spring Cloud Config 路径穿越漏洞浅析

本文标题:浅析CVE-2020-5405

文章作者:xianyu123

发布时间:2021年03月11日 - 16:35

最后更新:2021年03月11日 - 16:40

原始链接:http://0clickjacking0.github.io/2021/03/11/浅析CVE-2020-5405/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------    本文结束  感谢您的阅读    -------------