java反序列化预备全知
字数 1709 2025-08-25 22:58:35

Java反序列化漏洞全面解析

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

1. Java IO流与序列化关系

Java的IO流分为:

  • 文件IO流(FileInput/OutputStream):用于文件输入输出
  • 对象IO流(ObjectInput/OutputStream):用于对象输入输出

序列化过程实质上是将对象通过对象输出流(ObjectOutputStream)转换为字节流输出到文件或其他存储介质中。

2. 序列化/反序列化示例代码

序列化示例:

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);

反序列化示例:

ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();

3. 序列化要求

类必须实现Serializable接口:

public class Person implements Serializable {
    private String name;
    private int age;
    // 构造方法和其他方法...
}

4. PHP与Java反序列化区别

特性 PHP Java
API serialize/unserialize 需自定义序列化过程
触发方法 __wakeup readObject
设计目的 初始化对象 还原完整对象

二、Java反射机制

1. 反射基础

反射允许程序在运行时获取类的信息并操作类或对象,无需在编译时知道具体类。

2. 反射常用方法

  • Class.forName(classname):获取类的Class对象
  • Class.newInstance():实例化对象(调用无参构造)
  • Class.getMethod(method name, arg types):获取方法
  • Method.invoke(obj, args):调用方法

3. 获取Class对象的三种方式

  1. Class.forName("完整类名")
  2. obj.getClass()
  3. 类名.class

4. 通过反射执行命令

Runtime执行命令:

Class clazz = Class.forName("java.lang.Runtime");
clazz.getMethod("exec", String.class)
     .invoke(clazz.getMethod("getRuntime").invoke(clazz), "calc.exe");

ProcessBuilder执行命令:

Class clazz = Class.forName("java.lang.ProcessBuilder");
((ProcessBuilder)clazz.getConstructor(List.class)
     .newInstance(Arrays.asList("calc.exe"))).start();

5. 访问私有方法

使用getDeclaredMethod/getDeclaredConstructor配合setAccessible(true)

Constructor m = clazz.getDeclaredConstructor();
m.setAccessible(true);
clazz.getMethod("exec",String.class).invoke(m.newInstance(), "calc.exe");

三、反序列化漏洞利用

1. ysoserial工具

ysoserial是一个集成了多种Java反序列化利用链的工具,可以生成各种payload。

基本使用:

java -jar ysoserial.jar CommonsCollections1 "command"

2. URLDNS利用链分析

URLDNS是简单的反序列化利用链,用于验证反序列化漏洞存在。

利用原理:

  1. 创建HashMap并将URL对象作为key
  2. 反序列化时HashMap的readObject方法会调用key的hashCode
  3. URL的hashCode会触发DNS查询

关键代码:

HashMap ht = new HashMap();
URL u = new URL(null, url, handler);
ht.put(u, url);
Reflections.setFieldValue(u, "hashCode", -1); // 强制重新计算hashCode

3. 调用链分析

  1. HashMap.readObject()
  2. HashMap.putVal()
  3. HashMap.hash()
  4. URL.hashCode()
  5. URLStreamHandler.hashCode()
  6. URLStreamHandler.getHostAddress()
  7. InetAddress.getByName() → 触发DNS查询

四、代理模式与动态代理

1. 静态代理

角色:

  • 抽象角色(接口):如Rent
  • 真实角色:如Host
  • 代理角色:如Proxy
  • 客户:使用代理的代码

示例:

public class Proxy implements Rent {
    private Host host;
    public void rent() {
        host.rent();
        seeHouse(); // 额外功能
    }
}

2. 动态代理

核心类:

  • java.lang.reflect.Proxy
  • java.lang.reflect.InvocationHandler

实现步骤:

  1. 创建InvocationHandler实现类
  2. 使用Proxy.newProxyInstance创建代理对象
  3. 通过代理对象调用方法

示例:

public class ProxyInvocationHandler implements InvocationHandler {
    private Object target;
    
