14-9
约 914 字大约 3 分钟
2025-11-02
反序列化除了readObject 还有什么触发点
1. readResolve() 和 writeReplace()
这两个方法主要用于控制对象的序列化和反序列化过程,它们可以用来触发攻击链
- 原理:
writeReplace():这个方法在对象被序列化时调用。它允许开发者用另一个对象来替换即将被序列化的对象。攻击者可以利用这个方法,让一个无害的对象在序列化时被替换成一个恶意的对象readResolve():这个方法在对象被反序列化后调用。它允许开发者用另一个对象来替换刚刚反序列化得到的对象。攻击者可以利用这个方法,在反序列化时触发攻击链,例如调用一个可以触发 JNDI 注入的类
- 攻击链举例:
- 攻击者构造一个恶意的对象,这个对象的
readResolve()方法被重写,用于返回一个可以触发 JNDI 注入的JdbcRowSetImpl对象 - 当应用程序反序列化这个对象时,
readResolve()方法会被自动调用,从而将攻击链的控制权转移到JdbcRowSetImpl上,最终导致 RCE
- 攻击者构造一个恶意的对象,这个对象的
2. finalize()
finalize() 方法是一个“魔法”方法,它在对象被垃圾回收时调用
- 原理:在某些情况下,当一个对象被反序列化后,如果它不再被引用,Java 虚拟机(JVM)可能会将其放入垃圾回收队列。在垃圾回收前,JVM 会调用对象的
finalize()方法 - 攻击链举例:
- 攻击者构造一个恶意的对象,这个对象的
finalize()方法被重写,用于执行系统命令 - 当应用程序反序列化并丢弃这个对象时,如果垃圾回收被触发,
finalize()方法就会被调用,从而执行恶意代码
- 攻击者构造一个恶意的对象,这个对象的
- 局限性:这种方法不常见,因为它不可预测。你无法控制垃圾回收何时发生,甚至无法保证它一定会发生。因此,它不是一个可靠的漏洞利用方式,但其原理是成立的
3. toString()
在某些情况下,某些类在反序列化时会调用其内部对象的 toString() 方法
- 原理:当一个对象被反序列化时,如果它被放入到一个需要调用
toString()的上下文中(例如,在日志记录中),那么toString()方法就会被自动调用 - 攻击链举例:
- 攻击者找到一个类,它的
toString()方法可以间接触发命令执行 - 攻击者构造一个恶意的序列化对象,这个对象包含上面找到的类
- 当应用程序反序列化这个对象,并将其放入一个需要调用
toString()的上下文中时,就会触发攻击链 - 典型的例子是
BadAttributeValueExpException这个类,它的readObject()方法会调用内部对象的toString(),从而可以触发InvokerTransformer的攻击链
- 攻击者找到一个类,它的
4. hashCode() 和 equals()
这两个方法通常用于哈希表(HashMap、HashSet)等集合类中
- 原理:当一个哈希表被反序列化时,它需要重新构建内部的数据结构。在这个过程中,它会调用其存储的对象的
hashCode()和equals()方法 - 攻击链举例:
- 攻击者构造一个恶意的哈希表,并向其中放入一个可以被利用的对象
- 当这个哈希表被反序列化时,它的
hashCode()方法会被调用 - 攻击者可以利用一些特殊的类(例如
HashSet),让其在hashCode()方法中调用其他恶意对象的transform()方法,从而触发攻击链