Java 反序列化过程深究
字数 1138 2025-08-26 22:11:35

Java 反序列化过程深度解析

0x01 反序列化漏洞基本原理

Java反序列化漏洞与PHP反序列化漏洞类似,其核心在于:

  • 开发者重写readObject方法时插入了漏洞代码
  • 在反序列化过程中触发这些漏洞代码
  • 类似于PHP中在__destruct等魔术函数中触发漏洞代码

典型漏洞触发流程:

FileInputStream fis = new FileInputStream("calc.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
Object obj = ois.readObject();  // 触发点

0x02 反序列化调用链深度分析

关键调用流程

  1. 初始入口ObjectInputStream.readObject()

    • 调用readObject0(false)方法
  2. 对象类型判断readObject0

    • 当遇到TC_OBJECT(值为115)时
    • 调用readOrdinaryObject(unshared)
  3. 普通对象处理readOrdinaryObject

    • 关键分支:
      if (desc.isExternalizable()) {
          readExternalData((Externalizable) obj, desc);
      } else {
          readSerialData(obj, desc);  // 主要进入这里
      }
      
  4. 序列化数据处理readSerialData

    • 核心判断逻辑:
      if (slotDesc.hasReadObjectMethod()) {
          slotDesc.invokeReadObject(obj, this);  // 重写readObject时进入
      } else {
          defaultReadFields(obj, slotDesc);  // 未重写时进入
      }
      

重写与未重写readObject的区别

  1. 重写readObject的情况

    • slotDesc.hasReadObjectMethod()返回true
    • 进入invokeReadObject方法
    • 通过反射机制调用自定义的readObject方法:
      readObjectMethod.invoke(obj, new Object[]{ in });
      
  2. 未重写readObject的情况

    • slotDesc.hasReadObjectMethod()返回false
    • 进入defaultReadFields方法
    • 使用默认的反序列化流程

关键判断点分析

hasReadObjectMethod()方法实现:

return (readObjectMethod != null);

调试观察:

  • 未重写readObject时:readObjectMethod为null
  • 重写readObject时:readObjectMethod指向自定义方法

0x03 技术总结与要点

  1. 核心流程

    readObject() → readObject0() → readOrdinaryObject() → readSerialData()
                   ↘ hasReadObjectMethod()? → invokeReadObject()/defaultReadFields()
    
  2. 关键区别

    • 是否重写readObject决定了最终进入哪个处理分支
    • 重写时通过反射机制调用自定义逻辑
    • 未重写时使用标准反序列化流程
  3. 安全启示

    • 重写readObject方法时要特别注意安全性
    • 避免在readObject中执行危险操作
    • 反序列化漏洞利用的核心在于控制readObject的执行流程
  4. 防御建议

    • 使用白名单验证反序列化的类
    • 考虑使用替代方案如JSON、XML等更安全的序列化格式
    • 对不可信的反序列化数据实施严格校验

附录:调试技巧

  1. 关键断点位置:

    • 自定义readObject方法入口
    • hasReadObjectMethod()返回处
    • invokeReadObject调用处
  2. 观察变量:

    • readObjectMethod的值变化
    • slotDesc的内容
    • 调用栈信息

通过深入理解这些底层机制,可以更好地分析Java反序列化漏洞的原理和利用方式,也能更有效地进行安全防护。

Java 反序列化过程深度解析 0x01 反序列化漏洞基本原理 Java反序列化漏洞与PHP反序列化漏洞类似,其核心在于: 开发者重写 readObject 方法时插入了漏洞代码 在反序列化过程中触发这些漏洞代码 类似于PHP中在 __destruct 等魔术函数中触发漏洞代码 典型漏洞触发流程: 0x02 反序列化调用链深度分析 关键调用流程 初始入口 : ObjectInputStream.readObject() 调用 readObject0(false) 方法 对象类型判断 : readObject0 当遇到 TC_OBJECT (值为115)时 调用 readOrdinaryObject(unshared) 普通对象处理 : readOrdinaryObject 关键分支: 序列化数据处理 : readSerialData 核心判断逻辑: 重写与未重写readObject的区别 重写readObject的情况 : slotDesc.hasReadObjectMethod() 返回true 进入 invokeReadObject 方法 通过反射机制调用自定义的readObject方法: 未重写readObject的情况 : slotDesc.hasReadObjectMethod() 返回false 进入 defaultReadFields 方法 使用默认的反序列化流程 关键判断点分析 hasReadObjectMethod() 方法实现: 调试观察: 未重写readObject时: readObjectMethod 为null 重写readObject时: readObjectMethod 指向自定义方法 0x03 技术总结与要点 核心流程 : 关键区别 : 是否重写readObject决定了最终进入哪个处理分支 重写时通过反射机制调用自定义逻辑 未重写时使用标准反序列化流程 安全启示 : 重写readObject方法时要特别注意安全性 避免在readObject中执行危险操作 反序列化漏洞利用的核心在于控制readObject的执行流程 防御建议 : 使用白名单验证反序列化的类 考虑使用替代方案如JSON、XML等更安全的序列化格式 对不可信的反序列化数据实施严格校验 附录:调试技巧 关键断点位置: 自定义readObject方法入口 hasReadObjectMethod() 返回处 invokeReadObject 调用处 观察变量: readObjectMethod 的值变化 slotDesc 的内容 调用栈信息 通过深入理解这些底层机制,可以更好地分析Java反序列化漏洞的原理和利用方式,也能更有效地进行安全防护。