java反序列化漏洞簡單學習

知識點

反序列化並不只存在於php,也存在各種語言中,如java、python等。
在學習java反序列化之前,我們需要知道一個基礎知識:重寫。

重寫

重寫,顧名思義就是重新改寫該方法,從而達到想要的結果。需要注意的是:

  1. 只有擁有繼承關係時才能重寫,也就是說,只能重寫父類同名方法
  2. 方法重寫時, 方法名與形參列表必須一致。
  3. 方法重寫時,子類的權限修飾符必須要大於或者等於父類的權限修飾符。
  4. 方法重寫時,子類的返回值類型必須要小於或者 等於父類的返回值類型。
  5. 方法重寫時, 子類拋出的異常類型要小於或者等於父類拋出的異常類型。 Exception(最壞) RuntimeException(小壞)
    (順帶提一嘴重載,重載就是一個類裏的兩個或以上同名方法就是方法重載,兩個函數的參數類型或者參數數目必須不一樣,但函數名一致)

代碼準備

正常序列化

package com.sertest;

import java.io.*;
import java.io.Serializable;

class SerObj implements Serializable//實現Serializable接口,使其可以被序列化
{
    public String name;
    public int time;
}
public class  ser{
    public static void main(String args[]) throws Exception{
        // 實例化對象
        SerObj serObj = new SerObj();
        serObj.name = "serobj";
        serObj.time = 10;

        // 以下就是序列化操作
        // 打開object.ser文件
        FileOutputStream fos = new FileOutputStream("object.ser");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        // 使用writeObject()方法將serObj對象寫到object.ser文件
        oos.writeObject(serObj);
        oos.close();
        fos.close();
    }
}

正常反序列化

package com.sertest;

import java.io.*;

public class Unser {
    public static void main(String args[]) throws Exception
    {
        FileInputStream fis = new FileInputStream("object.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);
        SerObj deSerobj = (SerObj) ois.readObject();
        System.out.println(deSerobj.name);
        ois.close();
        fis.close();
    }
}

此時的結果時正常的。

重寫readobject方法後的惡意代碼

package com.sertest;

import java.io.*;

class Evil implements Serializable
{
    public String name;
    public int time;
    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException
    {
        in.defaultReadObject();
        Runtime.getRuntime().exec("calc.exe");
    }
}

public class hack_test {
    public static void main(String args[])throws Exception
    {
        Evil h2 = new Evil();
        h2.name = "serobj";
        h2.time = 10;
        FileOutputStream fos = new FileOutputStream("hack.ser");
        ObjectOutputStream os = new ObjectOutputStream(fos);
        os.writeObject(h2);
        os.close();
    }
}

反序列化代碼:

package com.sertest;

import java.io.*;

public class Unser {
    public static void main(String args[]) throws Exception
    {
        FileInputStream fis = new FileInputStream("hack.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Evil deSerobj = (Evil) ois.readObject();//這裏的類在反序列化的時候需要改變爲包含惡意代碼的類的名稱,這樣改是爲了看得更明白
        System.out.println(deSerobj.name);
        ois.close();
        fis.close();
    }
}

此時在反序列化時,由於惡意代碼重寫了readObject,所以在調用時調用的是已經被重寫的readObject方法,執行了惡意代碼。

本來想試行一下把這兩個打包成jar文件包,然後一個用來序列化數據一個用來反序列化數據,奈何java編程水平有限,只能做到這個地步。實際上生成惡意序列化數據的時候肯定要使用同一個類名和變量名,不然會因類名不同而報錯,那就不能成功了。
以後有時間的話看能不能寫一個簡單的鏈出來,再瞭解一下JAVA的反射機制,這樣能對相關的利用就能有一定程度的理解了。
參考文章:
https://www.cnblogs.com/Fluorescence-tjy/p/11222052.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章