01 漏洞编号
CVE-2022-25845
CNVD-2022-40233
CNNVD-202206-1037
二、Fastjson 知多少
万恶之源 AutoType
Fastjson 的主要功能是将 Java Bean 序列化为 JSON 字符串,这样得到的字符串就可以通过数据库等方式进行持久化了。
但是,Fastjson 在序列化及反序列化的过程中,没有使用 Java 自带的序列化机制,而是自定义了一套机制。
对于 JSON 框架来说,想要把一个 Java 对象转换成字符串,有两种选择:
1、基于属性
2、基于 Setter/Getter
在我们常用的 JSON 序列化框架中,Fastjson 和 Jackson 将对象序列化成 Json 字符串时,是通过遍历该类中所有的 Getter 方法来进行的。而 Gson 不是这么做的,它是通过反射遍历该类中的所有属性,并把其值序列化为 Json 。
假设我们有下面这个 Java 类:
class Store {
private String name;
private Fruit fruit;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Fruit getFruit() {
return fruit;
}
public void setFruit(Fruit fruit) {
this.fruit = fruit;
}
}
interface Fruit {
}
class Apple implements Fruit {
private BigDecimal price;
//省略 setter/getter、toString等
}
当我们对它进行序列化时,Fastjson 会扫描其中的 Getter 方法,即找到 getName 和 getFruit,这时就会将 Name 和 Fruit 两个字段的值序列化到 JSON 字符串中。
那么问题来了,上面定义的 Fruit 只是一个接口,序列化的时候 Fastjson 能将属性值正确序列化出来吗?如果可以的话,反序列的时候,Fastjson 会把这个 Fruit 反序列化成什么类型呢?
我们尝试基于 Fastjson v1.2.68 验证一下:
Store store = new Store();
store.setName("Hollis");
Apple apple = new Apple();
apple.setPrice(new BigDecimal(0.5));
store.setFruit(apple);
String jsonString = JSON.toJSONString(store);
System.out.println("toJSONString : " + jsonString);
以上代码比较简单,我们创建了一个 store,为它指定了名称,并创建了 Fruit 的子类型 Apple,然后将 store 用 JSON.toJSONString 进行序列化,可以得到以下 JSON 内容:
toJSONString : {
"fruit":{
"price":0.5
}
,"name":"Hollis"
}
那么,Fruit 的类型是什么呢,能否反序列化为 Apple 呢?我们再来执行以下代码:
Store newStore = JSON.parseObject(jsonString, Store.class);
System.out.println("parseObject : " + newStore);
Apple newApple = (Apple)newStore.getFruit();
System.out.println("getFruit : " + newApple);
执行结果如下:
toJSONString : {
"fruit":{
"price":0.5
}
,"name":"Hollis"
}
parseObject : Store{
name='Hollis', fruit={}}
Exception in thread "main" java.lang.ClassCastException: com.hollis.lab.fastjson.test.$Proxy0 cannot be cast to com.hollis.lab.fastjson.test.Apple
at com.hollis.lab.fastjson.test.FastJsonTest.main(FastJsonTest.java:26)
可以看到,在将 store 反序列化后,我们尝试将 Fruit 转换成 Apple,但抛出了异常,如果直接转换成 Fruit 则不会报错,如下:
Fruit newFruit = newStore.getFruit();
System.out.println("getFruit : " + newFruit);
从以上现象中我们得知,当一个类中包含了一个接口(或抽象类)的时候,使用 Fastjson 进行序列化,会将子类型抹去,只保留接口(抽象类)的类型,使得反序列化时无法拿到原始类型。
如何解决这个问题呢?Fastjson 引入了AutoType
,在序列化时,把原始类型记录下来。使用方法是通过SerializerFeature.WriteClassName
进行标记,即将上述代码中的:
String jsonString = JSON.toJSONString(store);
修改为:
String jsonString = JSON.toJSONString(store,SerializerFeature.WriteClassName);
修改后的代码输出结果如下:
System.out.println("toJSONString : " + jsonString);
{
"@type":"com.hollis.lab.fastjson.test.Store",
"fruit":{
"@type":"com.hollis.lab.fastjson.test.Apple",
"price":0.5
}
,
"name":"Hollis"
}
可以看到,使用 SerializerFeature.WriteClassName 进行标记后,JSON 符串中多出了一个 @type 字段,标注了类对应的原始类型,方便在反序列化的时候定位到具体类型。**
如上,将序列化后的字符串再反序列化,就可以顺利拿到 Apple 类型,整体输出内容如下:
toJSONString : {
"@type":"com.hollis.lab.fastjson.test.Store","fruit":{
"@type":"com.hollis.lab.fastjson.test.Apple","price":0.5
}
,"name":"Hollis"
}
parseObject : Store{
name='Hollis', fruit=Apple{price=0.5}}
getFruit : Apple{price=0.5}
这就是 Fastjson 中引入 AutoType 的原因,但是也正因为这个特性,因为功能设计之初在安全方面考虑不周,给后续的 Fastjson 使用者带来了无尽的痛苦。
checkAutoType
Fastjson 为了实现反序列化引入了 AutoType,造成:
1、Fastjson 是基于内置黑名单来实现安全的,打开 AutoType 后可能造成安全风险,即绕过黑名单。
2、关闭 AutoType 后,是基于白名单进行防护的,此次解析的漏洞就是在未开启 AutoType 时产生的。
从 v1.2.25 版本开始,Fastjson 默认关闭了 AutoType 支持,并且加入了 checkAutoType,加入了黑白名单来防御 AutoType 开启的情况。
Fastjson 绕过历史可以分为 AutoType 机制绕过和黑名单绕过,绝大部分情况都是寻找一个新的利用链来绕过黑名单,所以 Fastjson 官方的黑名单列表越来越大;但是更有意义的绕过显然是 AutoType 机制绕过,这样无需手动配置 autoTypeSupport 也可能进行利用。
我们先来看一下通过 checkAutoType()校验的方式有哪些:
1、白名单里的类
2、开启了 AutoType
3、使用了 JSONType 注解
4、指定了期望类(expectClass)
5、缓存在 mapping 中的类
6、使用 ParserConfig.AutoTypeCheckHandler 接口通过校验的类
三、攻击思路
**目标:**绕过 AutoType 机制
**手段:**通过 checkAutoType()校验
**方法:**寻找使用 checkAutoType()的函数,并使之通过 checkAutoType()校验
通过研究 v1.2.50 和 v1.2.68 的绕过方式,主要是在 ObjectDeserializer 接口的子类 JavaBeanDeserializer 中存在 expectClass 非空的 checkAutoType 调用,这也是绕过的关键。顺着这个思路,我们继续在 ObjectDeserializer 接口的其他子类中寻找 expectClass 非空的 checkAutoType 调用,发现在子类 ThrowableDeserializer 的函数 deserialze 中也存在满足条件的调用。
如果你对网络安全入门感兴趣,那么你点击这里👉优快云大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享
如果你对网络安全感兴趣,学习资源免费分享,保证100%免费!!!(嘿客入门教程)a
1.成长路线图&学习规划
要学习一门新的技术,作为新手一定要先学习成长路线图,方向不对,努力白费。
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图&学习规划。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
2.视频教程
很多朋友都不喜欢晦涩的文字,我也为大家准备了视频教程,其中一共有21个章节,每个章节都是当前板块的精华浓缩。
3.SRC&黑客文籍
大家最喜欢也是最关心的SRC技术文籍&黑客技术也有收录
SRC技术文籍:
黑客资料由于是敏感资源,这里不能直接展示哦!
4.护网行动资料
其中关于HW护网行动,也准备了对应的资料,这些内容可相当于比赛的金手指!
5.黑客必读书单
6.面试题合集
当你自学到这里,你就要开始思考找工作的事情了,而工作绕不开的就是真题和面试题。
更多内容为防止和谐,可以扫描获取~
需要全套共282G的《网络安全&黑客技术零基础到进阶全套学习大礼包》,可以扫描下方二维码免费领取!