淺談Java反序列化漏洞原理(案例未完善後續補充)

  • 2019 年 10 月 3 日
  • 筆記

序列化與反序列化

img

序列化用途:方便於對象在網絡中的傳輸和存儲

java的反序列化

序列化就是將對象轉換為流,利於儲存和傳輸的格式

反序列化與序列化相反,將流轉換為對象

例如:json序列化、XML序列化、二進制序列化、SOAP序列化

  • 序列化:java.io.ObjectOutputStream 類中的 writeObject()

    該方法把對象序列化,將位元組序列寫到一個目標輸出流中(.ser擴展名)

  • 反序列化:java.io.ObjectInputStream 類中的 readObject()

    從輸入流中讀取位元組序列,再將其反序列化為對象

實現Serializable和Externalizable接口的類的對象才能被序列化。

漏洞危害

導致代碼執行、文件操作、執行數據庫操作等不可控後果

漏洞原理

如果Java應用對用戶輸入,即不可信數據做了反序列化處理,那麼攻擊者可以通過構造惡意輸入,讓反序列化產生非預期的對象,非預期的對象在產生過程中就有可能帶來任意代碼執行。

漏洞發現

存在於 WebLogic、WebSphere、JBoss、Jenkins、OpenNMS 等等

  • HTTP請求中的參數,cookies以及Parameters。
  • RMI協議,被廣泛使用的RMI協議完全基於序列化
  • JMX 同樣用於處理序列化對象
  • 自定義協議 用來接收與發送原始的java對象

漏洞挖掘

  1. 確定反序列化輸入點
    首先應找出readObject方法調用,在找到之後進行下一步的注入操作。一般可以通過以下方法進行查找:

    1. 源碼審計:尋找可以利用的「靶點」,即確定調用反序列化函數readObject的調用地點。

    2. 對該應用進行網絡行為抓包,尋找序列化數據,如wireshark,tcpdump等

      黑盒流量分析(可能面試)

      在Java反序列化傳送的包中,一般有兩種傳送方式,在TCP報文中,一般二進制流方式傳輸,在HTTP報文中,則大多以base64傳輸。因而在流量中有一些特徵:

      (1)TCP:必有aced0005,這個16進制流基本上也意味者java反序列化的開始;

      (2)HTTP:必有rO0AB,其實這就是aced0005的base64編碼的結果;

      以上意味着存在Java反序列化,可嘗試構造payload進行攻擊。

      黑盒java的RMI

      RMI是java的一種遠程對象(類)調用的服務端,默認於1099端口,基予socket通信,該通信實現遠程調用完全基於序列化以及反序列化。

      白盒代碼審計

      (1)觀察實現了Serializable接口的類是否存在問題。

      (2)觀察重寫了readObject方法的函數邏輯是否存在問題。

  2. 再考察應用的Class Path中是否包含Apache Commons Collections庫

  3. 生成反序列化的payload

  4. 提交我們的payload數據

漏洞防禦

  1. 類的白名單校驗機制:

    實際上原理很簡單,就是對所有傳入的反序列化對象,在反序列化過程開始前,對類型名稱做一個檢查,不符合白名單的類不進行反序列化操作。很顯然,這個白名單肯定是不存在Runtime的。

  2. 禁止JVM執行外部命令Runtime.exec

    這個措施可以通過擴展 SecurityManager 可以實現。