作为 ysoserial 中最简单链,这里简单记录学习一下
首先使用ysoserial生成urldns的探测类型
首先先去 dnslog.cn 获取一个url

java -jar ysoserial-0.0.6-SNAPSHOT-all.jar URLDNS "http://pk3q64.dnslog.cn" > Test.txt
查看生成的文件


Java反序列化后的前几个字节就是 ac ed
这其实是一个序列化后的对象,这里我们将它反序列化看一下
我们将这个反序列化了一下
随即我们就收到了DNS查询的记录

这是为什么呢
接下来分析一下
简单的观察一下ysoserial
我们刚才生成一个Payload使用的是类似于 java -jar ysoserial-0.0.6-SNAPSHOT-all.jar URLDNS "http://pk3q64.dnslog.cn" > Test.txt 的命令
我们分析一下干了什么吧
首先下载 ysoserial 项目
https://github.com/frohoff/ysoserial
生成Payload的类在 GeneratePayload.java

首先检查我们传入的参数是否正确,然后将我们调用的payload放入 payloadType,参数放入 command 例如上文我们调用的是 URLDNS 参数是我们的url

之后将我们的payload传入 Utils.getPayloadClass 中,这个是作者自己实现的一个工具类,我们传入payload,根据反射获取到类的 Class ,然后判断是否为空
其中Payload都放在 payloads 文件夹下

我们这里面调用的就是 URLDNS 了

之后根据 Class 获取到类的实例,然后向 getObject 方法中传入我们的参数,将返回的对象序列化输出,我们后面用 > test.txt 就是把序列化的数据重定向到文件中
其中 getObject 的实现如下

这个就是 ysoserial 的简单工作原理,其他的也类似
分析
DNSURL 反序列化的链为
首先序列化点在 HashMap的 readObject 方法(因为实现了Serializable接口)

readObject 调用了 putVal方法,且参数里调用了 HashMap的hash方法

继续跟进

因为HashMap里面的 key 与 Value 是一个对应的关系,所以看看 ysoserial传入的 key 是什么吧

显然传入的 key 是 URL 类
因此是调用了 URL 中的 hashCode方法,跟进看一下

若 hashcode 的值为 -1 则调用 handler.hashcode 方法
其实这个值默认就是 -1 的

yso中也是用反射将其强制设置为 -1

调用的 hander.hashCode 其实也就是我们传入的 hander

在 URL 的构造方法中将其初始化为我们传入的

ysoserial 中的 SilentURLStreamHandler 其实就是 URLStreamHandler 的子类(为了程序的健壮性,后面有解释)
所以 handler.hashCode(this) 其实就是调用的 URLStreamHandler.hashCode(this),我们跟进一下

这里面将 u 传入 getHostAddress
跟进getHostAddress

其中将 u.getHost() 的结果放入 InetAddress.getByName 此函数将是根据主机名获取对应ip,相当于发出一次dnslog请求
我们查看一下 URL.getHost()

返回的是 host,而这个值已经在我们初始化 URL 的时候就被设置了(设置为我们一开始传入的url)
因此一套简单的流程就出来了
后续思考
我们查看一下HashMap的 put 方法看看

发现也调用了 hash方法

那这样我们利用 ysoserial 生成 POC的时候,也不是会有dns请求吗?

我们测试一下

确实会产生很多请求
有个方法就是通过反射修改 hashCode的值(将URL的 hashCode修改为非 -1 就不会调用到了)

那么 URLDNS 呢

也没有产生请求
原因在这个

这个 SilentURLStreamHandler 继承了 URLStreamHandler
重写了里面的 openConnection 和 getHostAddress

因此在调用 put 方法的时候不会触发 dns 查询
那这样我们反序列化的时候不是也因为重写了方法而不能进行 dns 查询吗?
原因是因为 URL 里面的 handler 设置的是 transient

因为transient修饰符无法被序列化,所以虽然它最后是没执行dns请求,但是在反序列化的时候还是会执行dns请求!
简单测试一下
User.java

可以看见 name 属性未被反序列化,还是原来的值(为赋值前 为 null)
总结
虽然 URLDNS 不能Getshell,但是可以帮助我们探测目标是否存在漏洞等,写POC或者扫描器的时候挺适用的