千家信息网

如何进行Fastjson 1.2.24反序列化漏洞深度分析

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,如何进行Fastjson 1.2.24反序列化漏洞深度分析,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。前言FastJson是aliba
千家信息网最后更新 2026年10月31日如何进行Fastjson 1.2.24反序列化漏洞深度分析

如何进行Fastjson 1.2.24反序列化漏洞深度分析,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

前言

FastJson是alibaba的一款开源JSON解析库,可用于将Java对象转换为其JSON表示形式,也可以用于将JSON字符串转换为等效的Java对象。近几年来fastjson漏洞层出不穷,下面将会谈谈近几年来fastjson
RCE漏洞的源头:17年fastjson爆出的1.2.24反序列化漏洞。以这个漏洞为基础,详细分析fastjson漏洞的一些细节问题。

关于Fastjson 1.2.24反序列化漏洞,自从17年以来已经有很多人分析过了,一些基础内容本文就不再陈述了。此次漏洞简单来说,就是Fastjson通过parseObject/parse将传入的字符串反序列化为Java对象时由于没有进行合理检查而导致的

小编将着重分析一下这个漏洞没有被详细介绍过的细节问题,如下:

1、parseObject(String text) 、parse (String text)、 parseObject(String text, Class\ clazz)三个方法从代码层面上来看,究竟有何不同?

2、使用TemplatesImpl攻击调用链路构造poc时,为什么一定需要构造_tfactory以及_name字段?

3、_outputProperties与其getter方法getOutputProperties()方法名字并不完全一致是如何解决的?

除此之外,在介绍TemplatesImpl攻击调用链路时,以模拟寻找漏洞利用链的思路,从最终的执行点开始向上寻找入口,模拟还原出挖掘这个TemplatesImpl利用链的完整过程。

漏洞分析

关于parse (String text) 、parseObject(String text)、 parseObject(String text, Class\ clazz)三个方法,我们进行一个测试

FastJsonTest类中变量以及其setter/getter关系如下表

| | public String t1 | private int t2 | private Boolean t3 | private Properties t4 | private Properties t5 |
| ------ | ---------------- | -------------- | ------------------ | --------------------- | --------------------- |
| setter | 有 | 有 | 无 | 无 | 有 |
| getter | 有 | 有 | 有 | 有 | 有 |

接下来,我们分别使用下图三种方式分别将JSON字符串反序列化成Java对象

1、Object obj = JSON.parse(jsonstr);

2、Object obj = JSON.parseObject(jsonstr, FastJsonTest.class);

3、Object obj = JSON.parseObject(jsonstr);

首先我们运行一下Object obj = JSON.parse(jsonstr);这种方式

结果:

setT1() 、setT2() 、getT4() 、setT5() 被调用

JSON.parse(jsonstr)最终返回FastJsonTest类的对象

接着我们运行下Object obj = JSON.parseObject(jsonstr, FastJsonTest.class);

结果:

与JSON.parse(jsonstr);这种方式一样setT1() 、setT2() 、getT4() 、setT5() 被调用

JSON.parse(jsonstr)最终返回FastJsonTest类的对象

最后我们运行下Object obj = JSON.parseObject(jsonstr);

结果:

这次结果与上两次大不相同,FastJsonTest类中的所有getter与setter都被调用了,并且JSON.parseObject(jsonstr);返回一个JSONObject对象

通过上文运行结果,不难发现有三个问题

1. 使用JSON.parse(jsonstr);与JSON.parseObject(jsonstr, FastJsonTest.class);两种方式执行后的返回结果完全相同,且FastJsonTest类中getter与setter方法调用情况也完全一致,parse(jsonstr)与parseObject(jsonstr, FastJsonTest.class)有何关联呢?

2. 使用JSON.parse(jsonstr);与JSON.parseObject(jsonstr, FastJsonTest.class);两种方式时,被调用的getter与setter方法分别为setT1()、setT2()、setT5()、getT4()。FastJsonTest类中一共有五个getter方法,分别为getT1()、getT2()、getT3()、getT4()、getT5(),为什么仅仅getT4被调用了呢?

