JAVA反序列化漏洞基础
JAVA反序列化漏洞基础
1.1 什么是序列化和反序列化
Java序列化是指把Java对象转换为字节序列的过程;
Java反序列化是指把字节序列恢复为Java对象的过程;
1.2 为什么要序列化
对象不只是存储在内存中,它还需要在传输网络中进行传输,并且保存起来之后下次再加载出来,这时
候就需要序列化技术。
Java的序列化技术就是把对象转换成一串由二进制字节组成的数组,然后将这二进制数据保存在磁盘或
传输网络。而后需要用到这对象时,磁盘或者网络接收者可以通过反序列化得到此对象,达到对象持久
化的目的。
1.3 ObjectOutputStream 与 ObjectInputStream类
1.3.1 ObjectOutputStream类
java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。
序列化操作
一个对象要想序列化,必须满足两个条件:
▪ 该类必须实现 java.io.Serializable 接口, Serializable 是一个标记接口,不实现此接口的类将不会
使任何状态序列化或反序列化,会抛出 NotSerializableException 。
▪ 该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态
的,使用transient 关键字修饰。
示例:
Employee.java
public class Employee implements java.io.Serializable{ |
SerializeDemo.java
public class SerializeDemo { |
将Employee对象写入到了employee.txt文件中
开头的 AC ED 00 05 为序列化内容的特征
1.3.2 ObjectInputStream类
如果能找到一个对象的class文件,我们可以进行反序列化操作,调用 ObjectInputStream 读取对象的
方法:
public class DeserializeDemo { |
打印结果:
反序列化操作就是从二进制文件中提取对象
1.4 反序列化漏洞的基本原理
在Java反序列化中,会调用被反序列化的readObject方法,当readObject方法被重写不当时产生漏洞
public class demon { |
此处重写了readObject方法,执行了 Runtime.getRuntime().exec()
defaultReadObject方法为ObjectInputStream中执行readObject后的默认执行方法
运行流程:
myObj对象序列化进object文件
从object反序列化对象->调用readObject方法->执行Runtime.getRuntime().exec(“calc.exe”);
1.5 java类中serialVersionUID的作用
serialVersionUID适用于java序列化机制。简单来说,JAVA序列化的机制是通过 判断类的serialVersionUID来验证的版本一致的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较。如果相同说明是一致的,可以进行反序列化,否则会出现反序列化版本一致的异常,即是InvalidCastException。
1.5.1 serialVersionUID有两种显示的生成方式:
一是 默认的1L,比如:private static final long serialVersionUID = 1L;
二是根据包名,类名,继承关系,非私有的方法和属性,以及参数,返回值等诸多因子计算得出的,极
度复杂生成的一个64位的哈希字段。基本上计算出来的这个值是唯一的。比如:private static final
long serialVersionUID = xxxxL;
注意:显示声明serialVersionUID可以避免对象不一致
设置自动生存uid