Java JDBC導致的反序列化攻擊原理解析
這篇文章主要介紹了Java JDBC導致的反序列化攻擊原理解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
背景
上周BlackHat Europe 2019的議題《New Exploit Technique In Java Deserialization Attack》中提到了一個通過注入JDBC URL實現(xiàn)反序列化攻擊的場景,簡單分析一下。
分析
首先,當java應用使用MySQL Connector/J(官方的JDBC驅動,本文基于其8.0+版本)連接mysql時,JDBC URL的格式如下:protocol//[hosts]/[database]?properties,具體可看mysql官方文檔,示例:jdbc:mysql://localhost:3306/test?useSSL=true
其中,protocol、host、database都比較好理解,URL中的properties可以設定MySQL Connector/J連接mysql服務器的具體方式,關于properties的官方文檔地址,其中和本文相關的連接屬性有兩個,分別是autoDeserialize和queryInterceptors,前者是設定MySQL Connector/J是否反序列化BLOB類型的數(shù)據(jù),后者是攔截器,在查詢執(zhí)行時觸發(fā),由com.mysql.cj.protocol.a.NativeProtocol#sendQueryPacket方法源碼可知,會在執(zhí)行查詢語句前后分別調用攔截器的preProcess和postProcess方法。
接下來定位下反序列化的觸發(fā)點,在mysql-connector-java組件下全局搜索關鍵字“.readObject()”,定位到com.mysql.cj.jdbc.result.ResultSetImpl類中的getObject(int columnIndex)方法,部分核心代碼如下:
public Object getObject(int columnIndex) throws SQLException { …… case BLOB: byte[] data = getBytes(columnIndex); if (this.connection.getPropertySet().getBooleanProperty(PropertyDefinitions.PNAME_autoDeserialize).getValue()) { Object obj = data; // Serialized object? try { ByteArrayInputStream bytesIn = new ByteArrayInputStream(data); ObjectInputStream objIn = new ObjectInputStream(bytesIn); obj = objIn.readObject(); } } }
變量data即為mysql返回結果集,當JDBC URL中設定屬性autoDeserialize為true時,會對類型為bit、binary以及blob的數(shù)據(jù)進行反序列化,如何觸發(fā)getObject(int columnIndex)方法的調用呢?議題中給出的調用鏈如下:
> com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor#preProcess/postProcess > com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor#populateMapWithSessionStatusValues > com.mysql.cj.jdbc.util.ResultSetUtil#resultSetToMap > com.mysql.cj.jdbc.result.ResultSetImpl#getObject
ServerStatusDiffInterceptor即為此前提到過的攔截器,在JDBC URL中設定屬性queryInterceptors為ServerStatusDiffInterceptor時,執(zhí)行查詢語句會調用攔截器的preProcess和postProcess方法,進而通過上述調用鏈最終調用getObject(int columnIndex)方法。
實際利用還有一個問題,最終調用getObject方法的對象是數(shù)據(jù)庫返回的結果集,由populateMapWithSessionStatusValues方法可知:
try { toPopulate.clear(); stmt = this.connection.createStatement(); rs = stmt.executeQuery("SHOW SESSION STATUS"); ResultSetUtil.resultSetToMap(toPopulate, rs); }
這個結果集是執(zhí)行SQL語句“SHOW SESSION STATUS”后數(shù)據(jù)庫返回的值,SQL語句“SHOW SESSION STATUS”返回當前數(shù)據(jù)庫連接的狀態(tài)值,實際是讀取系統(tǒng)表INFORMATION_SCHEMA.SESSION_VARIABLES的值,也可能是PERFORMANCE_SCHEMA.SESSION_VARIABLES(Mysql版本差異導致)。但是mysql中INFORMATION_SCHEMA和PERFORMANCE_SCHEMA都是不允許被修改的,所以需要想辦法操縱返回的數(shù)據(jù)。
利用條件
1.本質上還是Java原生的反序列化利用,所以需要環(huán)境中有可用的Gadget;
2.需要能偽造相關系統(tǒng)表的數(shù)據(jù),將“SHOW SESSION STATUS”的執(zhí)行結果設置為我們精心構造的反序列化數(shù)據(jù),或者基于mysql連接協(xié)議,自定義返回數(shù)據(jù),后面有時間的時候會寫寫這塊兒。
3.可控的JDBC URL
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Java去重排序之Comparable與Comparator的使用及說明
這篇文章主要介紹了Java去重排序之Comparable與Comparator的使用及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04Java編程實現(xiàn)對十六進制字符串異或運算代碼示例
這篇文章主要介紹了Java編程實現(xiàn)對十六進制字符串異或運算代碼示例,簡述了異或運算以及具體實例,具有一定借鑒價值,需要的朋友可以參考下。2017-12-12Java elasticSearch-api的具體操作步驟講解
這篇文章主要介紹了elasticSearch-api的具體操作步驟講解,本文通過詳細的步驟介紹和圖文代碼展示講解了該項技術,需要的朋友可以參考下2021-06-06