淺談Java反序列化漏洞原理(案例未完善後續補充)
序列化與反序列化
序列化用途:方便於物件在網路中的傳輸和儲存
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物件
漏洞挖掘
確定反序列化輸入點
首先應找出readObject方法呼叫,在找到之後進行下一步的注入操作。一般可以通過以下方法進行查詢:原始碼審計:尋找可以利用的“靶點”,即確定呼叫反序列化函式readObject的呼叫地點。
對該應用進行網路行為抓包,尋找序列化資料,如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方法的函式邏輯是否存在問題。
再考察應用的Class Path中是否包含Apache Commons Collections庫
生成反序列化的payload
提交我們的payload資料
漏洞防禦
類的白名單校驗機制:
實際上原理很簡單,就是對所有傳入的反序列化物件,在反序列化過程開始前,對型別名稱做一個檢查,不符合白名單的類不進行反序列化操作。很顯然,這個白名單肯定是不存在Runtime的。
禁止JVM執行外部命令Runtime.exec
這個措施可以通過擴充套件 SecurityManager 可以實現。