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

admin 2020年9月30日14:24:26评论978 views字数 5611阅读18分42秒阅读模式

更多全球网络安全资讯尽在邑安全

简介

Spring Cloud Config,为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环境提供了一个中心化的外部配置。

Spring Cloud Config分为服务端和客户端两部分:

  • 服务端,也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密/解密信息等访问接口。

  • 客户端,则是通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息,配置服务器默认采用git来存储配置信息,这样就有助于对环境配置进行版本管理,并且可以通过git客户端工具来方便的管理和访问配置内容。

CVE-2020-5405,Spring Cloud Config允许应用程序通过spring-cloud-config-server模块使用任意配置文件。 恶意用户或攻击者可以发送精心构造的包含(_)的请求进行目录穿越攻击。

影响版本:

  • versions 2.2.x -- 2.2.2

  • versions 2.1.x -- 2.1.7

  • 停止更新支持的更早版本

复现

下载官方Spring Cloud Config,具体版本versions 2.1.5.RELEASE,下载地址为:

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

导入IDEA项目

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

修改配置文件src/main/resources/configserver.yml

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/rai4over/Desktop/spring-cloud-config-2.1.5/config-repo

server:
port: 8888
management:
context_path: /admin

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

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

POC

http://127.0.0.1:8888/1/1/..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)etc/passwd

URL编码变形

http://127.0.0.1:8888/1/1/..%28_%29..%28_%29..%28_%29..%28_%29..%28_%29..%28_%29..%28_%29..%28_%29etc/passwd

结果

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

目录穿越成功,问题出现在Spring Cloud Config服务端,简单的看是将/替换成为(_)

分析

查看官方文档:

https://cloud.spring.io/spring-cloud-static/spring-cloud.html#_serving_plain_text

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

org.springframework.cloud.config.server.resource.ResourceController#retrieve(java.lang.String, java.lang.String, java.lang.String, org.springframework.web.context.request.ServletWebRequest, boolean)

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

解析下路由的结构

  • name,应仓库名称。

  • profile,应配置文件环境。

  • labelgit分支名。

  • **,通配子目录。

打好断点,查看被解析后的关键变量:

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

request为该次请求对象, nameprofile对应解析为1label对应解析为..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)etc**对应通过getFilePath函数解析为passwd,跟进retrieve函数。

org.springframework.cloud.config.server.resource.ResourceController#retrieve(org.springframework.web.context.request.ServletWebRequest, java.lang.String, java.lang.String, java.lang.String, java.lang.String, boolean)

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

先跟进处理nameresolveName函数

org.springframework.cloud.config.server.resource.ResourceController#resolveName

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

替换name中存在的(_),name经过处理后不发生变化,继续跟进resolveLabel

org.springframework.cloud.config.server.resource.ResourceController#resolveLabel

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

..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)etc经过替换之后变为../../../../../../../../../etc,然后将几个处理过的变量传入并跟进this.resourceRepository.findOne函数。

org.springframework.cloud.config.server.resource.GenericResourceRepository#findOne

@Override
public synchronized Resource findOne(String application, String profile, String label,
String path) {

if (StringUtils.hasText(path)) {
String[] locations = this.service.getLocations(application, profile, label)
.getLocations();
try {
for (int i = locations.length; i-- > 0;) {
String location = locations[i];
for (String local : getProfilePaths(profile, path)) {
if (!isInvalidPath(local) && !isInvalidEncodedPath(local)) {
Resource file = this.resourceLoader.getResource(location)
.createRelative(local);
if (file.exists() && file.isReadable()) {
return file;
}
}
}
}
}
catch (IOException e) {
throw new NoSuchResourceException(
"Error : " + path + ". (" + e.getMessage() + ")");
}
}
throw new NoSuchResourceException("Not found: " + path);
}

首先通过this.service.getLocations获取对应的file协议的绝对路径地址且为有两个元素的素组

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

接着通过for循环对locations数组元素进行遍历,与POC相关的是第一号元素,取出后传入getProfilePaths函数。

org.springframework.cloud.config.server.resource.GenericResourceRepository#getProfilePaths

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

创建了一个集合包含两个元素,首先包含原本的passwd,还有第二个根据file + "-" + profile + ext拼接而成的元素,此时profile为1,ext为空

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

然后对这个集合再次遍历,取出元素后通过sInvalidPathisInvalidEncodedPath进行安全检查,关注1号元素passwd即可。

org.springframework.cloud.config.server.resource.GenericResourceRepository#isInvalidPath

protected boolean isInvalidPath(String path) {
if (path.contains("WEB-INF") || path.contains("META-INF")) {
if (logger.isWarnEnabled()) {
logger.warn("Path with "WEB-INF" or "META-INF": [" + path + "]");
}
return true;
}
if (path.contains(":/")) {
String relativePath = (path.charAt(0) == '/' ? path.substring(1) : path);
if (ResourceUtils.isUrl(relativePath) || relativePath.startsWith("url:")) {
if (logger.isWarnEnabled()) {
logger.warn(
"Path represents URL or has "url:" prefix: [" + path + "]");
}
return true;
}
}
if (path.contains("..") && StringUtils.cleanPath(path).contains("../")) {
if (logger.isWarnEnabled()) {
logger.warn("Path contains "../" after call to StringUtils#cleanPath: ["
+ path + "]");
}
return true;
}
return false;
}

org.springframework.cloud.config.server.resource.GenericResourceRepository#isInvalidEncodedPath

private boolean isInvalidEncodedPath(String path) {
if (path.contains("%")) {
try {
// Use URLDecoder (vs UriUtils) to preserve potentially decoded UTF-8
// chars
String decodedPath = URLDecoder.decode(path, "UTF-8");
if (isInvalidPath(decodedPath)) {
return true;
}
decodedPath = processPath(decodedPath);
if (isInvalidPath(decodedPath)) {
return true;
}
}
catch (IllegalArgumentException | UnsupportedEncodingException ex) {
// Should never happen...
}
}
return false;
}

其实是对以前老洞的修复方式,进行了WEB-INF..、解码等安全校验,输入为passwd无压力通过两个函数校验。

this.resourceLoaderAnnotationConfigServletWebServerApplicationContext类加载器,继续通过this.resourceLoader.getResource(location).createRelative(local);加载资源,最终file为:

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

最终作为结果进行层层返回,完成任意文件读取。

补丁

git地址

https://github.com/spring-cloud/spring-cloud-config/commit/651f458919c40ef9a5e93e7d76bf98575910fad0

org.springframework.cloud.config.server.resource.GenericResourceRepository#isInvalidLocation

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

findOne函数新增使用isInvalidLocation函数对..的检测。

转自先知社区

欢迎收藏并分享朋友圈,让五邑人网络更安全

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

欢迎扫描关注我们,及时了解最新安全动态、学习最潮流的安全姿势!


推荐文章

1

新永恒之蓝?微软SMBv3高危漏洞(CVE-2020-0796)分析复现

2

重大漏洞预警:ubuntu最新版本存在本地提权漏洞(已有EXP) 




  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2020年9月30日14:24:26
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CVE-2020-5405 Spring Cloud Config 路径穿越漏洞浅析http://cn-sec.com/archives/147223.html

发表评论

匿名网友 填写信息