Jdk7u21 反序列化漏洞Gadget原理
字数 1977 2025-08-29 08:31:53

JDK7u21 反序列化漏洞 Gadget 原理分析

0x00 漏洞概述

JDK7u21 反序列化漏洞是一个经典的 Java 反序列化安全问题,利用 Java 序列化机制中的特定类组合(Gadget Chain)实现远程代码执行。该漏洞的核心在于利用 Java 动态代理机制和哈希碰撞技巧,通过精心构造的序列化数据触发恶意代码执行。

0x01 前置知识

1. Java 动态代理机制

  • 动态代理类实现了 InvocationHandler 接口
  • 代理对象方法调用会被转发到 InvocationHandler 的 invoke 方法
  • 本例中使用的是 AnnotationInvocationHandler 作为 InvocationHandler

2. TemplatesImpl 类

  • 位于 javax.xml.transform 包中
  • 可以加载字节码并执行
  • 通过 getOutputProperties() 方法可以触发字节码执行

3. Java 序列化机制

  • 反序列化时会调用对象的 readObject 方法
  • HashSet/LinkedHashSet 反序列化时会重新计算哈希值并比较元素

0x02 Gadget 组成

整个利用链由以下几个关键部分组成:

  1. LinkedHashSet:作为反序列化的入口点
  2. TemplatesImpl 对象:包含恶意字节码
  3. 代理对象
    • 实现 Templates 接口
    • 使用 AnnotationInvocationHandler 作为 InvocationHandler
    • memberValues 设置为特殊构造的 Map

0x03 利用链详细分析

1. 构造恶意序列化数据

LinkedHashSet set = new LinkedHashSet();
// 1. 添加包含恶意代码的 TemplatesImpl 对象
set.add(templatesImpl); 

// 2. 创建代理对象
Map map = new HashMap();
map.put("f5a5a608", templatesImpl);
InvocationHandler handler = new AnnotationInvocationHandler(Templates.class, map);
Templates proxy = (Templates) Proxy.newProxyInstance(
    Templates.class.getClassLoader(),
    new Class[]{Templates.class},
    handler
);

// 3. 添加代理对象到集合
set.add(proxy);

2. 反序列化触发流程

  1. LinkedHashSet.readObject()

    • 反序列化时调用 HashSet 的 readObject 方法
    • 创建 HashMap 来存储 Set 中的元素
    • 调用 HashMap.put() 方法添加元素
  2. HashMap.put() 关键逻辑:

    for (Entry<K,V> e = table[i]; e != null; e = e.next) {
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            // ...
        }
    }
    
    • 需要满足两个条件:
      1. e.hash == hash:哈希值相等
      2. key.equals(k):对象相等或 equals 方法返回 true
  3. 哈希碰撞技巧

    • 代理对象的 hashCode() 会调用 AnnotationInvocationHandler.invoke()
    • invoke() 调用 hashCodeImpl() 方法:
      private int hashCodeImpl() {
          int result = 0;
          for (Map.Entry<String, Object> e : memberValues.entrySet()) {
              result += (127 * e.getKey().hashCode()) ^ memberValueHashCode(e.getValue());
          }
          return result;
      }
      
    • "f5a5a608".hashCode() 为 0,因此:
      result = (127 * 0) ^ templatesImpl.hashCode() = templatesImpl.hashCode()
      
    • 这样就实现了 proxy.hashCode() == templatesImpl.hashCode()
  4. equals 方法触发恶意代码

    • e.hash == hash 条件满足后,会调用 key.equals(k)
    • 代理对象的 equals 方法会调用 AnnotationInvocationHandler.invoke()
    • invoke() 调用 equalsImpl() 方法:
      private Boolean equalsImpl(Object proxy, Object other) {
          for (Method method : getMemberMethods()) {
              Object thisVal = method.invoke(proxy);
              Object otherVal = method.invoke(other);
              // ...
          }
      }
      
    • 这会触发 TemplatesImpl 的 getOutputProperties() 方法,执行恶意字节码

0x04 关键点总结

  1. AnnotationInvocationHandler 的核心作用

    • 作为动态代理的 InvocationHandler
    • 通过 invoke 方法控制代理对象的行为
    • 提供了 equalsImpl 和 hashCodeImpl 的关键实现
  2. 哈希碰撞技巧

    • 精心选择 "f5a5a608" 作为 key,其 hashCode() 为 0
    • 使得 proxy.hashCode() == templatesImpl.hashCode()
    • 绕过 HashMap.put() 的第一个条件检查
  3. 执行链触发点

    • LinkedHashSet/HashSet 反序列化
      → HashMap.put()
      → equals 比较
      → 代理对象方法调用
      → AnnotationInvocationHandler.invoke()
      → equalsImpl()
      → TemplatesImpl.getOutputProperties()
      → 恶意代码执行

