Java序列化基础-URLDNS利用
字数 1584 2025-08-19 12:42:34

Java反序列化漏洞基础与URLDNS利用链分析

0x01 序列化基础概念

序列化定义

序列化是指将一个对象转换为字节序列的过程,包含:

  • 对象的数据
  • 对象的类型
  • 对象中存储的属性等信息

Java序列化实现

  • 通过实现java.io.Serializable接口
  • 只有实现了Serializable接口的对象才能被序列化
  • 注意:序列化的是对象而不是类

序列化限制

  1. 静态属性不能序列化
    • 原因:静态变量属于类,在类加载时获取内存空间存储在静态区
    • 访问方式:应直接通过类名访问而非对象引用
  2. Transient瞬态属性不能序列化

序列化用途

  1. 数据持久化:将数据永久保存在硬盘上
    • 通过输出流将内存中的数据保存在文件中
  2. 远程通信:在网络上传送对象的字节序列

反序列化

  • 序列化的逆过程,将字节流转换回对象
  • 过程:开启输入流通道,Java从字节流中的信息重构对象并重新加载到内存

0x02 反序列化漏洞原理

漏洞产生原因

  • 服务端反序列化数据时,客户端传递类的readObject方法中的代码会自动执行
  • 本质:攻击者利用服务器反序列化过程执行恶意代码

反序列化利用形式

  1. 入口类的readObject直接调用危险方法(不常见)
  2. 入口类参数中包含可控类,该可控类有危险方法,被反序列化时被readObject调用(不常见)
  3. 入口参数中包含可控类,该可控类调用其他含有危险方法的类(常见)
  4. 构造函数/静态代码块等类加载时隐式执行

利用前提

  • 利用链里的类必须继承Serializable
  • 危险方法通常不是指可控类本身的方法,而是指与可控类方法同名且类型相同的函数

0x03 URLDNS利用链分析

URLDNS链特点

  1. 学习Java反序列化的第一条Gadget Chain
  2. 只能发起DNS请求,不能进行其他利用
  3. 优点:
    • 不限制JDK版本
    • 使用Java内置类,无第三方依赖要求
    • 目标无回显时,可通过DNS请求验证漏洞存在

原理分析

  • java.util.HashMap实现了Serializable接口,重写了readObject
  • 反序列化时会调用hash函数计算key的hashCode
  • java.net.URL实现了Serializable接口,其hashCode计算时会调用getHostAddress解析域名,从而发出DNS请求

利用目的

  • 序列化时不请求DNS反序列化时请求DNS
  • 实现方式:
    • 序列化时hashCode值不等于-1(直接返回不进行DNS解析)
    • 反序列化时hashCode值等于-1(触发DNS解析)

Gadget Chain调用流程

HashMap.readObject() 
--> HashMap.hash(URL) 
--> URL.hashCode()的handler.hashCode(即URLStreamHandler.hashCode()) 
--> URLStreamHandler.hashCode() 
--> URLStreamHandler.getHostAddress() 
--> InetAddress.getByName()

0x04 代码实现与分析

测试代码关键部分

// 设置URL对象的hashCode为8888(序列化时不触发DNS)
Field filed = Class.forName("java.net.URL").getDeclaredField("hashCode");
filed.setAccessible(true);  // 绕过权限检查
filed.set(url, 8888);

// 将URL对象放入HashMap(此时hashCode不为-1,不触发DNS)
hashMap.put(url, 23);

// 序列化前将hashCode设为-1(反序列化时将触发DNS)
filed.set(url, -1);
serializable(hashMap);

代码分析要点

  1. 使用反射获取并修改URL对象的hashCode字段
  2. 通过setAccessible(true)绕过Java语言权限控制
  3. 序列化前将hashCode设为非-1值避免立即触发DNS
  4. 反序列化前将hashCode设为-1确保触发DNS请求

0x05 实际测试与验证

测试步骤

  1. 使用DNSLog平台(如dnslog.org)获取临时域名
  2. 在代码中设置目标URL为http://[your-id].dnslog.biz
  3. 执行序列化生成payload文件
  4. 在服务端模拟环境中反序列化该文件
  5. 观察DNSLog平台是否收到请求

服务端模拟代码

