<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    初識Java反序列化

    Ann2022-06-10 08:49:49

    前言

    研究某產品反序列化EXP時,搜集到的POC只有一段16進制字節序列難以利用,遂有下文對Java序列化和反序列化的學習。

    大致內容如下:

    1. 序列化和反序列化示例
    2. 序列化數據組成解構
    3. 反序列化漏洞形成原理

    序列化和反序列化

    序列化:將程序運行時所需要的Java對象轉化為字節序列并存儲在文件系統中,一般為.ser后綴的文件,ObjectOutputStream.writeObject()方法可以將對象序列化。

    反序列化:將存儲在文件系統的字節序列轉化成對象供程序使用,ObjectInputStream.readObject()方法可以將字節序列轉化成對象。

    可序列化的類必須繼承 java.io.Serializable;序列化機制使對象得以脫離程序之外獨立存在。

    示列:

    Employ.java


    import java.io.Serializable;
    
    
     //該類必須實現java.io.Serializable
    public class Employ implements Serializable { 
        public String name;
        public int age;
    }
    

    test.java


    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectOutputStream;
    
    public class test {
    
        public static void main(String[] args) {
            //將e轉化為字節序列存儲于/tmp/1.ser
            Employ e = new Employ();
            e.name = "zhangyida";
            e.age = 15;
            try {
                FileOutputStream fops = new FileOutputStream("/tmp/1.ser");
                ObjectOutputStream obos = new ObjectOutputStream(fops);
                obos.writeObject(e);
                obos.close();
                System.out.println("Serialized data is saved in /tmp/1.ser");
    
            }catch (IOException i){
                i.printStackTrace();
            }
    
        }
    }
    

    desEmploy.java


    import java.io.ObjectInputStream;
    
    
    public class desEmploy {
        public static void main(String[] args) {
            Employ e = new Employ();
            try {
                FileInputStream fis  = new FileInputStream("/tmp/1.ser");
                ObjectInputStream obis = new ObjectInputStream(fis);
                e = (Employ) obis.readObject();
            }catch (IOException i){
                i.printStackTrace();
                return;
            } catch (ClassNotFoundException ex) {
                System.out.println("Employ class not found!");
                ex.printStackTrace();
                return;
            }
            System.out.println(e.name);
            System.out.println(e.age);
        }
    
    }
    

    運行test.java,生成一個字節序列存儲于/tmp目錄下。



    運行desEmploy.java,將存儲在1.ser內的字節序列轉化為對象。



    字節序列數據格式


    字節序列格式:

    一個java對象序列化后的字節序列由三部分組成(magic、version、contents),其中magic和version是常量,magic表示內容類型,version則是版本號,contents是被序列化對象的屬性、狀態等內容。java序列化stream的特征aced 0005及aced 0005編碼后的字符串。


    stream:
        magic version contents
    

    字節序列中的contents,可能由一個content組成也可以有多個content。


    contents
      content
      contents content
    

    content由一個或多個的object(對象)、blockdata(數據塊)組成。


    content
      object 
      blockdata
    

    object(對象),序列化的Stream中常見的對象有newObject、newClassDesc、newString。


    object
      newObject  
      newClass    
      newArray     
      newString    
      newEnum
      newClassDesc  
      prevObject
      nullReference
      exception
      TC_RESET
    

    newObject,表示序列化對象是一個普通object對象;標識符為TC_OBJECT;classDesc表示一個ObjectStreamClass對象,其保存著className、序列化ID、類字段等信息;newHandle是其句柄值,類似對象ID;classdata[],保存類實例化對象屬性。


    newObject:
      TC_OBJECT classDesc newHandle classdata[]
    

    newString,表示序列化對象是一個字符串常量對象。


    newString:
      TC_STRING newHandle
    

    newClassDesc,表示序列化對象是一個ObjectStreamClass對象,TC_CLASSDESC是其標識符;className是其類名;serialVersionID是其序列化版本ID,當對字節序列被反序列化會將此值與本地相應實體類的serialVersionUID比較,一致則反序列化,不一致則拋出異常;classDescINFO保存著類的序列化屬性。


    classDescINFO:  

    classDescFlags(0x02 - SC_SERIALIZABLE or 0x03 - SC_WRITE_METHOD | SC_SERIALIZABLE),0x02表示類實現了Serializable接口但并未重寫readObject方法,0x03表示類即實現了Serializable接口又重寫了readObject方法。當值為0x03時,反序列化該字節序列時會調用重寫的readObject方法。

    fields:類的屬性

    classAnnotation:類注解,一般為TC_ENDBLOCKDATA

    superClassDesc:被序列化對象的類的父類是否可序列化,可序列化時則寫入父類的classDesc,不可序列化時則為TC_NULL。


    newClassDesc
      TC_CLASSDESC className serialVersionUID newHandle classDescInfo
      
          *classDescInfo
              classDescFlags fields classAnnotation superClassDesc 
    


    使用SerializationDumper可以查看其序列化之后的相關信息:Employ類的實例對象,Int屬性age值為15,String屬性name值為zhangyida;Employ類未重寫readObject方法。



    用途及使用場景

    用途:

    1、將對象的字節序列永久保存在硬盤以便使用。

    2、網絡傳輸。

    使用場景:

    使用場景豐富,簡單列舉常用場景。

    1、服務器啟動后,將用戶session信息永久保存在硬盤中,當服務器出現問題需要重啟時可以直接從硬盤中讀取字節序列還原用戶seesion。

    2、JNDI、RMI遠程代碼調用

    3、xml Xstream、XMLDecoder等(HTTP body:Content-Type:applicatin/xml)、json(Jackson、fastjson)http請求中包含。

    4、...


    反序列化命令執行漏洞原理

    被序列化對象的類重寫了readObject方法,且重寫的readObject方法存在問題可執行java代碼造成反序列化命令執行漏洞。

    示例:

    Employ類重寫readObject方法,添加一個命令執行的方法

    Employ.java


    import java.io.ObjectInputStream;
    import java.io.Serializable;
    import java.io.IOException;
    
    public class Employ implements Serializable {
        public String name;
        //public int age;
    
        private void test(String name){
            System.out.println(name);
        }
    
    
    
        private void  readObject(ObjectInputStream objin) {
    
            try {
                objin.readObject();
                
    
                Runtime.getRuntime().exec("open  /System/Applications/Calculator.app");
                
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
           
    
        }
    }
    

    重新生成字節序列后再反序列化字節序列將執行系統命令彈出計算器,故Java反序列化漏洞就是當前類重寫readObject方法時可調用執行系統命令的函數造成遠程命令執行的漏洞。因此真實環境中的java反序列化漏洞需要去尋找重寫了readObject方法的且可利用的類能通過調用Runtime.getRuntime().exec()或者其他函數來達到執行系統命令目的,這個可利用的類稱之為gadget,調用過程稱為gadget chain。

    文章來源:Tide安全團隊
    序列化
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    Java安全中Groovy組件從反序列化到命令注入及繞過和在白盒中的排查方法
    最近兩個月我一直在做拒絕服務漏洞相關的時間,并收獲了Spring和Weblogic的兩個CVE但DoS漏洞終歸是雞肋洞,并沒有太大的意義,比如之前有人說我只會水垃圾洞而已,所以在以后可能打算做其他方向早上和pyn3rd師傅聊天
    淺談Java反序列化漏洞
    2022-05-17 17:48:01
    Java序列化與反序列化Java 提供了一種對象序列化的機制,該機制中,一個對象可以被表示為一個字節序列,該字節序列包括該對象的數據、有關對象的類型的信息和存儲在對象中數據的類型。反序列化就是打開字節流并重構對象。對象序列化不僅要將基本數據類型轉換成字節表示,有時還要恢復數據。
    java序列化與反序列化
    2022-04-13 16:35:35
    java反序列化指字節序列恢復到java對象。bit,則一個字最大為 FFFF。序列化是把對象轉換成有序字節流,以便在網絡上傳輸或者保存在本地文件中。序列化后的字節流保存了Java對象的狀態以及相關的描述信息。序列化機制的核心作用就是對象狀態的保存與重建。
    序列化漏洞匯總
    2022-01-07 22:17:34
    漏洞出現在WLS Security組件,允許遠程攻擊者執行任意命令。攻擊者通過向TCP端口7001發送T3協議流量,其中包含精心構造的序列化Java對象利用此漏洞。然后將其序列化,提交給未做安全檢測的Java應用。Java應用在進行反序列化操作時,則會觸發TransformedMap的變換函數,執行預設的命令。
    序列化的核心思維旨在,將A變成B,最后再從B還原回A。 總之,在一些條件苛刻或者變化無常的環境與需求中,產生了這種靈活的可逆性的B的中間體。 理解不安全反序列化的最好方法是了解不同的編程語言如何實現序列化和反序列化。這里的序列化與反序列化指的是程序語言中自帶的實施與實現。而非自創或者自定義的序列化與反序列化機制(比如:N進制形式hashmap樹型等其他數據結構里的序列化中間體)。
    攻擊者可能利用此漏洞獲取敏感信息或執行惡意代碼。漏洞概述  漏洞名稱Apache Dubbo多個反序列化漏洞漏洞編號CVE-2023-29234、CVE-2023-46279公開時間2023-12-15影響對象數量級十萬級奇安信評級高危CVSS 評分7.7、8.1威脅類型信息泄露、代碼執行利用可能性中POC狀態未公開在野利用狀態未發現EXP狀態未公開技術細節狀態未公開危害描述:
    它指的是一個有用的工具庫,幫助處理和操作XML格式的數據。ROME庫允許我們把XML數據轉換成Java中的對象,這樣我們可以更方便地在程序中操作數據。另外,它也支持將Java對象轉換成XML數據,這樣我們就可以把數據保存成XML文件或者發送給其他系統。
    URLDNS鏈子是Java反序列化分析的第0課,網上也有很多優質的分析文章。筆者作為Java安全初學者,也從0到1調試了一遍,現在給出調試筆記。Java原生鏈反序列化:利用Java.io.ObjectOutputStream對象輸入流的readObject方法實現將字節序列轉化成對象。測試源碼如下,此部分源碼參考了ol4three師傅的博客:package?將輸出字節流寫入文件中進行封存。讀取字節流操作為readObject,所以重寫readObject可以執行自定義代碼。影響的版本問題:與JDK版本無關,其攻擊鏈實現依賴于Java內置類,與第三方庫無關?
    接著定義 Person 類實現前面的接口:public?XStream 序列化是調用?unmarshall : xml-> object 解碼兩個重要的實現類:?Mapper 映射器簡單來說就是通過 mapper 獲取對象對應的類、成員、Field 屬性的 Class 對象,賦值給 XML 的標簽字段。Converter 轉換器XStream 為 Java 常見的類型提供了 Converter 轉換器。EventHandler 類EventHandler 類為動態生成事件偵聽器提供支持,這些偵聽器的方法執行一條涉及傳入事件對象和目標對象的簡單語句。EventHandler 類是實現了 InvocationHandler 的一個類,設計本意是為交互工具提供 beans,建立從用戶界面到應用程序邏輯的連接。
    Ann
    暫無描述
      亚洲 欧美 自拍 唯美 另类