3. JSON.parseObject(jsonstr);为什么返回值为JSONObject类对象,且将FastJsonTest类中的所有getter与setter都被调用了

问题一解答

经过调试可以发现,无论使用JSON.parse(jsonstr);或是JSON.parseObject(jsonstr,
FastJsonTest.class);方式解析json字符串,程序最终都会调用位于com/alibaba/fastjson/util/JavaBeanInfo.java中的JavaBeanInfo.build()
方法来获取并保存目标Java类中的成员变量以及其对应的setter、getter

首先来看下JSON.parse(jsonstr)这种方式,当程序执行到JavaBeanInfo.build()
方法时情景如下图

此时的调用链如下图

此时传入JavaBeanInfo.build() 方法的参数值如下图

再来看下JSON.parseObject(jsonstr,
FastJsonTest.class)这种方式,当程序执行到JavaBeanInfo.build() 方法时情景如下图

此时的调用链如下图

此时传入JavaBeanInfo.build() 方法的参数值如下图

二者执行到JavaBeanInfo.build() 方法时调用链对比如下

可见二者后面的调用链是完全一样的。二者不同点在于调用JavaBeanInfo.build()
方法时传入clazz参数的来源不同:

JSON.parseObject(jsonstr, FastJsonTest.class)在调用JavaBeanInfo.build()
方法时传入的clazz参数源于parseObject方法中第二个参数中指定的"FastJsonTest.class"。

JSON.parse(jsonstr);这种方式调用JavaBeanInfo.build()
方法时传入的clazz参数获取于json字符串中\@type字段的值。

关于JSON.parse(jsonstr);从json字符串中\@type字段获取clazz参数,具体代码如下

程序通过解析传入的json字符串的\@type字段值来获取之后传入JavaBeanInfo.build()
方法的clazz参数

因此,只要Json字符串的\@type字段值与JSON.parseObject(jsonstr,
FastJsonTest.class);中第二个参数中类名一致,见下图

JSON.parse(jsonstr)与JSON.parseObject(jsonstr,FastJsonTest.class)这两种方式执行的过程与结果是完全一致的。二者唯一的区别就是获取clazz参数的途径不同

问题二解答

> 使用JSON.parse(jsonstr)与JSON.parseObject(jsonstr, FastJsonTest.class)两种方式时,被调用的getter与setter方法分别为setT1()、setT2()、setT5()、getT4()。FastJsonTest类中一共有五个getter方法,分别为getT1()、getT2()、getT3()、getT4()、getT5(),为什么仅仅getT4被调用了呢?

这个问题要从JavaBeanInfo.build() 方法中获取答案:

通过上文的分析可以发现,程序会使用JavaBeanInfo.build()
方法对传入的json字符串进行解析。在JavaBeanInfo.build()
方法中,程序将会创建一个fieldList数组来存放后续将要处理的目标类的 setter
方法及某些特定条件的 getter
方法。通过上文的结果可见,目标类中所有的setter方法都可以被调用,但只有getT4()这一个getter被调用,那么到底什么样的getter
方法可以满足要求并被加入fieldList数组中呢?

在JavaBeanInfo.build() 方法可见如下代码

程序从clazz(目标类对象)中通过getMethods获取本类以及父类或者父接口中所有的公共方法,接着进行循环判断这些方法是否可以加入fieldList中以便后续处理

条件一、方法名需要长于4

条件二、不是静态方法

条件三、以get字符串开头,且第四个字符需要是大写字母

条件四、方法不能有参数传入

条件五、继承自Collection \|\| Map \|\| AtomicBoolean \|\| AtomicInteger \|\|
AtomicLong

条件六、此getter不能有setter方法(程序会先将目标类中所有的setter加入fieldList列表,因此可以通过读取fieldList列表来判断此类中的getter方法有没有setter)

