JAVA反序列化漏洞基礎原理


JAVA反序列化漏洞基礎原理

1.1 什么是序列化和反序列化?

Java序列化是指把Java對象轉換為字節序列的過程;

Java反序列化是指把字節序列恢復為Java對象的過程;

image-20210507210106526

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文件中

image-20210508144949488

開頭的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);
    }
}

打印結果:

image-20210508150221435

反序列化操作就是從二進制文件中提取對象

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后的默認執行方法

image-20210508153910511

運行流程:

  1. myObj對象序列化進object文件
  2. 從object反序列化對象
  3. 調用readObject方法
  4. 執行Runtime.getRuntime().exec("calc.exe");

``


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM