FastJson是什么

Fastjson是一个Java语言编写的高性能功能完善的JSON库。

FastJson高性能的原理是自己写了一套ASM框架,而不是用反射来进行操作,所以FastJson的处理速度,比市面上常见的json处理组件要快

FastJson的漏洞,主要是围绕settergetter方法

fastjson各版本漏洞

fastjson中产生漏洞的根本原因在于其 autoType 机制,以及针对于 autoType 机制做的checkAutoType检测防御机制。

1.2.24及以下 主要是因为,没有对序列化的类做校验,导致漏洞产生

1.2.25-1.2.41增加了黑名单限制,更改autoType默认为关闭选项。

1.2.42版本是对1.2.41及以下版本的黑名单绕过,代码内更新字符串黑名单为hash方式

1.2.43版本是对1.2.42及以下版本的黑名单绕过

1.2.44-1.2.45版本1.2.43版本黑名单无法绕过,寻找新的利用链进行利用

1.2.47版本 利用fastjson处理Class类时的操作,将恶意类加载到缓存中,实现攻击

1.2.62-1.2.67版本 Class不会再往缓存中加载恶意类,寻找新的利用链进行突破

1.2.68版本,使用期望类AutoCloseable来绕过fastjson校验

1.2.72-1.2.80使用期望类Throwable的子类,进行饶过

FastJson执行流程分析

demo

@RequestMapping("/fastjson")
public String fastjson(@RequestBody String ObjName) {
    try {
        JSONObject jsonObject = JSONObject.parseObject(ObjName);
        String type = jsonObject.toJSONString();
        return type;
    } catch (Exception e) {
        return e.toString();
    }
}

exec类

package com.example.fastjson_demo.Example;

import java.io.Closeable;
import java.io.IOException;

public class exec implements Closeable {
    public String exec;

    public String getExec1() {
        return exec1;
    }

    public void setExec1(String exec1) {
        this.exec1 = exec1;
    }

    public String exec1;

    public String getExec() {
        return exec;
    }

    public void setExec(String exec) throws IOException {

        this.exec = exec;
        Runtime.getRuntime().exec(this.exec);
    }

    @Override
    public void close() {

    }
}

POC

{
	"@type":"com.example.fastjson_demo.Example.exec",
	"exec":"calc",
    "exec1":"calc1"
}

调用流程分析

com.alibaba.fastjson.JSON#parseObject(java.lang.String)

在这里插入图片描述

com.alibaba.fastjson.JSON#parse(java.lang.String)

image-20230603113830616

com.alibaba.fastjson.JSON#parse(java.lang.String, int)

传入了一个fastjson分析器实例,用来检查或分析后续操作。

image-20230603114019344

com.alibaba.fastjson.JSON#parse(java.lang.String, com.alibaba.fastjson.parser.ParserConfig, int)

在这里,开始进行Json字符串解析,跟进DefaultJSONParser类看一下。

在这里插入图片描述

com.alibaba.fastjson.parser.DefaultJSONParser#DefaultJSONParser()

image-20230603114407902

JSONScanner是对JSON字符串进行处理并分析,JSONScanner extends JSONLexerBase JSONLexerBase implements JSONLexer所以在DefaultJSONParser的构造方法中,获取的为JSONLexer对象

com.alibaba.fastjson.parser.DefaultJSONParser#DefaultJSONParser()

image-20230603115604610

在这里开始对JSON字符串进行初始化操作。

执行next()方法将递增字符串下标,更新this.ch参数,执行一次next()更新一次下标,同时也更新this.ch

在之前JSONScanner初始化时,已经执行过next(),所以lexer.getCurrent()在此直接拿到的就是JSON字符串的第一个值。

