Fastjson 最想版本 RCE 漏洞【漏洞分析】

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.Appleat 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的《网络安全&黑客技术零基础到进阶全套学习大礼包》,可以扫描下方二维码免费领取在这里插入图片描述

 如果你有需要可以点击👉优快云大礼包:《嘿客&网络安全入门&进阶学习资源包》免费分享 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值