作者:阿里安全歸零實驗室
來源:https://xz.aliyun.com/t/2272
本文分享一下defineClass在反序列化漏洞當中的使用場景,以及在exp構造過程中的一些使用技巧
0x00 前言
首先看一下defineClass的官方定義

眾所周知,java編譯器會將.java文件編譯成jvm可以識別的機器代碼保存在.class文件當中。正常情況下,java會先調用classLoader去加載.class文件,然后調用loadClass函數去加載對應的類名,返回一個Class對象。而defineClass提供了另外一種方法,從官方定義中可以看出,defineClass可以從byte[]還原出一個Class對象,這種方法,在構造java反序列化利用和漏洞poc時,變得非常有用。下面總結我在實際分析漏洞和編寫exp時的一點兒體會,具體有如下幾種玩法.
0x01 defineCLass構造回顯
這里以java原生的java.io.ObjectInputStreamread的readObject()作為反序列化函數,以commons-collections-3.1作為payload,注入類文件代碼如下

常規的回顯思路是用URLClassLoader去加載一個.class或是.java文件,然后調用loadClass函數去加載對應類名,返回對應的Class對象,然后再調用newInstance()實例出一個對象,最后調用對應功能函數,使用例如throw new Exception("genxor");這樣拋錯的方法,將回顯結果帶出來。例如

回顯結果如下所示:

但是前提是要先寫入一個.class或是.jar文件(寫入方法這里不描述,使用FileOutputStream類,方法大同小異),這樣顯得拖泥帶水,而且讓利用過程變得很復雜。
那可不可以不寫文件而直接調用我們的代碼呢,使用defineClass很好的解決了這個問題。將我們編譯好的.class或是.jar文件轉換成byte[]放到內存當中,然后直接用defineClass加載byte[]返回Class對象。那怎么調用defineClass函數呢,因為默認的defineClass是java.lang.ClassLoader的函數,而且是protected屬性,無法直接調用(這里暫且不考慮反射),而且java.lang.ClassLoader類也無法被transform函數加載,這里我們使用org.mozilla.classfile.DefiningClassLoader類, 代碼如圖

他重寫了defineClass而且是public屬性,正好符合我們要求,這里我寫個具體事例,代碼如下

回顯結果如下所示

根據這個思路,我們構造transformerChain生成map對象,代碼如圖所示

0x02 fastjson利用
fastjson早期的一個反序列化命令執行利用poc用到了 com.sun.org.apache.bcel.internal.util.ClassLoader,首先簡單說一下漏洞原理,如下是利用poc的格式

fastjson默認開啟type屬性,可以利用上述格式來設置對象屬性(fastjson的type屬性使用不屬于本文敘述范疇,具體使用請自行查詢)。tomcat有一個tomcat-dbcp.jar組件是tomcat用來連接數據庫的驅動程序,其中org.apache.tomcat.dbcp.dbcp.BasicDataSource類存在如下代碼,如圖所示

當com.alibaba.fastjson.JSONObject. parseObject解析上述json的時候,代碼會上圖中Class.forName的邏輯,同時將driverClassLoader和driverClassName設置為json指定的內容,到這里簡單敘述了一下fastjson漏洞的原理,一句話概括就是利用fastjson默認的type屬性,操控了相應的類,進而操控Class.forName()的參數,可以使用任意ClassLoader去加載任意代碼,達到命令執行的目的。
這里詳細說一下利用Class.forName執行代碼的方法,有兩種方式:
- Class.forName(classname)
- Class.forName(classname, true, ClassLoaderName)
先說第一種,通過控制classname執行代碼,這里我寫了一個demo,如圖所示

這里利用了java的一個特性,利用靜態代碼塊兒static{}來執行,當com.fastjson.pwn.run被Class.forName加載的時候,代碼便會執行。
第二種,通過控制classname和classloader執行代碼,我寫了一個demo,以com.sun.org.apache.bcel.internal.util.ClassLoader這個類為例子,如圖所示

這里用到了com.sun.org.apache.bcel.internal.util.ClassLoader這個classloader,而classname是一個經過BCEL編碼的evil.class文件,這里我給出evil.java的源碼,如圖所示

classloader會先把它解碼成一個byte[],然后調用defineClass返回Class,也就是evil
具體我們跟一下代碼邏輯,如圖所示

這里會開始調用com.sun.org.apache.bcel.internal.util.ClassLoader的loadClass加載類,如圖所示

這里判斷classname如果經過了BCEL編碼,則解碼獲取Class文件,如圖

此刻內存中evil.class文件的結構,如圖所示

繼續跟蹤后面的邏輯,如圖

這里調用defineClass還原出evil.class中的evil類,因為使用static{},所以在加載過程中代碼執行。
OK 回到fastjson漏洞邏輯,因為控制了Class.forName加載的類和ClassLoader,所以可以通過調用特定的ClassLoader去加載精心構造的代碼,從而執行我們事先構造好的class文件,從而達到執行任意代碼的目的。
0x03 jackson利用
jackson的反序列化命令執行跟fastjson類似,也似注入一個精心構造的pwn.class文件,最后通過newInstance實例對象觸發代碼執行。這里先給出pwn.java的源碼,如圖所示:

然后寫了一個Demo,觸發漏洞,代碼如下

jackson類似fastjson可以通過type屬性,設置變量的值,但是不同時jackson默認不開啟type,需要mapper.enableDefaultTyping()設置開啟。

當readValue這段json的時候,觸發命令執行漏洞,下面調試一下關鍵步驟,如圖

這里defineTransletClasses會解碼transletBytecodes成byte[],并執行defineClass得到foo.pwn這個類,然后在后面執行newInstance導致static{}靜態代碼塊兒執行,如圖

成功觸發,如圖所示

0x04 總結
利用defineClass在運行時狀態下,將我們精心構造的class文件加載進入ClassLoader,通過java的static{}特征,導致代碼執行。
以上測試代碼全部保存在: https://github.com/genxor/Deserialize.git
0x05 關于我們
阿里安全歸零實驗室成立于2017年11月,實驗室致力于對黑灰產技術的研究,愿景通過技術手段解決當前日益嚴重的網絡違規和網絡犯罪問題,為阿里新經濟體保駕護航。實驗室與寄生在阿里生態經濟體的黑灰產直面技術對抗,以打造一流的以情報驅動的黑灰產情報體系能力,看清黑灰產風險、領先黑灰產、演練風險為愿景,重點研究業務安全和數據安全領域中黑灰產風險事件背后的產業鏈和手法,解決相關風險問題。以情報外部視角切入,在多個安全風險領域內均取得了不錯的成績;以藍軍真實黑灰產視角,模擬黑灰產進行演練攻擊,檢驗防線,為阿里巴巴經濟體保駕護航貢獻了一份獨特的力量。
目前團隊也在不斷的招聘各種優秀人才,研發專家、數據分析專家、情報分析與體系化專家等,歡迎加盟,聯系郵箱 聯系:back2zero@service.alibaba.com
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/572/
暫無評論