CVE-2020-5405 Spring Cloud Config Server 目录穿越 – 作者:斗象智能安全平台

事件背景

Spring Cloud Config为分布式系统的外部配置提供客户端的服务端的支持。使用了它,开发人员就可以在一个中心仓库管理应用程序在所有环境中的外部配置。2020-02-26 Spring 收到漏洞报告, Spring Cloud Config Server 存在目录穿越漏洞。

时间线

2020-02-26 Spring 收到漏洞报告, Spring Cloud Config Server 存在目录穿越漏洞
2020-03-03 Spring Cloud Config Server 更新 2.1.7 版本
2020-03-04 Spring Cloud Config Server 更新 2.2.2 版本
2020-03-06 斗象应急响应团队分析出漏洞POC

漏洞挖掘

根据描述该漏洞为目录穿越 2.2.0-2.2.1,2.1.0-2.1.6 都受到影响, 所以这里直接下载2.2.1和2.2.2的源码包进行对比

https://github.com/spring-cloud/spring-cloud-config/releases

解压后直接使用idea Ctrl+D 进行对比

很多开源项目都会在test文件中写入本次更新涉及的漏洞点
比如这次 spring-cloud-config-2.2.2.RELEASE/spring-cloud-config-client/src/test/java/org/springframework/cloud/config/environment/EnvironmentTests.java

显而易见的这个漏洞是用 (_) 来代替 / 进行目录穿越

搭建环境

这里启动 2.2.1环境, 使用idea 打开 (maven项目)
\spring-cloud-config-2.2.1.RELEASE\spring-cloud-config-server
这里如果速度慢可以修改成阿里源,启动成功后访问
http://127.0.0.1:8888/foo/default/master/test.json

补丁对比

根据上一个目录穿越漏洞

Spring Cloud Config Server 路径穿越与任意文件读取漏洞分析 – 【CVE-2019-3799】 – 先知社区
https://xz.aliyun.com/t/4844

这里可以构造一个路径进行尝试(看看报错)

/foo/default/master/..(_)..(_)..(_)..(_)etc(_)passwd

效果不佳,从文中可知请求格式如下

GET /{name}/{profile}/{label}/{path}

继续看对应实现源码

org/springframework/cloud/config/server/resource/ResourceController.java

这里可以知道请求的格式,这里决定了POC的基本结构

继续对比可以可以看出, (_) 会在 [name/label] 时被处理成 /

再根据新增的测试文件
spring-cloud-config-2.2.2.RELEASE/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/resource/GenericResourceRepositoryTests.java

基本可以构造出来如下格式

由于label中可以解析(_)
图片[1]-CVE-2020-5405 Spring Cloud Config Server 目录穿越 – 作者:斗象智能安全平台-安全小百科
根据提示 “Cannot clone or checkout repository” 以及 代码中的
this.nativeRepository.setSearchLocations("file:./src/test/resources/test/local");
这里考虑可能是得采用本地配置文件方式
玩转Spring Cloud之配置中心(config server &config client) – 梦在旅途 – 博客园
https://www.cnblogs.com/zuowj/p/10432445.html

更改配置文件为

configserver.yml

info:
  component: Config Server
spring:
  application:
    name: configserver
  autoconfigure.exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
  profiles:
    active: native
  jmx:
    default_domain: cloud.config.server
  cloud:
    config:
      server:
        #如下是本地文件配置
        native:
          search-locations: classpath:/configs #配置文件存放的目录

server:
  port: 8888
management:
  context_path: /admin

然后再resources目录下新建文件夹 configs
随便放个配置文件

configclient-dev.properties

--configclient-dev.properties内容:

demo-config-profile-env=dev-native
zuowenjun.site=http://www.zuowenjun.cn,http://zuowj.cnblogs.com--20190227
zuowenjun.skills=.net,java,html,js,css,sql,python,vb--20190227
zuowenjun.motto=Learning is endless; Opportunity is for the prepared mind;--20190227

访问 http://127.0.0.1:8888/configclient/dev

当native本地方式启动时, {label}无需指定(有用但是对这个漏洞没有影响), 所以这里可以采取{label}可以生效的方式git后端配置的请求格式进行访问

