0x01.Before Version 1.2.24
此版本AutoType功能默认开启,且没有任何类黑名单限制。测试代码如下:
import com.alibaba.fastjson.JSON; |
漏洞成因首先是反序列化过程中会根据@type字段来加载对应的Class。

第二点就是会通过反射执行对应Class的两个setter方法,根据字段分别是setDataSourceName和setAutoCommit。setDataSourceName会在其父类javax.sql.rowset#BaseRowSet设置dataSource为恶意ldap服务地址。

在setAutoCommit会调用到connect方法,其中根据dataSource作为参数调用javax.naming.InitialContext#lookup,很明显就是JNDI注入了嘛。

如果目标不出网就需要第二条链子,CC3使用到的com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl这个类,POC如下:
import com.alibaba.fastjson.JSON; |
我写payload的时候发现一直执行失败,后面才知道_bytecodes字段的字节码会在反序列化过程中通过com.alibaba.fastjson.util.IOUtils#decodeBase64解码。那么序列化过程中有些情况下也会调用encodeBase64。
这条链子后面就是调用TemplatesImpl#getOutputProperties方法了,没啥好说的,后续调用链如下(参考CC3):
TemplatesImpl#getOutputProperties() -> TemplatesImpl#newTransformer() -> |

0x02.Version 1.2.25-1.2.41
针对1.2.25的修复方案引入checkAutoType防护机制,采用黑名单 + 白名单方式防御。默认关闭AutoType支持,并将常见的恶意类包名加入黑名单。

黑名单如下:
private String[] denyList = "bsh,com.mchange,com.sun.,java.lang.Thread,java.net.Socket,java.rmi,javax.xml,org.apache.bcel,org.apache.commons.beanutils,org.apache.commons.collections.Transformer,org.apache.commons.collections.functors,org.apache.commons.collections4.comparators,org.apache.commons.fileupload,org.apache.myfaces.context.servlet,org.apache.tomcat,org.apache.wicket.util,org.codehaus.groovy.runtime,org.hibernate,org.jboss,org.mozilla.javascript,org.python.core,org.springframework".split(","); |
如下可以发现黑名单的匹配其实是匹配Class前缀的。并且是先进行白名单匹配的。

绕过Payload如下,前提是AutoType,所以Payload中用了一行先开启。
import com.alibaba.fastjson.JSON; |
这个绕过方法就是在类名中以L开头和;结尾绕过黑名单。checkAutoType中会调用com.alibaba.fastjson.util.TypeUtils#loadClass,其中会对className进行处理,保证能够成功加载这个Class。

0x03.Version 1.2.42
针对上一版本的绕过,修复方案是进一步加强checkAutoType逻辑判断,限制部分特殊字符的使用。


之前的黑名单以及白名单还转成了Hash。不过我记得在GitHub上有人搞了个Hash对照Class的。

绕过很好绕过,由于不是递归处理删除L和;。双写就可以绕过,Payload如下:
import com.alibaba.fastjson.JSON; |
0x04.Version 1.2.43-1.2.44
此版本修复了双写绕过。


