文章目录
- 写在前面
- JSONPath语法
- 利用演示
- $ref引用触发get方法分析
- 解释为什么1.2.36前的版本不行
写在前面
平时我们在处理fastjson反序列化的时候,如果我们想要执行属性的get方法,而如果只有JSON.parse怎么办
我们知道JSON.parse可以套一层parseObject实现对get方法的调用,但说这个也没有必要继续本篇的介绍了,这里介绍另一种,废话不多说开始分析
JSONPath语法
看文档https://goessner.net/articles/JsonPath/,重点关注下这个
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_json](https://file.cfanz.cn/uploads/png/2022/10/26/18/f100F522U3.png)
利用演示
人比较不老实,喜欢骚东西,这里执行下命令
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;
}
}
触发
public static void main(String[] args) {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload = "[{\"@type\":\"com.yyds.Test\",\"cmd\":\"calc\"},{\"$ref\":\"$[0].cmd\"}]";
Object o = JSON.parse(payload);
}
最爱的计算器
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_java_02](https://file.cfanz.cn/uploads/png/2022/10/26/18/92680N89b0.png)
$ref引用触发get方法分析
简简单单引入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.36</version>
</dependency>
老规矩拉到底,看看调用栈再分析
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_get方法_03](https://file.cfanz.cn/uploads/png/2022/10/26/18/9647T8W4S4.png)
跟进handleResovleTask函数
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_get方法_04](https://file.cfanz.cn/uploads/png/2022/10/26/18/DaZ4K534I2.png)
获取$ref
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_get方法_05](https://file.cfanz.cn/uploads/png/2022/10/26/18/6861L7eVMV.png)
至于如果你问在哪里设置的在DefaultJSONParser#parse()
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_json_06](https://file.cfanz.cn/uploads/png/2022/10/26/18/Ua4ITee20f.png)
ok,不说废话,继续看下去,满足条件跟进
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_get方法_07](https://file.cfanz.cn/uploads/png/2022/10/26/18/O15JUX11cK.png)
这里面没有返回null
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_java_08](https://file.cfanz.cn/uploads/png/2022/10/26/18/bQWXC537K4.png)
接下来重点来了,我们看看JSONPath.eval函数干了什么
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_java_09](https://file.cfanz.cn/uploads/png/2022/10/26/18/0Q489V6399.png)
跟进compile
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_get方法_10](https://file.cfanz.cn/uploads/png/2022/10/26/18/G4b29XZa8M.png)
根据path生成并返回一个JavaPath对象
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_get方法_11](https://file.cfanz.cn/uploads/png/2022/10/26/18/64Q8Xa15XC.png)
继续看看eval
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_get方法_12](https://file.cfanz.cn/uploads/png/2022/10/26/18/Q8e7U3WI1a.png)
这里有一个init函数执行
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_java_13](https://file.cfanz.cn/uploads/png/2022/10/26/18/6Jf0fd6166.png)
我们重点关注这个explain函数,把$ref的value解析成Segment,这个Segment是定义在JSONPath类的一个接口,具体看他的过程
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_json_14](https://file.cfanz.cn/uploads/png/2022/10/26/18/N7AFc6516d.png)
这里初始化长度是8很好奇吗
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_json_15](https://file.cfanz.cn/uploads/png/2022/10/26/18/ReO1A7d8ab.png)
因为实现segment接口的类只有八个
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_调用栈_16](https://file.cfanz.cn/uploads/png/2022/10/26/18/7X4c0492W0.png)
ok,继续看看这个readSegement,获取.后面的值
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_get方法_17](https://file.cfanz.cn/uploads/png/2022/10/26/18/72JHcPfbJA.png)
这里通过readName获取到cmd
![这里 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_调用栈_18](https://file.cfanz.cn/uploads/png/2022/10/26/18/77712N67Oc.png)
内部实现靠循环追加到StringBuilder后面
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_get方法_19](https://file.cfanz.cn/uploads/png/2022/10/26/18/610e8KC0b5.png)
后面通过浅拷贝赋值返回
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_get方法_20](https://file.cfanz.cn/uploads/png/2022/10/26/18/124Cc0W1b8.png)
接下来按顺序执行前面explain生成的Segment array
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_调用栈_21](https://file.cfanz.cn/uploads/png/2022/10/26/18/Y2aa368180.png)
跟进JSONPath.getPropertyValue
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_调用栈_22](https://file.cfanz.cn/uploads/png/2022/10/26/18/b64cd07b3V.png)
继续跟进
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_json_23](https://file.cfanz.cn/uploads/png/2022/10/26/18/L7R72Efa61.png)
跟进
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_调用栈_24](https://file.cfanz.cn/uploads/png/2022/10/26/18/3bDU3BPc36.png)
后面就是用反射调用get方法了
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_get方法_25](https://file.cfanz.cn/uploads/png/2022/10/26/18/5a0871066R.png)
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_调用栈_26](https://file.cfanz.cn/uploads/png/2022/10/26/18/122deZ4a2Y.png)
分析完毕
解释为什么1.2.36前的版本不行
我们知道关键在于JSONPath.eval方法的调用
我们来对比一下,前为1.2.36版本,后为1.2.35版本
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_get方法_27](https://file.cfanz.cn/uploads/png/2022/10/26/18/f218DXVFH3.png)
![在这里插入图片描述 [Java安全]Fastjson>=1.2.36$ref引用可触发get方法分析_json_28](https://file.cfanz.cn/uploads/png/2022/10/26/18/1041C294I0.png)
限制了refValue的值不能为null,并且必须是JSONObject对象,那就结束了