Spring Cloud Config Server 启动后, GIT仓库中的配置文件会被自动转换成当前项目的web api,若需访问查看远程配置数据可以参照以下的规则:
/{application}/{profile}[/{label}]
[/{label}]/{application}-{profile}{.yml|.properties|.json}

规则简单说明:{application}=配置消费方应用名称(即:config client的项目名,通俗讲:就是谁用这个配置就是谁的名字)

{profile}=配置环境(如:dev开发环境,test测试环境,prod生产环境)

{label}=仓库分支名(git或svn方式指定,native本地方式无需指定)

.yml|.properties|.json表示指定的响应返回格式,{}表示必需,[]表示可选,|表示或的关系

或者参考
https://cloud.spring.io/spring-cloud-static/spring-cloud-config/2.2.2.RELEASE/reference/html/#_placeholders_in_git_uri

https://www.cnblogs.com/zuowj/p/10432445.html

当配置文件中的 search-locations 修改为 file:///c:/ 时,即可在在根目录进行文件读取

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:///C:\TCC\Spring-cloud-config-server\spring-cloud-config-2.2.1.RELEASE\spring-cloud-config-server\src\main\resources\configs #配置文件存放的目录
server:
  port: 8888
management:
  context_path: /admin

断点分析

通过打断点,我们可以更清晰的看到漏洞的成因

首先根据路由格式,进入 org.springframework.cloud.config.server.resource.ResourceController#retrieve(java.lang.String, java.lang.String, java.lang.String, org.springframework.web.context.request.ServletWebRequest, boolean) 函数中

其中参数分别为我们传入的

name = blah

profile = local

label = 马赛克

path = Windows/win.ini

然后进入org.springframework.cloud.config.server.resource.GenericResourceRepository#findOne函数

图片[2]-CVE-2020-5405 Spring Cloud Config Server 目录穿越 – 作者:斗象智能安全平台-安全小百科

这里会对 Win[-{label}].ini 也就是 win-label.ini win.ini 在对应目录搜索,

也就是 {search-locations} + {label} 即

file:///C:\TCC\Spring-cloud-config-server\spring-cloud-config-2.2.1.RELEASE\spring-cloud-config-server\src\main\resources\configs/../../../../../../../../../../../../../../../../../../../../../../../../../../../../..//

也就是进入了C盘根目录, 即可读取文件

无后缀文件读取

但是因为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)中存在对于后缀的匹配导致没有后缀的文件会读取失败

46对应ascii码的.

当没有获取到 “.” 的时候返回 null 导致后续 null.toLowerCase() 报错异常退出

但是在windows中.当文件名后面加空格或者点号.也可以正确处理

Naming Files, Paths, and Namespaces – Win32 apps | Microsoft Docs
https://docs.microsoft.com/zh-cn/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN

Do not end a file or directory name with a space or a period. Although the underlying file system may support such names, the Windows shell and user interface does not. However, it is acceptable to specify a period as the first character of a name. For example, ".temp".

所以在Windows中,我们可以使用文件名加点.的方式进行无后缀文件读取

漏洞产生根本原因

org.springframework.cloud.config.server.environment.NativeEnvironmentRepository#getLocations
这里产生了直接拼接{label}的行为

所以这里双重url编码/%252f还是可以用,因为最后拼接成的路径是URL类,支持%2f

图片[3]-CVE-2020-5405 Spring Cloud Config Server 目录穿越 – 作者:斗象智能安全平台-安全小百科
使用 %252f 请求

Spring修复方式

修复点在
spring-cloud-config-2.2.2.RELEASE/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/resource/GenericResourceRepository.java

org.springframework.cloud.config.server.resource.GenericResourceRepository#findOne函数加入了对路径的判断

org.springframework.cloud.config.server.resource.GenericResourceRepository#isInvalidEncodedLocation 会先对路径进行url解码

org.springframework.cloud.config.server.resource.GenericResourceRepository#isInvalidLocation 然后检测是否包含 ..

检测方法

Windows 可以检测 C:/Windows/win.ini
Linux 可以检测 /etc/resolv.conf
(这里测试Windows上file协议无法访问其他盘,如果Spring Cloud Config Server 搜索路径指定在 classpath,可以尝试读取META-INF/下面的文件,这里是个检测难点)

作者:斗象能力中心 TCC – 小胖虎

来源:freebuf.com 2020-03-07 19:00:34 by: 斗象智能安全平台

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论