URLDNS链
前言
URLDNS链是ysoserial里的一个简单利用链
通过DNS请求检测是否存在Java反序列化漏洞,但是只能发起DNS请求,不能进行其他利用
对JDK版本没有要求,只依赖原生类(不过调链子时发现在序列化时JDK17会出现无权限修改私有字段报错,最好使用JDK9以下的版本)
URLDNS链分析
URL类继承了java.io.Serializable,是可以序列化的

在URL类中有个常见的hashCode()函数

在这个hashCode函数中调用了handler的hashCode函数

进入handler的hashCode函数中可以看到调用了getHostAddress()函数,是根据域名获取地址,会进行域名解析,发送DNS请求


最后InetAddress.getName这里可以触发DNS请求
所以只要能调用到URL类中的hashCode()函数,就可以发起DNS请求,验证是否存在漏洞
在HashMap中的readObject()函数中可以看到调用了hash()函数

跟进可以看到在hash()函数中调用了hashCode()函数

所以进行构造,入口类就是HashMap类,执行类就是URL类,都有相同名称类型的hashCode()方法
看URL的构造函数知道直接传入一个URL网址即可,可以使用BurpSuite的Collaborator生成一个

最后序列化hashmap即可

然后立即轮询,正常在序列化时是什么都不会发生的,但是会发现在序列化的时候就会发起多次DNS查询,并且进行反序列化后并不会有DNS请求

跟进hashmap的put中,会发现此时就会调用hash()方法

进而调用了hashCode()方法,所以会发起DNS请求

所以当代码运行到下面这段代码时就会发起DNS请求,会影响对是否存在反序列化漏洞的判断
1 | |
重新回到URL类中的hashCode函数,可以发现这里存在一个判断:如果hashCode != -1就会直接返回hashCode,不会执行到下面的handler的hashCode函数,也就不会触发getHostAddress()函数,所以在反序列化时不会发起DNS查询

这里hashCode在初始化的时候是-1

在执行完hashmap.put(new URL("http://q3uy1mhj5wykolrewrdopeeqyh49szgo.oastify.com"),1);这句代码之后就变成了输入的URL的hashCode,可以通过调试查看此时的hashCode的值已经不是-1了


现在就是要在执行hashmap.put(new URL("http://q3uy1mhj5wykolrewrdopeeqyh49szgo.oastify.com"),1);时不要发起DNS请求,在执行完这句代码后、序列化之前,将hashCode改回-1,从而可以在反序列化时发起DNS请求
这就需要利用反射来改变已有的对象属性,将hashCode改回-1
1 | |
此时序列化是不会发起DNS请求

然后反序列化可以看到有一次DNS请求

在判断hashCode值这里下一个断点,然后调试反序列化代码,可以看到此时这里的hashCode的值为-1

总结
- 入口类:
HashMap类:入口类的HashMap.readObject中的HashMap.hash中的Object.hashCode - 调用类:
URL类:通过调用URL.hashCode中的URLStreamHandler.hashCode中的URLStreamHandler.getHostAddress中的InetAddress.getByName来发起DNS请求 - 相同名称类型的函数:
hashCode HashMap可以接收Object对象,所以可以将URL类的实例化对象传入HashMap中,最终在HashMap中调用的不是Object.hashCode,而是URLStreamHandler.hashCode
所以URLDNS的利用链是:
HashMap.readObject()HashMap.hash()URL.hashCode()URLStreamHandler.hashCode()URLStreamHandler.getHostAddress()InetAddress.getByName()