URLDNS链再分析
readObject()方法
Java反序列化会调用对应的readobject方法
比如我创建一个类test。序列化test类就会调用writeobject方法,
反序列化就会调用test类的readobject方法。默认是存在的。可以重写readobject方法
在HashMap类中,恰恰存在readobject方法
以ysoserial的payload为例,作者有明确指出
* Gadget Chain:
* HashMap.readObject()
* HashMap.putVal()
* HashMap.hash()
* URL.hashCode()
我先是把这条链子跟完了,现在分析一下他的payload
public Object getObject(final String url) throws Exception {
URLStreamHandler handler = new SilentURLStreamHandler();
HashMap ht = new HashMap();
URL u = new URL(null, url, handler);
ht.put(u, url);
Reflections.setFieldValue(u, "hashCode", -1);
return ht;
}
整条链子加起来不到5行,他第一步先是实例化了一个URLStreamHandler的对象,但是这里用的是它的子类,因为后面你调试的时候会发现,他本是是一个抽象类,想要实例化只能选择继承他的子类,而这里作者是在下面自己继承了一个子类
static class SilentURLStreamHandler extends URLStreamHandler {
protected URLConnection openConnection(URL u) throws IOException {
return null;
}
protected synchronized InetAddress getHostAddress(URL u) {
return null;
}
}
第一行的openConnection方法是必须被子类重写的,我们可以回到URLStreamHandler他有对这个抽象方法的介绍:Opens a connection to the object referenced by the URL argument. This method should be overridden by a subclass.
意思就是子类应该覆盖该方法,而且这个方法也是抽象方法,子类必须要对它实现
而第二行,经过我反复测试,当把这一行代码删除的时候,dns的请求次数会+1,也就是说之所以要有一个return null是为了防止在poc创建的时候触发dns请求,而无法判断是否是链条本身触发的dns请求,他本身也有解释:**此UrlStreamHandler的实例用于在创建URL实例时避免任何DNS解析。**DNS分辨率用于漏洞检测。重要的是使用序列化对象先前探测给定的URL。潜在假阴性:如果首先从测试器计算机解析DNS名称,则目标服务器可能会在第二分辨率上获取缓存。
链子分析:
首先就是利用HashMap.readObject()方法在反序列化的时候作为触发点,其中putVal(hash(key), key, value, false, false);
的hash方法会对key进行处理,而这里的key就是我们创建的url对象,那么他是如何赋值的:利用ht.put(u, url);
作为下一个跳板,来调用URL u的hashcode并用Reflections.setFieldValue(u, “hashCode”, -1); 对URL的对象u的参数进行调整,再利用其hashcode调用URLStreamHandler的hashcode来进行dns请求,达到我们的要求