如果json的字符串为{形式,token就为12,如果json的字符串为[形式,就标记token为14

至此 , 传入的JSON字符串已经初始化完成 。

com.alibaba.fastjson.parser.DefaultJSONParser#parse() 开始分析并获取Json中的内容

image-20230603120431455

com.alibaba.fastjson.parser.DefaultJSONParser#parse(java.lang.Object)

token,标记值为12,继续跟进

传入的JSONObject如果为true的话,会使用LinkedHashMap(有序),如果传入的false的话会使用HashMap(无序)

image-20230603120657702

com.alibaba.fastjson.parser.DefaultJSONParser#parseObject(java.util.Map, java.lang.Object)

因为LinkedHashMapHashMap都是为Map的实现类,所以在此转为Map仍可使用

token为12

在这里插入图片描述

image-20230603122129205

简单来说,这里的逻辑就是, 检查你的json字符串是否合规,合规的话,取出值, 检查key的名称是否为JSON.DEFAULT_TYPE_KEY 也就是 @type

image-20230603122536485

lexer.scanSymbol(this.symbolTable, '"');

这段代码的意思为从当前字符串开始,获取,到下一个"的中间的值,也就是指定闭合符,获取闭合符中的内容并返回。

image-20230603125153610

然后将@type的值给到autoType进行检查,检查通过,继续进行下一个检查

JSONScanner初始化的Mapnull时, 也就是还没有向map内进行添加操作时

简单说就是去系统内获取Deserializer, 获取不到系统内的Deserializer, 没有对应的, 就会去获取当前类的注解,如果注解依然不存在的话

… … … …

如果以上匹配都不通过的话, 则会匹配是否为Java的一些工具类或者是否为三方类

image-20230603131050032

此处略过一万字, 如果fastjson@type的值,不在以上这些限定的类或其他东西中,则create创建一个出来,然后加入到deserializer

com.alibaba.fastjson.parser.ParserConfig#createJavaBeanDeserializer

image-20230603131422037

看一下这边是怎么实现的,跟进createJavaBeanDeserializer方法

image-20230603201911575

大概解释一下 这里一些if的意思

首先对是否开启asm功能进行判断

如果开启了,那么这个要被序列化的类,是否有注解

然后获取类的信息,匹配父类是否有注解

然后判断里面的泛型变量, 如果存在的话 关闭asm功能

然后判断asm工厂类是否为null,并检查他们的上一级关系,是否与ASMClassLoader相同

然后经过上面的步骤后,判断asm是否还为开启状态

然后检查包和类地址的合法性

然后检查类地址是否为接口类型

然后根据clazzpropertyNamingStrategy生成beaninfo

又经过一堆判断之后,调用asm工厂类生成处理类

image-20230603204024751

com.alibaba.fastjson.parser.deserializer.ASMDeserializerFactory#createJavaBeanDeserializer

image-20230603204138259

其实看到这里已经比较吃力了,没有系统学习过ASM,建议大家去看Lucifaer师傅的文章https://paper.seebug.org/994/讲的很清晰

跟踪到

com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer#JavaBeanDeserializer()

image-20230603204630395

这个类,大概就是将clazz中的一些信息,转换为FieldDeserializer存储到sortedFieldDeserializers

image-20230603204804767

转换之后

image-20230603205813255

image-20230603205833192

然后执行到了JavaBeanDeserializer下的deserialze方法

com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer#deserialze()

image-20230603210547315

对@type的key进行处理

image-20230604102059306

然后用过DefaultFieldDeserializer的parseField方法进行操作,执行setValue进行赋值操作

image-20230604102245800

setValue(),然后通过反射,操作方法,然后执行,导致漏洞产生

image-20230604095855955

image-20230604095950671

这样就导致了Fastjson命令执行。

参考文章

百度ASM解释

初识Java ASM

Fastjson源码分析—ASM的作用和实现

fastjson 1.2.24-1.2.67 漏洞分析,附Poc分析

fastjson 反序列化漏洞笔记

1.2.68版本期望类绕过

https://github.com/Lonely-night/fastjsonVul

https://github.com/safe6Sec/Fastjson

https://www.freebuf.com/news/347174.html

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