Fastjson 漏洞分析

做者:icematcha@云影实验室java

0x00前言

近日,Fastjson被传爆出新的“0day”,也引发了你们的高度关注。云影实验室第一时间进行了跟进和分析,经过分析咱们发现,这次的漏洞并不算新的漏洞,其实官方早在去年五月就已经推出了相关补丁修复,但可能没有发布相关的安全通告,致使许多用户没有及时升级处理,而在这次护网中就谣传变成了如今的“0day”。PHP大马git

这次漏洞利用的核心点是java.lang.class这个java的基础类,在fastjson 1.2.48之前的版本没有作该类作任何限制,加上代码的一些逻辑缺陷,形成黑名单以及autotype的绕过。下面跟着代码看看这个类的具体应用。github

 

0x01分析过程

Fastjson在开始解析json前会优先加载配置,在加载配置时会调用TypeUtils的addBaseClassMappings和loadClass方法将一些常常会用到的基础类和三方库存放到一个ConcurrentMap对象mappings中,相似于缓存机制。json

配置加载完成后正式开始解析json数据,在ParserConfig.checkAutoType方法中对’@type’对应的value进行处理。fastjson在1.2.2+版本默认便再也不开启autoType选项,且在调用解析函数时咱们没有传入预期的反序列化对象的对应类名时,fastjson则经过从mappings中或者deserializers.findClass()方法来获取反序列化对象的对应类。缓存

找到对应类后便返回,再也不通过黑名单和autotype的检查流程。而java.lang.class该类刚好存在于deserializers对象的buckets属性中:安全

接着获取到java.lang.class对应的反序列化处理类MiscCodec:app

在MiscCodec类中,java.lang.class拥有加载任意类到mappings中的功能。首先从输入的json串中解析获取val对应的键值:函数

获取后调用前面提到的TypeUtils. loadClass()方法对该键值进行类加载操做:3d

在TypeUtils. loadClass()中,咱们就能够看到当cache参数为true时,将键值对应的类名放到了mappings中后返回:对象

Mappings是ConcurrentMap类的,顾名思义就是在当前链接会话生效。因此咱们须要在一次链接会话同时传入两个json键值对时,这次链接未断开时,继续解析第二个json键值对。此时咱们利用’@type’传入早已在黑名单中的com.sun.rowset.JdbcRowSetImpl类尝试jdni注入利用:奇热影视

能够看到fastjson直接从mappings中获取到了该类,并在作有效判断后,直接返回了:

此时的mappings中确实存在com.sun.rowset.JdbcRowSetImpl类:

而就像前面已经提到的,黑名单以及autotype开关的检查是在上面那处return以后的,因此也就变相的绕过了黑名单以及autotype开关的检查。

绕过了黑名单和autotype,剩下的利用过程就跟之前的利用彻底一致了,利用jdni注入来RCE:

因此最终的漏洞利用实际上是分为两个步骤,第一步利用java.lang.class加载黑名单类到mappings中,第二步直接从mappings中取出黑名单类完成漏洞利用。

 

0x02总结

回头来看看,我以为该漏洞更像是一个逻辑漏洞,而不是依赖一些硬性的漏洞利用点,是代码的运行逻辑缺陷形成的漏洞利用。

在1.2.48版本的补丁中,首先黑名单作了更新,加了两条,其中应该包含了java.lang.class这个类:

MiscCodec中也将传入的cache参数置为了false:

ParserConfig.checkAutoType()也调整了检查策略和逻辑。

 

0x03修复建议

Fastjson在1.2.47及如下的版本受影响,请及时升级到1.2.48及以上版本。

 

0x04参考连接

https://github.com/alibaba/fastjson