与原生的Java反序列化的区别在于,FastJson反序列化并未使用
ObjectInputStream.readObject()方法,而是由FastJson自定一套反序列化的过程。通过在反序列化的过程中自动调用类属性的setter/getter方法,将JSON字符串还原成对象,当这些自动调用的方法中存在可利用的潜在危险代码时,漏洞便产生了。
FastJson反序列化漏洞的演变历程
自从2017年爆出FastJson1.2.24版本反序列化漏洞后,近几年安全人员在不断寻找新的利用方式。
自FastJson1.2.25版本开始,FastJson关闭了默认开启的AutoType,并且内置了一个黑名单,用于防止存在风险的类进行序列化。
由于FastJson 1.2.41版本和1.2.42版本对类名处理不当,导致黑名单机制被绕过,在修复该漏洞的同时还将黑名单进行加密,增加了研究成本。
在FastJson1.2.45版本中,研究人员发现新的可利用的类,且不在黑名单中。
在FastJson1.2.47版本中,研究人员发现通过缓存机制,能够绕过AutoType的限制和黑名单机制。
在2020年,FastJson1.2.68版本又被发现新的绕过AutoType的方式,也是通过缓存的方式绕过,但具体成因的代码逻辑有些差异,利用难度也较先前版本更大。
在2022年5月,FastJson1.2.80版本又被发现新的绕过AutoType的方式。
从上述FastJson反序列化漏洞可以看出漏洞利用主要集中在如下的2个方面。
寻找新的利用链,绕过黑名单;
寻找绕过AutoType的方式;
2. FastJson反序列化漏洞的基础
FastJson将JSON还原成对象的方法有以下3种。
parse(String text);
parseObject(String text);
parseObject(String input, Class clazz);
当通过这3种方法将JSON还原成对象时,FastJson自动调用类中的setter方法和无参构造函数,以及满足条件的getter方法。当类中定义的属性和方法满足下列要求时,FastJson会自动调用getter方法。
只存在getter方法,无setter方法;
方法名称长度大于等于4;
非静态方法;
方法名以get开头,且第四个字符为大写字母,例如getAge;
方法无须人参;
方法返回值继承自Collection、Map、AtomicBoolean、AtomicInteger和
AtomicLong的其中一个;
FastJson 1.2.24 下的PoC 如下:
import com.alibaba.fastjson.JSON;
import java.util.Properties;
public class User {
public String name;
private int age;
private Boolean sex;
private Properties properties;
public User() {
System.out.println("无参构造函数调用");
}
public int getAge() {
System.out.println("age的getter方法调用");
return age;
}
public void setAge(int age) {
System.out.println("age的setter方法调用");
this.age = age;
}
public Properties getProperties() {
System.out.println("properties的getter方法调用");
return properties;
}
public void setName(String name) {
System.out.println("name的setter方法调用");
this.name = name;
}
public String getName() {
System.out.println("name的getter方法调用");
return name;
}
public void setSex(Boolean sex) {
System.out.println("sex的setter方法调用");
this.sex = sex;
}
public Boolean getSex() {
System.out.println("sex的getter方法调用");
return sex;
}
public static void main(String[] args) {
String jsonstr = "{\"@type\":\"User\",\"sex\":true,\"name\":\"Yu\",\"age\":18,\"properties\":{}}";
Object obj = JSON.parse(jsonstr);
}
}
PoC执行结果:
parseObject(String text)方法将SON申还原成对象后,后会调用一次getter方法,类中所有的getter方法都会被执行一次,如下图所示:
3. checkAutoType 安全机制
FastJson1.2.25版本中引人了checkAutotype,其中增加了黑白名单的校,验,缓解反序列化需洞的产生,后续版本将内置的黑白名单进行加密,增加了绕过黑白名的研究成本。
com.alibaba.fastjson.parser.ParserConfig 加入了CheckAutoType方法,在其中有个 autotypeSupport 属性,如果为 false,那么就会检测json中@type的值 开头是否与黑名单中的值一样,若一样就直接返回一个异常,然后加载白名单中的类。
黑名单长这样:
CheckAutoType() 部分代码
若autotypesupport开启,则会先白名单加载,后黑名单检测
后面的许多更新都是对 checkAutotype 以及本身某些逻辑缺陷导致的漏洞进行修复,以及黑名单的不断增加。
4. RASP 防御
1.2.47 版本的漏洞利用与RASP 防御
复现参考:https://mp.weixin.qq.com/s/A0X3nCq9w4BAlGPCN-jH5Q
受到漏洞影响的服务注册到管理端:
发起攻击后查看日志:
攻击详情:
调用栈:
业务层面影响:请求被阻断
说明:1.2.80版本的绕过问题,rasp 理论上都可以检测到,由于绕过poc构造难度大,并且没有公开的资料,这里没有复现。
github:https://github.com/jvm-rasp/jrasp-agent
加入技术交流群请添加微信:sear2022