URLDNS反序列化漏洞
URLDNS外带反序列化:
写一个简单的demo:
package org.example.demo1;
import java.io.*;
import java.net.URL;
import java.util.HashMap;
public class UrlDns implements Serializable {
public static void main(String[] args) throws IOException, ClassNotFoundException {
HashMap<URL, Object> map = new HashMap<>();
map.put(new URL("http://127.0.0.1:8080/"), new Object());//此处做测试,域名为什么不重要,关键是跟进观察
FileOutputStream fos = new FileOutputStream("url.bin");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(map);
oos.flush();
oos.close();
fos.close();
FileInputStream fis = new FileInputStream("url.bin");
ObjectInputStream ois = new ObjectInputStream(fis);
Object obj = ois.readObject();
ois.close();
fis.close();
}
}
debug调试:
向hashmap中添加一条键值对,包括了url和一个不重要的对象
然后跳转到了:
该方法用于将指定的键值对存入HashMap中。
首先调用hash(key)计算键的哈希值;
然后调用putVal方法完成实际的插入操作;
如果键已存在,则旧值被替换;
返回与键关联的旧值,若不存在则返回null。
关键点在于调用了hash(key),这个方法,先跟进继续看,进入hash()
这段的意思是:
若 key 为 null,返回 0;
否则,先获取 key 的 hashCode() 值 h;
然后将 h 与 h 无符号右移 16 位后的结果进行异或运算,以打散高位影响,提升哈希分布均匀性。
由于传进来的key就是我们要解析的域名,并且不为空,所以会走hashcode()这个函数
所以接着跟进hashcode()
该方法用于计算URL对象的哈希码。
如果已计算过哈希码(hashCode != -1),直接返回缓存的结果;
否则,通过URL的协议处理器(handler)计算哈希码,并缓存该结果以供后续使用。
由于我们之前并没有计算过,所以会通过URL的协议处理器(handler)计算哈希码,
也就是说会调用hashCode = handler.hashCode(this);
所以跟进hashCode():
如果URL对象已缓存了IP地址(hostAddress),则直接返回;
否则获取URL的主机名(host);
若主机名为空或null,返回null;
否则通过InetAddress.getByName()解析主机名为IP地址,并缓存;
解析失败(如DNS异常或权限不足)则返回null。
关键点来了解析了主机名为ip地址,也就是说可以触发dns解析,来造成dnslog外带!!!!
流程:
ObjectInputStream.readObject()
→ HashMap.readObject()
→ HashMap.putVal()
→ HashMap.hash()
→ URL.hashCode()
→ URLStreamHandler.hashCode()
→ URLStreamHandler.getHostAddress()
→ InetAddress.getByName() // 触发DNS查询
有一个注意点,在自己写脚本测试的时候,可以使用反射修改hashCode的值,使其不等于-1
为什么要先修改 url 内的 hashCode 在将 url 存到 HashMap 内呢?答案就在上面,如果不设置 hashCode 不为 -1 的话,那么存入 hashMap 的时候就会触发一次 hash(key),也就是本地生成 poc 会执行一次 DNS请求,这会对我们的判断造成影响,所以要先设置其不为 -1 ,存入 hashMap 以后再将其变回来,这样只会执行一次 DNS 了