0x05 防御措施

  1. 升级 JDK 到最新版本
  2. 使用安全管理器限制反序列化操作
  3. 使用白名单机制控制可反序列化的类
  4. 替换默认的序列化机制(如使用 JSON 等替代)

0x06 参考实现

完整 PoC 通常包含以下组件:

  1. 生成恶意字节码的工具(如 ASM、javassist)
  2. 构造 TemplatesImpl 对象的代码
  3. 创建代理对象和 AnnotationInvocationHandler 的代码
  4. 序列化 LinkedHashSet 的代码

注意:本文仅用于技术研究,请勿用于非法用途。

JDK7u21 反序列化漏洞 Gadget 原理分析 0x00 漏洞概述 JDK7u21 反序列化漏洞是一个经典的 Java 反序列化安全问题,利用 Java 序列化机制中的特定类组合(Gadget Chain)实现远程代码执行。该漏洞的核心在于利用 Java 动态代理机制和哈希碰撞技巧,通过精心构造的序列化数据触发恶意代码执行。 0x01 前置知识 1. Java 动态代理机制 动态代理类实现了 InvocationHandler 接口 代理对象方法调用会被转发到 InvocationHandler 的 invoke 方法 本例中使用的是 AnnotationInvocationHandler 作为 InvocationHandler 2. TemplatesImpl 类 位于 javax.xml.transform 包中 可以加载字节码并执行 通过 getOutputProperties() 方法可以触发字节码执行 3. Java 序列化机制 反序列化时会调用对象的 readObject 方法 HashSet/LinkedHashSet 反序列化时会重新计算哈希值并比较元素 0x02 Gadget 组成 整个利用链由以下几个关键部分组成: LinkedHashSet :作为反序列化的入口点 TemplatesImpl 对象 :包含恶意字节码 代理对象 : 实现 Templates 接口 使用 AnnotationInvocationHandler 作为 InvocationHandler memberValues 设置为特殊构造的 Map 0x03 利用链详细分析 1. 构造恶意序列化数据 2. 反序列化触发流程 LinkedHashSet.readObject() : 反序列化时调用 HashSet 的 readObject 方法 创建 HashMap 来存储 Set 中的元素 调用 HashMap.put() 方法添加元素 HashMap.put() 关键逻辑: 需要满足两个条件: e.hash == hash :哈希值相等 key.equals(k) :对象相等或 equals 方法返回 true 哈希碰撞技巧 : 代理对象的 hashCode() 会调用 AnnotationInvocationHandler.invoke() invoke() 调用 hashCodeImpl() 方法: "f5a5a608".hashCode() 为 0,因此: 这样就实现了 proxy.hashCode() == templatesImpl.hashCode() equals 方法触发恶意代码 : 当 e.hash == hash 条件满足后,会调用 key.equals(k) 代理对象的 equals 方法会调用 AnnotationInvocationHandler.invoke() invoke() 调用 equalsImpl() 方法: 这会触发 TemplatesImpl 的 getOutputProperties() 方法,执行恶意字节码 0x04 关键点总结 AnnotationInvocationHandler 的核心作用 : 作为动态代理的 InvocationHandler 通过 invoke 方法控制代理对象的行为 提供了 equalsImpl 和 hashCodeImpl 的关键实现 哈希碰撞技巧 : 精心选择 "f5a5a608" 作为 key,其 hashCode() 为 0 使得 proxy.hashCode() == templatesImpl.hashCode() 绕过 HashMap.put() 的第一个条件检查 执行链触发点 : LinkedHashSet/HashSet 反序列化 → HashMap.put() → equals 比较 → 代理对象方法调用 → AnnotationInvocationHandler.invoke() → equalsImpl() → TemplatesImpl.getOutputProperties() → 恶意代码执行 0x05 防御措施 升级 JDK 到最新版本 使用安全管理器限制反序列化操作 使用白名单机制控制可反序列化的类 替换默认的序列化机制(如使用 JSON 等替代) 0x06 参考实现 完整 PoC 通常包含以下组件: 生成恶意字节码的工具(如 ASM、javassist) 构造 TemplatesImpl 对象的代码 创建代理对象和 AnnotationInvocationHandler 的代码 序列化 LinkedHashSet 的代码 注意:本文仅用于技术研究,请勿用于非法用途。