漏洞信息
Spring Cloud Config 程序内部在处理客户端传入的资源时存在自动将 (_) 转换为 / 的隐藏转换,当 profile
设置为 native
时,则会导致服务端路径穿越,因此攻击者可以利用此机制来穿越到其它路径,读取任意文件。
影响范围
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
代码目录,找到下列文件,修改其中的内容:
```
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-active
为native
profiles:
active: native
设置search-locations
为任意文件夹。
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 环境变量):
cd spring-cloud-config-server
../mvnw spring-boot:run
项目启动成功后,通过浏览器即可访问。
http://127.0.0.1:9999/
漏洞利用
POC
```
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.conf
和resolv.conf
,这段代码不难理解
然后上面的返回的值resolv-a.conf
和resolv.conf
分别迭代。然后跟进org/springframework/cloud/config/server/resource/GenericResourceRepository.java
的第70行isInvalidPath
方法,这里主要是检测path
中是否包含一些字符的,比如限制了WEB-INF
、META-INF
等
然后接着跟进org/springframework/cloud/config/server/resource/GenericResourceRepository.java
的第70行isInvalidEncodedPath
方法,这里主要是检测是否为有效url编码的,影响也不是很大
然后就根据反射读取文件了
java
Resource file = this.resourceLoader.getResource(location)
.createRelative(local);
if (file.exists() && file.isReadable()) {
return file;
参考链接
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论