public static void unserializable() throws Exception {
    FileInputStream filein = new FileInputStream("./hashmap.txt");
    ObjectInputStream inputStream = new ObjectInputStream(filein);
    Object o = inputStream.readObject();  // 触发反序列化
    filein.close();
    inputStream.close();
}

0x06 总结与扩展

URLDNS链价值

  1. 漏洞验证:确认目标是否存在反序列化漏洞
  2. 信息收集:可能获取系统版本等信息

学习建议

  1. 深入理解Java反射机制
  2. 掌握动态代理技术
  3. 研究其他常见反序列化漏洞链(如Commons Collections等)

防御措施

  1. 避免反序列化不可信数据
  2. 使用白名单机制限制可反序列化的类
  3. 考虑使用替代方案(如JSON、XML等更安全的序列化格式)
Java反序列化漏洞基础与URLDNS利用链分析 0x01 序列化基础概念 序列化定义 序列化是指将一个对象转换为字节序列的过程,包含: 对象的数据 对象的类型 对象中存储的属性等信息 Java序列化实现 通过实现 java.io.Serializable 接口 只有实现了 Serializable 接口的对象才能被序列化 注意 :序列化的是对象而不是类 序列化限制 静态属性 不能序列化 原因:静态变量属于类,在类加载时获取内存空间存储在静态区 访问方式:应直接通过类名访问而非对象引用 Transient瞬态属性 不能序列化 序列化用途 数据持久化:将数据永久保存在硬盘上 通过输出流将内存中的数据保存在文件中 远程通信:在网络上传送对象的字节序列 反序列化 序列化的逆过程,将字节流转换回对象 过程:开启输入流通道,Java从字节流中的信息重构对象并重新加载到内存 0x02 反序列化漏洞原理 漏洞产生原因 服务端反序列化数据时,客户端传递类的 readObject 方法中的代码会自动执行 本质:攻击者利用服务器反序列化过程执行恶意代码 反序列化利用形式 入口类的 readObject 直接调用危险方法(不常见) 入口类参数中包含可控类,该可控类有危险方法,被反序列化时被 readObject 调用(不常见) 入口参数中包含可控类,该可控类调用其他含有危险方法的类(常见) 构造函数/静态代码块等类加载时隐式执行 利用前提 利用链里的类必须继承 Serializable 危险方法通常不是指可控类本身的方法,而是指与可控类方法同名且类型相同的函数 0x03 URLDNS利用链分析 URLDNS链特点 学习Java反序列化的第一条Gadget Chain 只能发起DNS请求,不能进行其他利用 优点: 不限制JDK版本 使用Java内置类,无第三方依赖要求 目标无回显时,可通过DNS请求验证漏洞存在 原理分析 java.util.HashMap 实现了 Serializable 接口,重写了 readObject 反序列化时会调用 hash 函数计算key的 hashCode java.net.URL 实现了 Serializable 接口,其 hashCode 计算时会调用 getHostAddress 解析域名,从而发出DNS请求 利用目的 序列化时不请求DNS , 反序列化时请求DNS 实现方式: 序列化时 hashCode 值不等于-1(直接返回不进行DNS解析) 反序列化时 hashCode 值等于-1(触发DNS解析) Gadget Chain调用流程 0x04 代码实现与分析 测试代码关键部分 代码分析要点 使用反射获取并修改URL对象的 hashCode 字段 通过 setAccessible(true) 绕过Java语言权限控制 序列化前将 hashCode 设为非-1值避免立即触发DNS 反序列化前将 hashCode 设为-1确保触发DNS请求 0x05 实际测试与验证 测试步骤 使用DNSLog平台(如dnslog.org)获取临时域名 在代码中设置目标URL为 http://[your-id].dnslog.biz 执行序列化生成payload文件 在服务端模拟环境中反序列化该文件 观察DNSLog平台是否收到请求 服务端模拟代码 0x06 总结与扩展 URLDNS链价值 漏洞验证:确认目标是否存在反序列化漏洞 信息收集:可能获取系统版本等信息 学习建议 深入理解Java反射机制 掌握动态代理技术 研究其他常见反序列化漏洞链(如Commons Collections等) 防御措施 避免反序列化不可信数据 使用白名单机制限制可反序列化的类 考虑使用替代方案(如JSON、XML等更安全的序列化格式)