URLDNS学习
URLDNS
URLDNS
就是ysoserial
中⼀个利⽤链的名字,但准确来说,这个其实不能称作“利⽤链”。因为其参数不是⼀个可以“利⽤”的命令,⽽仅为⼀个URL,其能触发的结果也不是命令执⾏,⽽是⼀次DNS请求。
虽然这个“利⽤链”实际上是不能“利⽤”的,但因为其如下的优点,⾮常适合我们在检测反序列化漏洞时使⽤:
- 使⽤
Java
内置的类构造,对第三⽅库没有依赖 在⽬标没有回显的时候,能够通过DNS
请求得知是否存在反序列化漏洞 ysoserial
会调⽤URLDNS
类的getObject
⽅法⽅法获得Payload
。这个⽅法返回的是⼀个对象,这个对象就是最后将被序列化的对象,在这⾥是HashMap
。
触发反序列化的⽅法是 readObject
,因为Java
开发者(包括Java
内置库的开发者)经常会在这⾥⾯写⾃⼰的逻辑,所以导致可以构造 gadget
。
由于payload
被序列化的对象是HashMap
,那就直接看HashMap
的readObject
方法。
其中最后一行有这样的语句:
1 | putVal(hash(key), key, value, false, false); |
跟进这个方法:
1 | static final int hash(Object key) { |
可见,hash
⽅法调⽤了key
的hashCode()
⽅法。
URLDNS
中使⽤的这个key
是⼀个java.net.URL
对象,我们看看其hashCode
⽅法。
1 | public synchronized int hashCode() { |
此时,handler
是URLStreamHandler
对象(的某个⼦类对象),继续跟进其hashCode
⽅法:
1 | /** |
这里调用了InetAddress addr = getHostAddress(u);
继续跟进:
1 | protected synchronized InetAddress getHostAddress(URL u) { |
这⾥ InetAddress.getByName(host)
的作⽤是根据主机名,获取其IP
地址,在⽹络上其实就是⼀次 DNS
查询。到这⾥就不必要再跟了。
这次URLDNS
的整个gadget chain
就清晰了。
要构造这个Gadget
,只需要初始化⼀个 java.net.URL
对象,作为key
放在 java.util.HashMap
中;然后,设置这个 URL
对象的 hashCode
为初始值 -1
,这样反序列化时将会重新计算其 hashCode
,才能触发到后⾯的DNS
请求,否则不会调⽤ URL->hashCode()
。
另外,ysoserial
为了防⽌在⽣成Payload
的时候也执⾏了URL
请求和DNS
查询,所以重写了⼀ 个 SilentURLStreamHandler
类,这不是必须的。
1 | HashMap->readObject() |
Gadget:
1 | Gadget chain: |
最后摘抄p神在这篇文章写的一段话
学习过PHP反序列化的同学这时就会惊叹,这不就跟在PHP⾥找反序列化利⽤链⼀样吗?其实就是⼀样,那为什么很多同学觉得Java反序列化很难?多半其实是被 CommonsCollections 带偏了,这个链中确实有⼀些较难理解的概念。
有时候想要学习⼀个东⻄,⽹上搜索⼀下,发现有教程,于是跟着做⼀遍。这样⼀来,你会发现⽹上⼤ 部分Java反序列化“教程”、“⼊门”通常上来先了解Java反序列化是什么,然后很快开始讲 CommonsCollections ,就好像刚知道C语⾔语法的同学⽴⻢马继续学习Linux内核,我是⼗分不建议这样做的,除⾮你有⾮常强的理解能⼒。
学习需要聪明⼀点,并独⽴思考问题。我很少参照别⼈的⽂章来学习,这样你学的东⻄是⼆⼿的,有时候连⼆⼿都不是,⽂章原作者也可能是参考另⼀篇⽂章写的。 我的建议是从⽂档和源码开始学,实在有压⼒可以参考⼀些⻛风评较好的书籍或技术博客。
当然,有时候你并不知道怎样是对的怎样是错的。⽐如你作为⼀个Java反序列化漏洞的初学者,你并不知道应该先学习 URLDNS 还是 CommonsCollections ,也许你连 URLDNS 的名字都没听过,⽽你看到⽹上⼤部分⽂章都是介绍CommonsCollections的,⾃然也就去学习这个了。
所以有些弯路确实是避免不了的,不过如果你在学习的道路上更加富有探索精神,看到ysoserial这种项⽬时多问问⾃⼰“其他的Gadget是做什么的”,对于未知的事物原理充满好奇喜欢翻翻源码.
Reference:
反序列化篇(2)