众所周知,在 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)
下面这个例子
1 | package com.vuln; |
JSON.parse后的对象如下
$ref
的值是符合JSONPath语法的,详细可以参考:https://goessner.net/articles/JsonPath/
调用演示
Test.java
1 | package com.vuln; |
触发代码
1 | import com.alibaba.fastjson.JSON; |
可以看到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
1 | package com.vuln; |
触发代码
1 | import com.alibaba.fastjson.JSON; |
调用分析
巧妙利用了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](