概述
URLDNS就是ysoserial中一个利用链的名字。但准确来说,这个其实不能称作“利用链”。因为其参数不 是一个可以“利用”的命令,而仅为一个URL,其能触发的结果也不是命令执行,而是一次DNS请求。
虽然这个“利用链”实际上是不能“利用”的,但因为其如下的优点,非常适合在检测反序列化漏洞时使用。
优点:
- 使用Java内置的类构造,
- 对第三方库没有依赖
- 在目标没有回显的时候,能够通过DNS请求得知是否存在反序列化漏洞
URLDNS链调用栈
HashMap重写了writeObject和readObject,没有使用JDK统一的默认序列化与反序列化
gadget分析
在Java反序列化中,会调用被反序列化类的readObject方法,当readObject方法被重写不当时,就会产生漏洞。
分析:HashMap类的readObject方法,先调用putVal方法,然后调用hash方法(hash方法处理完后的结果再给putVal方法)
分析hash方法:传入一个对象key,key不为null就调用该对象的hashCode方法
继续分析hashCode方法:这里可以不用继续跟进HashMap类了,因为hash方法可以传入对象,所以可以调用任意类的hashCode方法;
这里使用URL类的hashCode方法:有一个判断:hashCode变量不为-1,就会进入if判断,不会执行下面的hashCode方法;并且该hashCode方法是URLStreamHandler类的,且把当前URL对象传入作为参数。hashCode变量的默认值是-1。(handler使用transient关键字定义,不参与序列化)
关于前面的hashCode变量的值:根据链子,必须让他第一次不为-1,直接返回hashCode变量;第二次要让hashCode变量为-1,才能跳出if判断,进而执行URLStreamHandler类的hashCode方法。
原因:
第一次不为 -1,第二次为 -1(利用反射来控制hashCode变量的值);这里需要分析HashMap类的put方法,通过该put方法传入键值对的时候,发现也会调用hash –> hashCode(和readObject方法一样,这样的话,在URL对象传入到HashMap的时候,就会还没序列化就触发了DNS请求,也就无法校验是否存在序列化漏洞了)
跟进URLStreamHandler类的hashCode方法,然后跟进getHostAddress方法
最终到getByName方法:该方法会对传入的域名进行IP解析,相当于一次DNS请求(以上就是该URLDNS链的基本分析)
POC
1 | import java.io.*; |
先序列化,然后对序列化的ser.bin的文件进行反序列化,触发DNS请求
注:
- DNS请求记录会在本地进行缓存,第二次反序列化时;如果没有收到请求的话,建议换一个域名或者清空DNS缓存。通过反射改变class对象的属性。
- Class.forName():forName方法默认会进行类加载,如果指定该方法的第二个参数是false的话,就不会进行类加载,也就不会执行静态代码块。