问题三解答

JSON.parseObject(jsonstr)为什么返回值为JSONObject类对象,且将FastJsonTest类中的所有getter与setter都被调用了

通过上文的分析可以发现,JSON.parse(jsonstr)与JSON.parseObject(jsonstr,
FastJsonTest.class)两种方式从执行流程几乎一样,结果也完全相同;然而使用JSON.parseObject(jsonstr)这种方式,执行的结果与返回值却与前两者不同:JSON.parseObject(jsonstr)返回值为JSONObject类对象,且将FastJsonTest类中的所有getter与setter都被调用。

通过阅读源码可以发现JSON.parseObject(String text)实现如下

parseObject(String text)其实就是执行了parse(),随后将返回的Java对象通过JSON.toJSON()转为
JSONObject对象。

JSON.toJSON()方法会将目标类中所有getter方法记录下来,见下图

随后通过反射依次调用目标类中所有的getter方法

完整的调用链如下

总结:

上文例子中,JSON.parse(jsonstr)与JSON.parseObject(jsonstr, FastJsonTest.class)可以认为是完全一样的,而parseObject(String text)是在二者的基础上又执行了一次JSON.toJSON()

parse(String text)、parseObject(String text)与parseObject(String text, Class\ clazz)目标类Setter\\Getter调用情况

| | parse(String text) | parseObject(String text) | parseObject(String text, Class\ clazz) |
| -------------- | ------------------ | ------------------------ | ------------------------------------------ |
| Setter调用情况 | 全部 | 全部 | 全部 |
| Getter调用情况 | 部分 | 部分 | 全部 |

此外,如果目标类中私有变量没有setter方法,但是在反序列化时仍想给这个变量赋值,则需要使用Feature.SupportNonPublicField参数。(在下文中,为TemplatesImpl类中无setter方法的私有变量_tfactory以及_name赋值运用到的就是这个知识点)

TemplatesImpl攻击调用链路

针对于上文的分析可以发现,无论使用哪种方式处理JSON字符串,都会有机会调用目标类中符合要求的Getter方法

如果一个类中的Getter方法满足调用条件并且存在可利用点,那么这个攻击链就产生了。

TemplatesImpl类恰好满足这个要求:

com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl中存在一个名为_outputPropertiesget的私有变量,其getter方法中存在利用点,这个getter方法恰好满足了调用条件,在JSON字符串被解析时可以调用其在调用FastJson.parseObject()序列化为Java对象时会被调用,下面我们详细说明一下:

首先我们从漏洞点开始,一层层往入口分析:首先看一下TemplatesImpl类中的getTransletInstance方法

其中455行调用_class[_transletIndex]的newInstance( )方法来实例化对象的操作

我们看一下_class[_transletIndex]是如何获取的,是否可以控制

\_class与_transletIndex值皆由451行处defineTransletClasses()方法中获取

我们跟入defineTransletClasses()方法中一探究竟

在defineTransletClasses()方法中,首先在393行判断_bytecodes值是否为空

值得注意的是,_bytecodes变量是TemplatesImpl类的成员变量

因此_bytecodes变量可以在构造json字符串时传入,在构造poc时属于可控变量

\_bytecodes变量非空值时,程序将会继续执行至下图红框处

此时,需要满足_tfactory变量不为null,否则导致程序异常退出。这就是为什么公开的poc中需要设置设置_tfactory为{
}的原因。因为_tfactory为私有变量,且无setter方法,这里需要指定Feature.SupportNonPublicField参数来为_tfactory赋值

接下来,程序将会把_bytecodes变量中的值循环取出并通过loader.defineClass处理后赋值给_class[i]

我们首先来看下loader.defineClass方法是什么

可见,loader.defineClass方法其实就是对ClassLoader.
defineClass的重写。defineClass方法可以从传入的字节码转化为Class

回头分析下上述流程

