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{
public String name;
public String address;
public transient int age; // transient瞬態修飾成員,不會被序列化
public void addressCheck() {
System.out.println("Address check : " + name + " ‐‐ " + address);
//此處省略tostring等方法
}
}
SerializeDemo.java
public class SerializeDemo {
public static void main(String[] args) throws IOException {
Employee e = new Employee();
e.name = "zhangsan";
e.age = 20;
e.address = "shenzhen";
// 1.創建序列化流
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("employee.txt"));
// 2.寫出對象
outputStream.writeObject(e);
// 3.釋放資源
outputStream.close();
}
}
將Employee對象寫入到了employee.txt文件中

開頭的AC ED 00 05為序列化內容的特征
1.3.2 ObjectInputStream類
如果能找到一個對象的class文件,我們可以進行反序列化操作,調用 ObjectInputStream 讀取對象的方法:
public class DeserializeDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 1.創建反序列化流
FileInputStream fileInputStream = new FileInputStream("employee.txt");
ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);
// 2.使用ObjectInputStream中的readObject讀取一個對象
Object o = inputStream.readObject();
// 3.釋放資源
inputStream.close();
System.out.println(o);
}
}
打印結果:

反序列化操作就是從二進制文件中提取對象
1.3 反序列化漏洞的基本原理
在Java反序列化中,會調用被反序列化的readObject方法,當readObject方法被重寫不當時產生漏洞
public class demon {
public static void main(String args[]) throws Exception{
//序列化
//定義myObj對象
MyObject myObj = new MyObject();
myObj.name = "hi";
//創建一個包含對象進行反序列化信息的”object”數據文件
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("object"));
//writeObject()方法將myObj對象寫入object文件
os.writeObject(myObj);
os.close();
//反序列化
//從文件中反序列化obj對象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object"));
//恢復對象
MyObject objectFromDisk = (MyObject)ois.readObject();
System.out.println(objectFromDisk.name);
ois.close();
}
static class MyObject implements Serializable {
public String name;
//重寫readObject()方法
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
//執行默認的readObject()方法
in.defaultReadObject();
//執行打開計算器程序命令
Runtime.getRuntime().exec("calc.exe");
}
}
}
此處重寫了readObject方法,執行了 Runtime.getRuntime().exec()
defaultReadObject方法為ObjectInputStream中執行readObject后的默認執行方法

運行流程:
- myObj對象序列化進object文件
- 從object反序列化對象
- 調用readObject方法
- 執行Runtime.getRuntime().exec("calc.exe");
``
