在一些测试环境之中 目标是否发生反序列化是无回显的 是否有一种办法能够测试目标是否能够发生反序列化呢?
有的兄弟有的
如果我们能让目标服务器通过反序列化发起一次DNS解析请求 那么在接收到请求的时候不就知道了吗
那么这就是我们需要学习的URLDNS链的作用之处
前置知识
- java反序列化简单了解
- 反射简单了解
这两部分知识博主都做了简单的讲解 可以参考我的博文
作用类选择
在这里我们选择HashMap链作为我们的作用链
因为我们知道在反序列化之中如果想我们反序列化出来的类执行其中的恶意代码 这个类之中就要有一个特殊的readObject()方法
而这个HashMap之中就是这样构造了一个特殊钩子 并且其是JDK原生类 不依赖任何第三方库 几乎所有反序列化场景都能触发
构造链
我们先理解这个HashMap的hash.put(key,value)方法 其实说简单了就是将一个数值对存入哈希表之中
我们来跟进一下看看
可以看到当这个传入的key不为空的时候会调用hashCode 这个hashCode其实就是生成一个快速定位对象的索引标签 为哈希表之中的对象设置一个方便快速查找的索引
那么现在我们知道我们可以构造一个特殊的类作为这里的key值 但是这个类不是随随便便选择的 回忆我们的目的:让目标服务器通过反序列化发起一次DNS解析请求 我们需要找一个类的hashcode()方法能够达成这个目的的
那么我们接着步入看看这个hashCode方法
看到这个方法是在Object类之中的 并且native修饰符代表这是一个平台相关的底层代码 这个范围太笼统了 看不出在URLDNS链之中这个方法的调用
我们点击代码左侧这个蓝色圈圈 查看一下哪些类重写的hashCode方法 能够被利用 在这里由于我们是带着答案看问题 所以我们直接定位到URL类
可以看到在URL类的hash.Code之中 如果hashCode得到值不等于-1(也就是之前已经计算过这个hashCode了 系统之中有缓存了)就会直接返回hashCode值 否则会第调用handler.hashCode
在这里出现了一个带有.的方法 那我们就要看看这个handler是什么类的对象
将光标置于此对象上方 即可发现这是URLStreamHandler类的实例化对象 那么我们就去URLStreamHandler查看一下其重写的hashCode逻辑是啥
这一步的逻辑实际上依然是在计算一个URL的哈希值 只不过是将URL拆分成几个部分 每部分分别计算哈希 最后合在一起
对于URLDNS链而言 其中唯一关键的也就是这一句
1 | InetAddress addr = getHostAddress(u); |
这也是此链的出口(整条链最终指向危险操作的那个方法调用)为什么? 我们继续进入这个方法看看
可以看到在getHostAddress之中有实现DNS查询的javaAPI InetAddress.getByName(host)
那么到这一步 这个API就会进行DNS解析 于是我们的目的就达到了
那么现在我们重写理一遍整个链子
1 | 目标反序列化 HashMap |
示例
1 | package java_URL; |
可以使用yakit进行Dnslog查询
使用yakit的DNSLog模块 会自动生成一个随机子域名 可以使用这个来完成复现 一些我常见的DNSlog平台我实际测试登不上去
设置hashCode为-1
我们注意到上述代码逻辑之中有一段
1 | // 把 hashCode 改为一个非 -1 的值,防止 put 时触发 DNS hashCodeField.set(url, 123); // 现在 hashCode = 123 |
这一段反复横跳是为什么呢
首先我们要搞清楚 我们想做的是通过反序列化让目标服务器产生DNS请求 以此试探出目标服务器能否进行反序列化操作
但是在hash方法的代码逻辑中我们发现如果hashCode的值是-1 那么当你put的时候 就会触发DNS
然而在URL类里面有一个私有的实例字段
所以我们需要在put之前将其设置为一个非-1的任意数 让代码以为哈希值已经计算 不会触发DNS
之后在序列化之前设置回-1 以便反序列化之后触发DNS
运行逻辑
我们将一个域名当作key值传入 并且通过设置hashCode不为-1的方式使得在反序列化之前不会触发DNS 此时我们序列化 将其转换成一段二进制字节流 将字节流传入目标服务器 假设目标服务器上存在readObject
1 | ObjectInputStream ois = new ObjectInputStream(输入流); |
当其发生反序列化的时候 由于HashMap类之中有特殊的readObject方法 就会之星其中的DNS查询·指令 最终我们在我们的DNSLOG平台上查看到请求 成功证明目标服务器存在反序列化
小结
至此我们就学完了UDLDNS链的绝大部分知识点
UDLDNS链是java反序列化利用链之中最基础 最稳定的一条链 其核心价值在于通过DNS请求探测目标是否存在反序列化漏洞 更重要的是要理解“从源码之中寻找可利用的调用链” 这也是后续我们学习CC链时候必备的能力
参考文章