    public Object getProxy() {
        return Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            this);
    }
    
    public Object invoke(Object proxy, Method method, Object[] args) {
        // 前置处理
        Object result = method.invoke(target, args);
        // 后置处理
        return result;
    }
}

五、关键安全要点总结

  1. 反序列化入口点:任何接受外部序列化数据的地方都可能成为入口

  2. 危险方法readObject是主要触发点,但也要注意readResolve等方法

  3. 利用链组成:通常需要多个类的组合才能构成完整利用链

  4. 防御措施

    • 使用白名单验证反序列化的类
    • 使用ObjectInputFilter限制反序列化类
    • 升级存在漏洞的库
  5. 工具使用:ysoserial是研究和验证反序列化漏洞的重要工具

通过深入理解这些知识点,可以更好地分析Java反序列化漏洞并开发相应的防御措施。

Java反序列化漏洞全面解析 一、Java序列化与反序列化基础 1. Java IO流与序列化关系 Java的IO流分为: 文件IO流(FileInput/OutputStream):用于文件输入输出 对象IO流(ObjectInput/OutputStream):用于对象输入输出 序列化过程实质上是将对象通过对象输出流(ObjectOutputStream)转换为字节流输出到文件或其他存储介质中。 2. 序列化/反序列化示例代码 序列化示例: 反序列化示例: 3. 序列化要求 类必须实现 Serializable 接口: 4. PHP与Java反序列化区别 | 特性 | PHP | Java | |------|-----|------| | API | serialize/unserialize | 需自定义序列化过程 | | 触发方法 | __ wakeup | readObject | | 设计目的 | 初始化对象 | 还原完整对象 | 二、Java反射机制 1. 反射基础 反射允许程序在运行时获取类的信息并操作类或对象,无需在编译时知道具体类。 2. 反射常用方法 Class.forName(classname) :获取类的Class对象 Class.newInstance() :实例化对象(调用无参构造) Class.getMethod(method name, arg types) :获取方法 Method.invoke(obj, args) :调用方法 3. 获取Class对象的三种方式 Class.forName("完整类名") obj.getClass() 类名.class 4. 通过反射执行命令 Runtime执行命令: ProcessBuilder执行命令: 5. 访问私有方法 使用 getDeclaredMethod / getDeclaredConstructor 配合 setAccessible(true) : 三、反序列化漏洞利用 1. ysoserial工具 ysoserial是一个集成了多种Java反序列化利用链的工具,可以生成各种payload。 基本使用: 2. URLDNS利用链分析 URLDNS是简单的反序列化利用链,用于验证反序列化漏洞存在。 利用原理: 创建HashMap并将URL对象作为key 反序列化时HashMap的readObject方法会调用key的hashCode URL的hashCode会触发DNS查询 关键代码: 3. 调用链分析 HashMap.readObject() HashMap.putVal() HashMap.hash() URL.hashCode() URLStreamHandler.hashCode() URLStreamHandler.getHostAddress() InetAddress.getByName() → 触发DNS查询 四、代理模式与动态代理 1. 静态代理 角色: 抽象角色(接口):如Rent 真实角色:如Host 代理角色:如Proxy 客户:使用代理的代码 示例: 2. 动态代理 核心类: java.lang.reflect.Proxy java.lang.reflect.InvocationHandler 实现步骤: 创建 InvocationHandler 实现类 使用 Proxy.newProxyInstance 创建代理对象 通过代理对象调用方法 示例: 五、关键安全要点总结 反序列化入口点 :任何接受外部序列化数据的地方都可能成为入口 危险方法 : readObject 是主要触发点,但也要注意 readResolve 等方法 利用链组成 :通常需要多个类的组合才能构成完整利用链 防御措施 : 使用白名单验证反序列化的类 使用 ObjectInputFilter 限制反序列化类 升级存在漏洞的库 工具使用 :ysoserial是研究和验证反序列化漏洞的重要工具 通过深入理解这些知识点,可以更好地分析Java反序列化漏洞并开发相应的防御措施。