JAVA反序列化深入学习(二):URLDNS

URLDNS 是适合新手分析的反序列化链,只依赖原生类,没有 jdk 版本限制,也被 ysoserial 涵盖在其中。它不会执行命令,只会触发 DNS 解析,因此通常用来探测是否存在反序列化漏洞。

背景描述

漏洞来源地址:点击这里

Java URLDNS链是通过readObject反序列化+DNS查询来确认反序列化利用点的存在。该利用链具有如下特点:

  • 只能发起 DNS 请求,不能进行其它利用。
  • 不限制 jdk 版本,使用 Java 内置类,对第三方依赖没有要求。
  • 目标无回显,可以通过 DNS 请求来验证是否存在反序列化漏洞。

JAVA环境

java version "1.8.0_441"

Java(TM) SE Runtime Environment (build 1.8.0_441-b07)

Java HotSpot(TM) 64-Bit Server VM (build 25.441-b07, mixed mode)

sink点 - sink

这个漏洞关键点是 Java 内置的 java.net.URL 类,这个类的 equalshashCode 方法具有一个有趣的特性:在对 URL 对象进行比较时(使用 equals / hashCode 方法),会触发一次 DNS 解析,因为对于 URL 来说,如果两个主机名(host)都可以解析为相同的 IP 地址,则这两个主机会被认为是相同的。

URL#equals

我们先来看一下这个特性的具体调用代码,URL#equals 方法重写了 Object 的判断,调用 URLStreamHandler#equals 方法进行判断:

public boolean equals(Object obj) {
    if (!(obj instanceof URL))
        return false;
    URL u2 = (URL)obj;

    return handler.equals(this, u2);
}

URLStreamHandler#equals 方法判断 URL 对象的锚点是否相同,并调用 sameFile 方法比较两个 URL

protected boolean equals(URL u1, URL u2) {
    String ref1 = u1.getRef();
    String ref2 = u2.getRef();
    return (ref1 == ref2 || (ref1 != null && ref1.equals(ref2))) &&
           sameFile(u1, u2);
}

sameFile 方法会检查是否引用了相同的 protocol(协议)、host(主机)、port(端口)、path(路径),在比较 host(主机) 时,调用 hostsEqual 方法进行比较。

protected boolean sameFile(URL u1, URL u2) {
    // Compare the protocols.
    if (!((u1.getProtocol() == u2.getProtocol()) ||
          (u1.getProtocol() != null &&
           u1.getProtocol().equalsIgnoreCase(u2.getProtocol()))))
        return false;

    // Compare the files.
    if (!(u1.getFile() == u2.getFile() ||
          (u1.getFile() != null && u1.getFile().equals(u2.getFile()))))
        return false;

    // Compare the ports.
    int port1, port2;
    port1 = (u1.getPort() != -1) ? u1.getPort() : u1.handler.getDefaultPort();
    port2 = (u2.getPort() != -1) ? u2.getPort() : u2.handler.getDefaultPort();
    if (port1 != port2)
        return false;

    // Compare the hosts.
    if (!hostsEqual(u1, u2))
        return false;

    return true;
}

hostsEqual 方法调用 getHostAddress 方法对要比较的两个 URL 进行请求解析 IP 地址,并实施对比。

protected boolean hostsEqual(URL u1, URL u2) {
    InetAddress a1 = getHostAddress(u1);
    InetAddress a2 = getHostAddress(u2);
    // if we have internet address for both, compare them
    if (a1 != null && a2 != null) {
        return a1.equals(a2);
    // else, if both have host names, compare them
    } else if (u1.getHost() != null && u2.getHost() != null)
        return u1.getHost().equalsIgnoreCase(u2.getHost());
     else
        return u1.getHost() == null && u2.getHost() == null;
}

getHostAddress 方法使用 InetAddress.getByName() 方法对 host 进行解析,触发了 DNS 请求

synchronized InetAddress getHostAddress() {
    if (hostAddress != null) {
        return hostAddress;
    }

    if (host == null || host.isEmpty()) {
        return null;
    }
    try {
        hostAddress = InetAddress.getByName(host);
    } catch (UnknownHostException | SecurityExcept
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Neolock

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值