复现
idea创建一个spring项目,然后pom.xml中加入
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
配置application.properties
server.port=8888
spring.cloud.config.server.git.uri=https://github.com/SukaraLin/awesome-cve-poc.git
然后访问
http://127.0.0.1:8888/aaa/bbb/master/..%252F..%252F..%252F..%252F..%252F..%252Fwindows/win.ini
分析
Spring Cloud Config Server是Spring为了分布式管理的一个组件,在Server端中负责存储配置,Client可以通过http的形式获取配置值。payload对应的路由存在于org.springframework.cloud.config.server.resource.ResourceController#retrieve()
中,其代码
@RequestMapping({"/{name}/{profile}/{label}/**"})
public String retrieve(@PathVariable String name, @PathVariable String profile, @PathVariable String label, HttpServletRequest request, @RequestParam(defaultValue = "true") boolean resolvePlaceholders) throws IOException {
String path = this.getFilePath(request, name, profile, label);
return this.retrieve(name, profile, label, path, resolvePlaceholders);
}
{name}/{profile}/{label}
:name对应仓库名,profile对应配置文件,label为git分支名,一般上都有一个master分支。实际测试中name、profile值无所谓,但是label分支名必须存在。调试跟进getFilePath
这边已经把%25
urldecode为%
了,继续跟retrieve(),这边path传入的是我们的payload
继续跟下findOne,位于org.springframework.cloud.config.server.resource.GenericResourceRepository#findOne
locations目录file:/C:/Users/icu/AppData/Local/Temp/config-repo-6608031716294156148/
是配置文件中git仓库被clone的临时位置,然后拼接../
造成跨目录文件读取。
修复
通过判断是否存在%
来urldecode,然后匹配../
、..
、/
等特殊字符。