Fastjson 1.2.24遠程代碼執行漏洞的實例分析,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
漏洞名稱:Fastjson 1.2.24遠程代碼執行漏洞(com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl)
漏洞編號:無
漏洞類型:遠程代碼執行
CVSS評分:無
漏洞危害等級:高危
Fastjson是一個Java語言編寫的高性能功能完善的JSON庫。它采用一種“假定有序快速匹配”的算法,把JSON Parse的性能提升到極致,是目前Java語言中最快的JSON庫。Fastjson接口簡單易用,已經被廣泛使用在緩存序列化、協議交互、Web輸出、Android客戶端等多種應用場景。下圖是Fastjson組件中的反序列化流程。
漏洞是利用fastjson autotype在處理json對象的時候,未對@type字段進行完全的安全性驗證,攻擊者可以傳入危險類,服務器接收到危險類執行其中惡意代碼。攻擊者通過這種方式可以實現遠程代碼執行漏洞的利用,獲取服務器的敏感信息泄露,甚至可以利用此漏洞進一步對服務器數據進行修改,增加,刪除等操作,對服務器造成巨大的影響。
無
影響版本:
Fastjson < 1.2.25
獲取Fastjson最新版本,下載鏈接:https://github.com/alibaba/fastjson
8080/HTTP
基于Windows平臺,使用環境
目錄下的fastjsondemo
環境,拷貝后使用Idea打開fastjsondemo文件夾,下載maven資源,運行DemoApplication類,即可啟動環境。效果如圖。
運行sniper
工具箱,填寫表單信息,點擊Attack,效果如圖。
JavaBean 是特殊的 Java 類,使用 Java 語言書寫,并且遵守 JavaBean API 規范。JavaBean的特征:
提供一個默認的無參構造函數。
需要被序列化并且實現了 Serializable 接口。
可能有一系列可讀寫屬性。
可能有一系列的 getter 或 setter 方法。
方法 | 描述 |
---|---|
getPropertyName() | 舉例來說,如果屬性的名稱為 myName,那么這個方法的名字就要寫成 getMyName() 來讀取這個屬性。這個方法也稱為訪問器。 |
setPropertyName() | 舉例來說,如果屬性的名稱為 myName,那么這個方法的名字就要寫成 setMyName()來寫入這個屬性。這個方法也稱為寫入器。 |
程序實例
public class StudentsBean implements java.io.Serializable { private String firstName = null; private String lastName = null; private int age = 0; public StudentsBean() { } public String getFirstName(){ return firstName; } public String getLastName(){ return lastName; } public int getAge(){ return age; } public void setFirstName(String firstName){ this.firstName = firstName; } public void setLastName(String lastName){ this.lastName = lastName; } public void setAge(int age) { this.age = age; } }
Fastjson通過parseObject方法解析傳入的json數據。
調用DefaultJSONParser缺省方法對json格式數據進行解析。
在方法的參數中,調用ParserConfig.getGlobalInstance()
方法獲取ParserConfig類中的初始配置,其中黑名單(denyList)也在此類中進行配置。
調用addDeny方法循環添加denyList數組中的黑名單。
回到DefaultJSONParser方法,初始化結束后,調用JSONScanner方法對傳入的json字符串設置讀取位置,判斷過程中處理Unicode字符集的BOM標識。
回到DefaultJSONParser方法,為token賦值。
回到JSON入口類,獲取到DefaultJSONParser類型對象,調用parse()方法進行解析。
在parse方法中,通過判斷lexer.token(),進入對應的代碼塊。
調用JSONObject構造方法,初始化JSONObject類中的map屬性。
回到DefaultJSONParser#parse方法,調用parseObject方法,對傳入的json數據進行字節讀取。
一般會讀取json字符串中的雙引號進入scanSymbol方法中,在scanSymbol方法中計算字符串的hash。
調用addSymbol方法,將鍵名添加到SymbolTable中。
回到DefaultJSONParser#parseObject方法中,判斷key值是否為@type
。如果是,則進入if判斷條件下的代碼塊中。
調用scanSymbol方法,以雙引號作為quote變量值,進行@type
json字段值的value讀取。
獲得@type
的鍵值,調用addSymbol方法,將@type
的字段值添加到SymbolTable中。
回到DefaultJSONParser#parseObject方法中,調用TypeUtils.loadClass方法進行類加載操作。
進入loadClass方法中,首先會在現有的mappings中尋找從@type
傳入的classname。
如果在原有的mappings中沒有記錄傳入的classname,則調用contextClassLoader.loadClass獲取AppClassLoader類加載器,并加載到mappings中與@type
傳入的類進行關聯,最后返回clazz對象。
回到DefaultJSONParser#parseObject方法中,調用this.config.getDeserializer(clazz)獲取反序列化器。
進入getDeserializer方法中,首先現有的IdentityHashMap中進行hash匹配,如果無法匹配,則進入第二個if判斷條件中重載getDeserializer方法,繼續獲取反序列化器。
在getDeserializer(Class<?> clazz, Type type)
方法中,首先依然會與現有的IdentityHashMap中進行hash匹配。如果無法匹配,會事先進行黑名單匹配,在調用ServiceLoader.load判斷META-INF/services/下是否存在傳入的classname類。
如果沒有尋找到對應的類,則判斷傳入的classname是否是繼承java.lang.Enum、是否是array類型選擇對應的反序列化器生成方法。如果上述條件不滿足,則繼續判斷傳入的classname是否為Set、HashSet、Collection、List、ArrayList,如果不是則繼續判斷classname是否繼承Collection,Map,Throwable接口。如果上述條件都不滿足,則調用createJavaBeanDeserializer方法生成JavaBean反序列化器。
進入createJavaBeanDeserializer方法,判斷asmEnable是否為true,調用JavaBeanInfo.build方法建立JavaBean。
建立JavaBean過程中,通過反射機制獲取傳入的class中所有的屬性,方法,并保存在數組中。選擇一個無參構造函數作為默認的構造函數。
循環遍歷method數組中的方法,并從中選取符合條件的方法。(條件:同時滿足方法名長度大于4;非靜態方法;方法類型為Void?;蛘叻椒愋团c方法所在類相同)
再從篩選的規則中繼續篩選出形參數量為1的方法。
再從篩選出的方法中獲取以set方法開頭的方法,并檢測JavaBean的方法命名規范,篩選出符合規范的方法。調用TypeUtils.getField方法獲取與set方法對應的屬性值。
進入getField方法中,遍歷@type傳入的class以及其父類的所有屬性值,返回尋找到屬性。
最終調用add方法,將獲取的Field屬性保存到fieldList列表中。
再以相同的流程篩選出存在get方法的屬性值,如果篩選出的filed屬性值不在fieldList,則添加到fieldList列表中。
調用JavaBeanInfo方法對JavaBeanInfo中的屬性進行初始化,并返回實例化對象。
回到ParserConfig#createJavaBeanDeserializer方法中,獲取到beanInfo對象,并從beaninfo中取出defaultConstructor默認構造器、field屬性。
通過檢測fieldClass屬性值,為asmEnable標志位賦值
由于@type傳入的class中的javabean方法,存在只讀屬性,因此asmEnable標志位變成false。
根據asmEnable標志位,進行if條件判斷,調用JavaBeanDeserializer構造方法,并返回實例化對象。
在實例化過程中,會將beaninfo中的屬性賦值給JavaBeanDeserializer類中的filed反序列化器。
回到ParserConfig#getDeserializer方法,調用putDeserializer方法,將生成的反序列化器與@type傳入的class類進行關聯,最后返回反序列化器
回到DefaultJSONParser#parseObject方法,調用deserializer.deserialze方法進行反序列化。
進入deserialze方法中,首先根據token值進入到對應的條件代碼塊。調用scanSymbol方法。
進入scanSymbol方法,對傳入的json字符串進行解析,和解析@type的流程相同,解析傳入的其他屬性字段。
回到JavaBeanDeserializer#deserialze方法中,解析的屬性值返回并賦值到key屬性中。
調用parseField方法解析屬性。
進入parseField方法,調用smartMatch方法,獲取field反序列化器。
進入smartMatch方法,首先會從建立的javabean中尋找是否存在對應key中屬性值的操作方法。
如果沒有匹配到javabean中的方法,則先消除掉屬性值中的_
和-
符號,再與javabean中的方法進行匹配,如果匹配成功,則返回反序列化器。如果匹配失敗,則返回null。
回到parseField方法中,設置Feature.SupportNonPublicField狀態,并根據狀態值進入if條件判斷的代碼塊中,生成extraFieldDeserializers擴展的反序列化器。再從反序列化器中取出從fastjson獲取的json數據中指定的屬性。
調用parseField方法,按照獲取deserializer反序列化器的流程,獲取fieldValueDeserilizer反序列化器。得到的fieldValueDeserilizer反序列化器,在parseField方法中調用deserialze方法進行反序列化。
由于傳入的參數中存在數組,fastjson首先會調用getFastMatchToken方法,獲取當前json字符串位置的token標志值。
由于json字符串中的數組是以[data]
的形式傳入的,所以當檢測屬性值是以[
開頭,則為token賦值為14。
由于是數組類型,因此在獲取反序列化器時,會進入ObjectArrayCodec類進行解析。
調用ObjectArrayCodec#parseArray方法,進行數組的解析。
根據數組中的元素類型,進行token賦值,再依據token,選擇對應token值,進入對應的if代碼塊。
解析數組中元素時,如果元素時String類型,則將字符串按照byte類型進行讀取,在讀取的過程中,會先進行base64解碼。
最終以]
符號作為數組結束符。
回到ObjectArrayCodec#deserialze方法中,調用toObjectArray方法,將傳入的數組數據,轉換成數組對象。
回到DefaultDeserializer#parseField方法中,調用setValue方法,將獲取的數組對象,賦予到@type class中的對應屬性中。
在解析最后一個_outputProperties參數時,會在setValue方法中進行反射,調用getOutputProperties方法。
此方法會在調用的過程中,實例化從bytecode傳入惡意class文件,從而實現攻擊。
Fastjson1.2.25版本新增了checkAutoType方法,設置了autotype開關,對@type字段進行限制。如果autotype開關關閉,則無法從@type字段傳入類進行jndi攻擊。
增加了黑名單中的類,對fastjson的gadget進行攔截。
關于Fastjson 1.2.24遠程代碼執行漏洞的實例分析問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。