fastjson1.22-1.24反序列化
fastjson基础
简介
什么是fastjson
- fastjson 是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean
- FastJson 与 Google 的 Gson 都是解析 Json 的强者,两者不相伯仲
- https://github.com/alibaba/fastjson
- fastjson 会不定期发布针对 android 版本优化的版本,android优化版本是去掉不必要的代码,减少体积,功能和标准版本基本一样。 已发布的android版本包括:http://repo1.maven.org/maven2/com/alibaba/fastjson/1.1.51.android/
maven配置一下依赖就能开始用
1 | <dependency> |
Map转JSON字符串
1 | package com.fastjson.demo1; |
基本用法
POJO List 转 JSON 字符串
1 | package com.fastjson.demo1; |
1
Json 字符串转 JsonObject
1 | package com.fastjson.demo1; |
Fastjson1.22-1.24反序列化
TEMPLATESIMPL环境&复现
jdk 1.8
fastjson 1.22
先编写一个恶意类Evil,编译为class文件后放在本地,我们需要他的字节码
这个类的构造方法中会Runtime.getRuntime().exec("calc");
1 | package com.fastjson.exploit; |
再编写(网上找了)一个调用了触发漏洞方法的客户端
1 | package com.fastjson.exploit; |
这个客户端做的事情也很简单:
读取class文件,并将其base64编码
创建json字符串 text1,其中
@type
设置为我们很熟悉的类TemplatesImpl
JSON.parseObject(text1, Object.class, config, Feature.SupportNonPublicField);
这是漏洞触发的核心点
这里我们转化为对象的字符串,也就是包含了恶意class的字符串为
1
2
3
4
5
6
7{
"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
"_bytecodes":["yv66vgAA...(省略一大段base64)"],
'_name':'a.b',
'_tfactory':{ },
"_outputProperties":{ }
}
分析
通过最简单的利用TemplatesImpl反序列化来学习fastjson1.22-1.24漏洞
在JSON.parseObject
处打上断点,下面主要分析这个方法中的流程
不得不说,这个调用还挺长的,所以我写的尽量详细点,对其中的一些方法和算法单独列出来分析,为以后回来看或者分析其他组件提供经验(吧。。)。
Fastjson反序列化的类方法调用关系
在这条利用TemplateImpl的利用链中,主要牵扯的还是靠左边的Deserializer
JSON.parseObject
先会对Feature数组进行遍历,并对mask值进行或运算,这里mask是有初值的,并将结果赋值给featureValues
接着会返回一个DefaultJSONParser对象
1 | DefaultJSONParser parser = new DefaultJSONParser(input, config, featureValues); |
可以看到我们的json字符串和features都被保存在这个parser里
其中lexer字段是一个JSONScanner对象,这里我们分析一下DefaultJSONParser对象的构造方法
DefaultJSONParser构造方法
可以看到这个构造方法中,根据我们传入的input和features,会先构造一个JSONScanner对象
这里由于ch是”{“,所以设置token为12
DefaultJSONParser.parseObject(Type type,Object fieldName)
接着调用parseObject方法,继续跟进
先返回token,这里为12,然后进到具体的处理部分
先返回一个derializer,然后再调用它其中的方法
JavaObjectDeserializer.deserialze
com.alibaba.fastjson.parser.deserializer.JavaObjectDeserializer.deserialze
因此我们跟进deserialize方法
由于parser.parseObject(clazz, (Object)null);
中传入的是Object类,所以这里跳过了if判断,直接进到return那一句里
三元运算为false,进到DefaultJSONParser.parse
方法中
DefaultJSONParser.parse(java.lang.Object)
最终会进到case 12里面
然后调用DefaultJSONParser.parseObject
方法
DefaultJSONParser.parseObject(java.util.Map, java.lang.Object)
因为在DefaultJSONParser的构造方法中已经调用过一次next方法了,所以现在的ch是"
,34,所以会进到这个判断
scanSymbol则会取出"
之间的数据
取出json对象的第一个key,也就是@type
还记得json中的
@type
所对应的数据是com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
,也就是我们要实例化的恶意类的类名。
加载了TemplateImpl类
然后接着往下走,就进入这个地方
这里先通过scanSymbol来获取到"
间的数据,然后用TypeUtils.loadClass
方法来加载这个类
最后在这个方法中实例化恶意类
JavaBeanDeserializer.deserialze
根据token为16,会先进到com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer#parseField
方法中
随后进入到com.alibaba.fastjson.parser.deserializer.DefaultFieldDeserializer#parseField
中,此处filedType判断为了这个class [[B
类型,然后再进入到下面的deserialze方法中
然后就取出了bytecodes字段
进入这个setValue方法中,可以看到传入的object就是TempaltesImpl对象,然后value即构造的恶意字节码
com.alibaba.fastjson.parser.deserializer.FieldDeserializer#setValue(java.lang.Object, java.lang.Object)
通过这个方法把_bytecodes
加入到TemplatesImpl对象中
然后他会通过这个parseFiled方法逐个取出parser也就是json中的字段名
直到解析这个字段,也就是_outputProperties
最后在com.alibaba.fastjson.parser.deserializer.FieldDeserializer#setValue(java.lang.Object, java.lang.Object)
中反射调用getOutputProperties方法,完成整个调用链调用,因为这里传入的object就是我们构造的恶意TemplatesImpl对象,这条攻击链可以在7d21中找到