但是com.alibaba.fastjson.util.TypeUtils#loadClass依然没动,这个版本的Payload如下,利用了 FastJSON 解析器对非标准格式的宽松处理。
import com.alibaba.fastjson.JSON; |
当进入checkAutoType,typeName为[com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl,能够成功绕过检测来到TypeUtils#loadClass中。其中包含了对[符号的处理。在checkAutoType返回时能够正确返回[com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl对象。

0x05.Version 1.2.44
拦了[符号。


0x06.Version 1.2.45
在1.2.25-1.2.45版本期间,爆出一个对黑名单的绕过,引入新的Gadgets,在mybatis组件org.apache.ibatis.datasource.jndi.JndiDataSourceFactory#setProperties方法中,存在JNDI注入。

构造Payload如下:
import com.alibaba.fastjson.JSON; |

0x07.Verison 1.2.46
上一版本绕过黑名单的org.apache.ibatis.datasource.jndi.JndiDataSourceFactory被新加入黑名单。

0x08.Verison 1.2.47
上述所有绕过都基于一个前提,autoTypeSupport开启为true。但在1.2.47版本中将出现绕过这一机制的方法,即1.2.25-1.2.47将通杀。当autoTypeSupport即使为false时,也会在进入黑名单判断之前,在TypeUtils.mappings中和deserializers中寻找要反序列化的类,如果找到了,则就会返回。如果在mappings中缓存有待加载的恶意类,那么autoTypeSupprot即使为false也能通杀。

跟进看一下com.alibaba.fastjson.util.TypeUtils#getClassFromMapping,向mappingss中获取@type指定的类名。

在此类中搜索mappings.put,发现也只有TypeUtils#addBaseClassMappings以及TypeUtils#loadClass方法。addBaseClassMappings是一个无参函数,并且经过分析,它的put只能加载固定的Class实例。看看loadClass,是能够调用过去执行put的。并且执行put的地方有三处。

该loadClass又会被另一个重载的loadClass引用。

而该重载的loadClass又会被com.alibaba.fastjson.serializer.MiscCodec#deserialze引用。

当parser.resolveStatus等于TypeNameRedirect然后就会进行一系列解析,这里面参数解析真是相当难懂,直接用Payload来调试分析。
if (parser.resolveStatus == DefaultJSONParser.TypeNameRedirect) { |
Payload如下:
import com.alibaba.fastjson.JSON; |
首先第一个判断语句,只要带有@type都会通过的。往下判断lexer的是否有val字段,有的话取出来解析给objVal(com.sun.rowset.JdbcRowSetImpl)。以及后面的strVal,然后只要@type是java.lang.Class就会调用loadClass。

然后调用mappings.put将利用类加入缓。

解析第二段json时,能直接从mappings缓存中找到利用类,直接返回。这时候还没有进入autoTypeSupprot为false的判断逻辑。

0x09.Version 1.2.48-1.2.68
通过mappings缓存这种方式在1.2.48版本后续了修复,修复方法时在com.alibaba.fastjson.serializer.MiscCodec#deserialze调用loadClass时,不走中间那个重载loadClass方法了,并且那个重载loadClass方法调用利用的loadClass方法的第三个参数cache默认为false了,最重要的是deserialze调用loadClass方法的cache参数也传入的false,这样调用的loadClass不会调用mappings.put。


在1.2.68版本中,引入了一个新的安全机制safeMode,查看checkAutoType可以发现,如果safeMode开启,将直接抛出异常。都不用直接管autoTypeSupport了。如下三个方式之一判断safeMode是否开启:
- 当前ParserConfig实例上设置的safeMode(通过
setSafeMode(true)设置) - 调用parseObject等方法时显式传入的Feature掩码
- 全局静态默认特性集
调试能够发现此版本上safeMode默认关闭。

但在此版本又出现了一个利用期望类expectClass全新的方式来绕过autoTypeSupport为false的情况。在执行严格的判断autoTypeSupprot之前会通过一个简单的判断,如果autoTypeSupport、jsonType、expectClassFlag其中之一满足一个true的话,会调用com.alibaba.fastjson.util.TypeUtils#loadClass加载@type指定的恶意类。如果checkAutoType的第三个参数expectClass是加载祖先类就会直接返回这个Class,绕过严格的autoTypeSupport判断,但是并没有绕过黑名单Class检查。
if (autoTypeSupport || jsonType || expectClassFlag) { |
当exceptClass不为null时,expectClassFlag变量也就会为true。

其中能够自定义传入expectClass的地方也就两处:
com.alibaba.fastjson.parser.deserializer.ThrowableDeserializer#deserialzecom.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer#deserialze

首先看到第一处在ThrowableDeserializer#deserialze中,传入的exceptClass为Throwable.class。

返回加载类后,通过ThrowableDeserializer#createException创建加载类实例。

如下是createException实现,其中会调用newInstance,那么将恶意代码写到构造方法、静态方法是不是也可以执行呢?

所以构造Payload如下:
import com.alibaba.fastjson.JSON; |
恶意类定义如下,可以继承Exception类,因为Exception类又继承Throwable类。
package org.example; |

按此Payload执行,首先会加载第一个@type指明的类java.lang.Exception。因为java.lang.Exception是JDK自带的基类,不在黑名单中,且属于内部缓存允许的类(com.alibaba.fastjson.util.TypeUtils#getClassFromMapping),checkAutoType直接放行。

Fastjson发现Exception Throwable的子类,于是决定使用ThrowableDeserializer(异常反序列化器)来处理接下来的JSON数据。于是就调用到了ThrowableDeserializer#deserialze其中的那个checkAutoType方法,传入的exceptClass为Throwable.class,然后就和之前分析的那样,不会进入autoTypeSupport的严格检查,但仍会收到两处黑名单的校验。

返回后就和正常Fastjson解析过程一样了,会调用Payload对应setter、getter方法。

对于自定义传入expectClass的第二处地方传入的expectClass参数为java.lang.AutoCloseable,除此之外和第一处地方原理完全一致。

Payload如下:
package org.example; |

在此版本的利用中,Fastjson在判断期望类之前将继承自ClassLoader、DataSource、RowSet的类直接抛出异常,加上前面两个黑名单判断,就有三道门禁了,但是重点是我们能够绕过AutoType了,所以需要一些新的gadgets。

具体新利用链是利用org.apache.commons.io这个Class,参考 : https://mp.weixin.qq.com/s/6fHJ7s6Xo4GEdEGpKFLOyg 。
0x0A.Version 1.2.69-1.2.80
在Fastjson 1.2.80版本中,利用方式和Fastjson 1.2.68版本一致,还是用期望类,只是之前利用AutoCloseable来进行文件读写,那么在1.2.69这个Class肯定被加入黑名单了嘛。那么在1.2.80版本中,利用的期望类便是Throwable.class。

利用类为包括:
org.codehaus.groovyorg.python、org.postgresql、org.springframeworkorg.aspectj
参考:
0x0B.END
临近2026 HVV,FastJson 1.8.3和2.0.53又爆洞了,建议就是不用这个组件,用Jackson,虽然比FastJson慢,但是安全啊(hhhh)。