fastjson记录
参考指南
fastjson:我一路向北,离开有你的季节 | 素十八 (su18.org)
1|0fastjson基础
fastjson 功能要点:
-
fastjson 在创建一个类实例时会通过反射调用类中符合条件的 getter/setter 方法以及构造方法,其中
- getter 方法需满足条件:方法名长于 4、不是静态方法、以
get
开头且第4位是大写字母、方法不能有参数传入、继承自Collection|Map|AtomicBoolean|AtomicInteger|AtomicLong
、此属性没有 setter 方法; - setter 方法需满足条件:方法名长于 4,以
set
开头且第4位是大写字母、非静态方法、返回类型为 void 或当前类、参数个数为 1 个。具体逻辑在com.alibaba.fastjson.util.JavaBeanInfo.build()
中。 - 构造方法:优先选无参构造,没有无参构造会选取唯一的构造方法。如有多个构造方法,优先选参数最多的public构造方法。如参数最多的构造方法有多个则随机选取一个构造方法。如果被实例化的是静态内部类,也可以忽视修饰。如果被实例化的是非public类,构造方法里的的参数类型仍然可以进一步反序列化
- public field参数类型以及静态代码块;
- getter 方法需满足条件:方法名长于 4、不是静态方法、以
-
fastjson 在为类属性寻找 get/set 方法时,调用函数
com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer#smartMatch()
方法,会忽略_|-
字符串,也就是说哪怕你的字段名叫_a_g_e_
,getter 方法为getAge()
,fastjson 也可以找得到,在 1.2.36 版本及后续版本还可以支持同时使用_
和-
进行组合混淆。 -
如果目标类中私有变量没有 setter 方法,但是在反序列化时仍想给这个变量赋值,则需要使用
Feature.SupportNonPublicField
参数。
2|0漏洞分析
2|1早期
经典利用有两条利用链
-
JdbcRowSetImpl(JNDI) (lookup,最常见)
-
TemplatesImpl(Feature.SupportNonPublicField)(jdk7u21的利用链触发方式)
2|2分析
com.alibaba.fastjson.JSON#parse(java.lang.String, int)中的parse方法实例化一个DefaultJSONParser对象并调用parse方法,之后跟进
DefaultJSONParser会初始化lexer进行不同操作,这个 lexer 属性实际上是在 DefaultJSONParser 对象被实例化的时候创建的,初始化了个JSONScanner对象
因为在DefaultJSONParser操作中可明显看到token为12
com.alibaba.fastjson.parser.DefaultJSONParser#parse(java.lang.Object),
这里new 了一个 JSONObject 对象之后进入parseObject方法
com.alibaba.fastjson.parser.DefaultJSONParser#parseObject(java.util.Map, java.lang.Object),检测json格式,并对下个字符进行判断。
进行判断后,获取@type对应值,之后使用loadClass进行装载。之后getDeserializer获取序列化对象,com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer#deserialze(com.alibaba.fastjson.parser.DefaultJSONParser, java.lang.reflect.Type, java.lang.Object, java.lang.Object, int)最终进行对其进行反射调用setter操作执行漏洞代码;
com.alibaba.fastjson.util.TypeUtils#loadClass(java.lang.String, java.lang.ClassLoader),只要存在就会缓存到mappings里;
2|3中期修复
1.2.25版本更新中新增autoTypeSupport默认为false,将不支持指定类的反序列化。并通过checkAutoType函数对加载类进行黑名单+白名单验证;
获取类对象的方法由原来的TypeUtils.loadClass替换为了checkAutoType
com.alibaba.fastjson.parser.ParserConfig#checkAutoType,
- 如果开启了 autoType,先判断类名是否在白名单中,如果在,就使用
TypeUtils.loadClass
加载,然后使用黑名单判断类名的开头,如果匹配就抛出异常。 - TypeUtils.mappings 中和 deserializers 中尝试查找要反序列化的类,存在则return;
- 如果没开启 autoType ,则是先使用黑名单匹配,再使用白名单匹配和加载。最后,如果要反序列化的类和黑白名单都未匹配时,只有开启了 autoType 或者 expectClass 不为空也就是指定了 Class 对象时才会调用
TypeUtils.loadClass
加载。因此中期的相关漏洞基本集中于此;
TypeUtils.loadClass的方法和checkAutoType存在判断差异导致了绕过;(需要开启autoType),调用loadClass方法是循环调用,并且第二个'['也可以进行绕过
Lcom.sun.rowset.JdbcRowSetImpl;
LLLcom.sun.rowset.JdbcRowSetImpl;;;"[com.sun.rowset.JdbcRowSetImpl"[
之后再1.2.42中延续之前检测模式并且将黑名单采用hash方式,避免了反向研究;
还有就是针对loadClass的修补,以及相关黑名单的添加;
2|4fastjson-1.2.47
到了1.2.47,出现了部分通杀AutoTypeSupport利用漏洞;
影响版本:1.2.25 <= fastjson <= 1.2.32 未开启 AutoTypeSupport
影响版本:1.2.33 <= fastjson <= 1.2.47
POC:
以上我们可以看到是解析两个对象,第一个是java.lang.Class,其不在黑名单,因此checkAutoType会顺利通过;
由前文的checkAutoType逻辑可以发现在两次AutoTypeSupport判断中间存在缓存读取的逻辑;而本次的绕过逻辑也主要集中在此;至于影响版本的差异主要是AutoTypeSupport开启的黑名单判断中增加了TypeUtils.mappings是否存在该类缓存的判断。
- deserializers 位于
com.alibaba.fastjson.parser.ParserConfig.deserializers
,是一个 IdentityHashMap;这个map的key为各种Class类型,value为其对应的反序列化处理类。赋值的函数有:getDeserializer()
:这个类用来加载一些特定类,以及有JSONType
注解的类,在 put 之前都有类名及相关信息的判断,无法为我们所用。initDeserializers()
:无入参,在构造方法中调用,写死一些认为没有危害的固定常用类,无法为我们所用。putDeserializer()
:被前两个函数调用,我们无法控制入参。
- TypeUtils.getClassFromMapping(typeName)。这个方法从
TypeUtils.mappings
中取值,这是一个 ConcurrentHashMap 对象addBaseClassMappings()
:无入参,加载loadClass()
:关键函数
关注com.alibaba.fastjson.serializer.MiscCodec#deserialze
方法,这个类主要用于处理特定功能的反序列化类;包括Class.calss类,因此成为入口
com.alibaba.fastjson.serializer.MiscCodec#deserialze
因此,当1.2.32之前版本需要AutoTypeSupport为false,才能走到获取缓存mapping的操作,而33-47的版本因为在AutoTypeSupport第一步检查中mapping判断多了一步缓存检查,导致了绕过;
2|5fastjson-1.2.68
影响版本:fastjson <= 1.2.68
描述:利用 expectClass 绕过 checkAutoType()
,实际上也是为了绕过安全检查的思路的延伸。主要使用 Throwable
和 AutoCloseable
进行绕过。
47之后进行了修复,cache设置为false,并且loadClass设置为默认调用不缓存。
1.2.68新增了个安全控制点sfaeMode,开启safeMode表示完全禁用autoType;
在 checkAutoType()
函数中有这样的逻辑:如果函数有 expectClass
入参,且我们传入的类名是 expectClass
的子类或实现,并且不在黑名单中,就可以通过 checkAutoType()
的安全检测。并且会添加入缓存mappings中,进而后续思路就如1.2.47;
可控expectClass入参的方法:
ThrowableDeserializer#deserialze()
,需要为Throwable子类JavaBeanDeserializer#deserialze()
AutoCloseable白名单,其子类
3|0展望
codeql利用挖掘fastjson
漏洞分析 | 利用 CodeQL 分析 fastjson 1.2.80 利用链-安全客 - 安全资讯平台 (anquanke.com)
__EOF__

本文链接:https://www.cnblogs.com/sentient-being/p/18084972.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!