\_bytecodes变量非空值时,程序将会把_bytecodes数组中的值循环取出,使用loader.defineClass方法从字节码转化为Class对象,随后后赋值给_class[i]。

如果此时的class为main
class,_transletIndex变量值则会是此时_bytecodes数组中的下标值

因此当我们构造出_bytecodes:[evilCode]这样的json字符串(evilCode字符串为我们构造的恶意类的字节码)后,程序会将evilCode化为Class对象后赋值给_class[0]

现在回到getTransletInstance()方法中

此时的_class[_transletIndex]即为我们构造传入的evilCode类

程序通过调用evilCode类的newInstance()方法来实例化对象的操作,这将导致我们构造的evilCode类中的恶意代码被执行

但在此之前,需要在poc构造json字符串时使得成员变量_name不为空,否则程序还未执行到将evilCode类实例化就提前return

注意:由于私有变量_name没有setter方法,在反序列化时想给这个变量赋值则需要使用Feature.SupportNonPublicField参数。

在分析完存在漏洞的getTransletInstance方法,我们需要找到一条调用链,这条调用链需要在使用fastjson处理json字符串时成功串连到存在漏洞的getTransletInstance方法上。

我们继续向上跟踪代码

com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java
newTransformer()方法中调用了getTransletInstance()

继续向上跟踪

com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java
getOutputProperties()方法中调用了newTransformer()

getOutputProperties()方法为_outputProperties成员变量的getter方法

细心的读者可能会发现,成员变量_outputProperties与其getter方法getOutputProperties()方法名字并不完全一致,多了一个下划线,fastjson是如何将其对应的呢?

实际上,fastjson在解析的时候调用了一个smartMatch() 方法

在寻找_outputProperties的getter方法时,程序将下划线置空,从而产生了成员变量_outputProperties与getter方法getOutputProperties()对应的形式

FastJson与TemplatesImpl的有趣结合

首先说TemplatesImpl类。经过上文分析可发现:TemplatesImpl中存在一个反序列化利用链,在反序列化过程中,如果该类的getOutputProperties()方法被调用,即可成功触发代码执行漏洞。

再来分析下FastJson:经过上文对FastJson三种不同途径处理JSON字符串时关于getter方法被调用的条件来看,TemplatesImpl类_outputProperties成员变量的getter方法满足被调用条件。无论通过fastjson哪种方式解析json字符串,都会触发getOutputProperties()方法。

二者放在一起一拍即合:FastJson在反序列化TemplatesImpl类时会恰好触发TemplatesImpl类的getOutputProperties()方法;TemplatesImpl类的getOutputProperties()方法被触发就会引起反序列化代码执行漏洞。所以说这个漏洞利用很是巧妙。

看完上述内容,你们掌握如何进行Fastjson 1.2.24反序列化漏洞深度分析的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注行业资讯频道,感谢各位的阅读!

方法 变量 字符 字符串 漏洞 对象 程序 方式 分析 参数 序列 条件 目标 结果 问题 上文 代码 成员 不同 就是 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技 喔噻互联网科技有限公司 北京路客互联网科技有限公司 互联网科技公司的优势 互联网科技公司发展 中国互联网科技发展 亿人帮互联网科技 四川狮子座互联网科技 金融科技和互联网金融 科技大学互联网专业好不好 衡水科技产业互联网平台 湖南诚度互联网科技有限公司 晓花互联网科技有限公司网址 佛山市翊博互联网络科技有限公司 南博望互联网科技有限公司 小米互联网科技园入驻 广州富喜互联网络科技 上海创道互联网络科技有限公司 互联网界的黑科技 互联网科技和医药行业 科技创新与互联网经济 科技互联网政务服务 有马互联网科技 电子科技大学互联网 贵州叶脉互联网科技有限公司所属行业 艺电能源互联网科技有限公司招聘 云南互联网科技学费 盐城市攀科互联网科技有限公司 陕西彩京云互联网科技有限公司 互联网 科技节活动 微视频大赛
0