# # 简介
这是一个最简单的链,原生 JDK 就存在。也就是说,不需要服务器存在任何特定的第三方组件。如果目标存在反序列化漏洞,那么我们就能够通过这个链来实现 dnslog 功能,从而验证漏洞的存在。
前面我们学习了反序列化的知识,我们也知道了,只需要服务器反序列化了我们传入的对象,我们就有机会进行反序列化漏洞的利用。接着我们来看看这条链的整个过程把。
PS:看了反序列化的基础但还是不太懂的,建议就先分析这条链。
# 分析
# java.net.URL 分析
我的分析不是从入口类开始分析,而是先找到存在漏洞的一个类,然后再往上寻找入口类。
分析 java.net.URL 这个原生 API。
首先,这个类实现了 Serializable 接口,所以能够被序列化。
接着我们需要找这个类里面的方法,看看有没有能够利用的。这里可以看到它存在很多方法,但是这些方法的命名我们很难在其他类中找到同名的情况,所以利用起来不好利用(和 php 的 pop 链一样,通过入口类的同名函数来移花接木)。我们需要找一些通用命名的方法(其实就是找 URL 这个类中和入口类中的同名方法)
接着我们找到了 hashCode 这个方法,这个方法想必在大量的类中都存在。
跟进分析,发现这个 hashCode 方法中尝试了获取 host 的地址,也就是说存在一个域名解析的过程,那么就可能造成 DNSlog。
# 寻找入口类(HashMap 分析)
在找到存在问题的类后,我们就可以寻找一个入口类,看看能不能进行利用了。
我们回忆一下,反序列化的入口类需要什么?
入口类参数中包含可控类,并且这个类有危险方法(在这条链中,我们的危险方法指的就是 dnslog),入口类在 readObject 时触发这个类的危险方法。
首先呢我们寻找的这个入口类要么类型是 URL 这个类的类型,要么它的参数能存 URL 这个类的类型(Object)。
这里我们自然而然就想到了 Map,Map 这个类它的 key 和 Value 可以是任意类型,自然满足了我们的第一个要求。我们这里以 Map 的实现类 HashMap 为例。
第二个要求就是这个 HashMap 类实现了序列化接口,存在 readObject,并且 readObject 中触发了目标类的危险方法,也就是说 hashcode 方法。
我们跟进 HashMap 看看代码:
①能够被序列化
②存在 readObject,我们可以看到它做了很多自定义的策略。
继续分析 readObject,我们可以看到,它执行了 key 的 hashcode 方法。也就是说,它调用了 key 值的 hashcode 的方法。这就意味着,如果我们以 HashMap 为入口类,并且 key 的参数是 URL 类型,则实例化 HashMap 获取的对象在反序列化的时候就会执行 URL 类的 hashcode 方法,从而进行 DNSlog。
# 梳理一下
到这里,其实整个利用链我们就分析的差不多了,但是我们还是需要梳理一下。
首先是 HashMap 这个对象在反序列化的时候会调用 key 键的 hashcode 方法。
其次就是调用 URL 中的 hashcode 方法就能实现 DNSlog。
那么利用链就很清晰了,只要让 HashMap 的 key 键为 URL 对象,那么在反序列化 HashMap<URL,xxxx> 这个对象的时候就达成了 DNSlog 的目的。
# 利用反射去掉序列化时的噪点
但需要注意的是,我们在测试的时候,序列化也会触发这个 DNSlog,这可能会干扰我们的分析。
比如这里,我们只是对其进行了序列化它也调用了 hashCode 这个方法,执行了 DNSlog。
PS:其实这里去不去不重要,但通过这个例子可以让我们知道反射在反序列化中的地位。
因此为了避免造成干扰,我们需要让它在序列化的时候不要执行 dnslog。这里我们就发现,URL 这个类的 hashcode 方法只要让 hashcode 这个变量的值不等于 - 1 就能够不执行 dnslog(而默认情况下这个个值是为 - 1 的,也就是说默认情况下必执行 dnslog),因此我们可以利用反射,让它不等于 - 1,从而跳过 hashcode 方法的调用。
此时我们再对其进行序列化就不会有 dnslog 了。
# 反序列化获取 DNSlog
此时再对其进行反序列化,就成功获取 dnslog 了。