fastjson-流程分析

news2024/9/17 9:17:54

参考视频:fasfjson反序列化漏洞1-流程分析

分析版本

fastjson1.2.24

JDK 8u65

分析过程

新建Person类

public class Person {

    private String name;
    private int age;

    public Person() {
        System.out.println("constructor_0");
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("constructor_2");
    }

    public String getName() {
        System.out.println("getName");
        return name;
    }

    public void setName(String name) {
        this.name = name;
        System.out.println("setName");
    }

    public int getAge() {
        System.out.println("getAge");
        return age;
    }

    public void setAge(int age) {
        this.age = age;
        System.out.println("setAge");
    }
}

新建JSONTest

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

public class JSONTest {
    public static void main(String[] args) throws Exception {
        String s = "{\"@type\":\"Person\",\"age\":18,\"name\":\"tttt\"}";

        JSONObject jsonObject = JSON.parseObject(s);
        System.out.println(jsonObject);
    }
}

image-20240715102848791

发现parseObject(s)过程还调用了get方法。详细的过程可以跟一下上面视频。

分析下fastjson的JSON.parseObject(s);逻辑

主要逻辑在DefaultJSONParser的parse方法

public static Object parse(String text, int features) {
    if (text == null) {
        return null;
    }

    DefaultJSONParser parser = new DefaultJSONParser(text, ParserConfig.getGlobalInstance(), features);
    Object value = parser.parse();    //主要的逻辑在这儿

    parser.handleResovleTask(value);

    parser.close();

    return value;
}

parse()先进行字符串的匹配

case LBRACE: //匹配到左大括号
    JSONObject object = new JSONObject(lexer.isEnabled(Feature.OrderedField));
    return parseObject(object, fieldName);

之后进入parseObject

key是@type,进入此循环,fastjson会尝试将字符串反序列化为输入的@type类。可以看到进入循环之后会调用loadCLass方法,加载类

image-20240715142244242

TypeUtils.loadClass对输入进行了预处理,不处理的话loadClass默认是不能加载数组类的

image-20240715143333345

加载完类之后,继续往下跟。到下面的位置会进行反序列化,跟进去

image-20240715143853109

public ObjectDeserializer getDeserializer(Type type) {
    ObjectDeserializer derializer = this.derializers.get(type);  //首先查看有没有符合条件的默认的反序列化器,我们自己写的类,肯定是返回null
    if (derializer != null) {
        return derializer;
    }

    if (type instanceof Class<?>) {
        return getDeserializer((Class<?>) type, type);   //之后进入这个方法
    }

    if (type instanceof ParameterizedType) {
        Type rawType = ((ParameterizedType) type).getRawType();
        if (rawType instanceof Class<?>) {
            return getDeserializer((Class<?>) rawType, type);
        } else {
            return getDeserializer(rawType);
        }
    }

    return JavaObjectDeserializer.instance;
}

getDeserializer((Class<?>) type, type);方法中,找不到符合条件的反序列化器,则把传入的默认当作JavaBean。

image-20240715145213169

在createJavaBeanDeserializer中又调用到了JavaBeanInfo beanInfo = JavaBeanInfo.build(clazz, type, propertyNamingStrategy);

通过这个build方法去获取Person的信息,从而创建Person的反序列化器。

这里不详细写了

下面三个循环,第一个寻找public的set方法,第二个寻找public的属性,第三个寻找public的get方法(如果有了对应的set方法,那么这里不在创建get方法)

image-20240715151747655

fastjson还有一个设定是,如果找到了某个属性的set方法,那么get方法就不再add。这个操作是在最后一个循环的下面这里实现的。

image-20240715164947894

这里要说一下根据上面分析,如果针对某个属性只有getter方法,则会创建getter方法,但是fastjson对getter方法的返回值做了判断,需要满足下面条件

image-20240731102641050

之后我们就拿到了需要的反序列化器(这有个关于debug的问题,大家看视频吧,这儿就不写了,更新了Person类)

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

import java.util.Map;

public class Person {
    private String name;
    private int age;
    private Map map;

    public Person() {
        System.out.println("constructor_0");
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("constructor_2");
    }

    public String getName() {
        System.out.println("getName");
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
        System.out.println("setName");
    }

    public int getAge() {
        System.out.println("getAge");
        return this.age;
    }

    public void setAge(int age) {
        this.age = age;
        System.out.println("setAge");
    }

    public Map getMap() {
        System.out.println("getMap");
        return this.map;
    }
}

下面可以跟一下反序列化器JavaBeanDeserializer中,是如何调用构造函数,set和get方法的。

在反序列化器JavaBeanDeserializer中,只会调用setAge和setName。不会调用getAge和getName方法(上面讲了原因)和getMap(这是因为在JavaBeanDeserializer中做了判断)

} else if (fieldClass == float[][].class) {   //上面还有很多类型的判断,但是没有Map类,所以这里为假
    fieldValue = lexer.scanFieldFloatArray2(name_chars);

    if (lexer.matchStat > 0) {
        matchField = true;
        valueParsed = true;
    } else if (lexer.matchStat == JSONLexer.NOT_MATCH_NAME) {
        continue;
    }
} else if (lexer.matchField(name_chars)) {  //检查map是否在JSON中
    matchField = true;
} else {
    continue;
}

我们想要输出getMap改一下JSON就行了。String s = "{\"@type\":\"Person\",\"age\":18,\"name\":\"tttt\",\"map\":{}}";这样就能输出getMap了。

剩下的getAge和getName是在JSON.toJSON(obj);中完成输出的。

///JSON
public static JSONObject parseObject(String text) {
    Object obj = parse(text);
    if (obj instanceof JSONObject) {
        return (JSONObject) obj;
    }

    return (JSONObject) JSON.toJSON(obj);
}
///JSON
if (serializer instanceof JavaBeanSerializer) {
    JavaBeanSerializer javaBeanSerializer = (JavaBeanSerializer) serializer;
    
    JSONObject json = new JSONObject();
    try {
        Map<String, Object> values = javaBeanSerializer.getFieldValuesMap(javaObject);
        for (Map.Entry<String, Object> entry : values.entrySet()) {
            json.put(entry.getKey(), toJSON(entry.getValue()));
        }
    } catch (Exception e) {
        throw new JSONException("toJSON error", e);
    }
    return json;
}

利用

下面弹个计算器试试

一、注意类里面都没有定义map这个属性,但是因为fastjson是按set和get等方法寻找属性的,所以并不影响。

要注意setMap中参数必须为1,否则fastjson会报错

public class Test {
    public void setMap(String map) throws IOException {
        Runtime.getRuntime().exec("calc");
    }
}
public class JSONTest {
    public static void main(String[] args) throws Exception {
        String s = "{\"@type\":\"Test\",\"map\":\"aaaa\"}";
        JSONObject jsonObject = JSON.parseObject(s);
        System.out.println(jsonObject);
    }
}

二、get方法注意不能有参数

public class Test {
        public Map getMap() throws IOException { //如果返回类型改为int的话,需要在JSON语句中加入map的赋值,否则不会执行get方法。这样做程序可以在toJSON中执行get方法
            Runtime.getRuntime().exec("calc");
            return new HashMap();
        }
}
public class JSONTest {
    public static void main(String[] args) throws Exception {
        String s = "{\"@type\":\"Test\"}";
        JSONObject jsonObject = JSON.parseObject(s);
        System.out.println(jsonObject);
    }
}

如果getMap返回类型是Map,而且JSON中还给map赋值了。那么会运行两次getMap(我的Test类里面没有setMap方法)

第一次是在形成反序列化器时

第二次是在toJSON中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1963685.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

API调度

API调度 什么是API什么是HTTP请求如何使用影刀API流程创建密钥获取token启动应用 如何通过代码调用影刀API下载requests库准备工作搭建框架获取token&#xff08;鉴权&#xff09;转换请求为json调用函数按照键名进行提取 获取应用查询状态结束流程 什么是API 什么是HTTP请求 如…

[极客大挑战 2019]Http1

打开题目 鼠标右键查看源码看看有外部链接 点击氛围&#xff0c;弹出新页面 修改请求头 得到flag 说只读&#xff0c;然后改

Java 反射(reflex)

反射理解 反射解析 Java 的反射机制是指在运行状态中。对于任意一个类&#xff0c;都能知道这个类的属性和方法&#xff1b; 对于任意一个对象&#xff0c;都能够调用它的任意一个方法&#xff1b; 这种动态获取信息以及动态调用对象方法的功能称为 java 的反射机制。 正射…

Python .whl 独立安装和全部依赖安装命令

以安装 Flask 为例&#xff1a; 1. 独立安装 pip install whl_files/Flask-1.1.2-py2.py3-none-any.whl 2. 安装 Flask 全部依赖包和自己 cd /path/to/flask/1.0 pip install --no-index --find-links/path/to/downloaded/files Flask1.1.2 cd /path/to/flask/2.0 pip install …

55533

作者主页&#xff1a; 作者主页 本篇博客专栏&#xff1a;C 创作时间 &#xff1a;2024年6月20日 最后&#xff1a; 十分感谢你可以耐着性子把它读完和我可以坚持写到这里&#xff0c;送几句话&#xff0c;对你&#xff0c;也对我&#xff1a; 1.一个冷知识&#xff1a; …

mysql数据和备份

mysql备份和恢复和日志管理&#xff08;配置文件当中的设置&#xff09; 备份的目的是什么 备灾 在生产环境中&#xff0c;数据的安全性非常重要 造成数据丢失的原因 1、程序出错 2、人为问题 3、磁盘故障。 备份的分类 物理备份&#xff1a;对磁盘或者文件直接进行备…

敢不敢跟我一起搭建一个Agent!不写一行代码,10分钟搞出你的智能体!纯配置也能真正掌握AI最有潜力的技术?AI圈内人必备技能

说一千道一万&#xff0c;不如实地转一转。学了那么久的AI Agent的概念了&#xff0c;是时候该落地一个Agent看看自己的掌握程度了对不对&#xff0c;我们都理解大脑是自动节能的&#xff0c;但是知识的确需要倒逼自己一把才能真的掌握&#xff0c;不瞒大家说&#xff0c;笔者对…

植物精灵大战僵尸(合体版),一款塔防+合体玩法的游戏

一款塔防合体玩法的游戏&#xff0c;本作在原先经典植物战僵尸玩法的基础上&#xff0c; 完美加入合体进化玩法。完美破解&#xff0c;支持飞行模式&#xff0c; 理论上支持所有运营商&#xff0c;进入付费页面直接点确定或者返回就能完成破解&#xff0c; 移动卡真机测试&a…

Vue3+TypeScript+printjs 实现标签批量打印功能

前言&#xff1a;临时性需求没怎么接触过前端&#xff0c;代码实现有问题及优化点希望大佬可以留言告知一下 开发工具&#xff1a;VS CODE 界面开发&#xff1a;Vue3TypeScriptElementPlus 打印组件&#xff1a;Print-JS 前端打印入口图&#xff1a; 标签页面&#xff1a; …

电气数字化能为企业带来哪些助力?

本文主要从“电气行业概况” 和 “电气数字化核心价值”2个方面&#xff0c;为大家全方位解答“电气数字化能为企业带来哪些助力&#xff1f;” 一、电气行业概况 总体而言&#xff0c;我国电气行业是规模体量巨大的基础产业&#xff0c;目前存在平均效益不高、生产及交易效率…

linux-centos配置jdk环境变量

1、在官网下载适配的jdk到本地后&#xff0c;通过ssh工具将文件上传到 /etc目录下 2、使用命令 vim /etc/profile 在文件末尾加上 #set java environment JAVA_HOME/etc/jdk1.8 JRE_HOME/etc/jdk1.8/jre CLASS_PATH.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOM…

Codeforces Round 946 (Div. 3) C. Beautiful Triple Pairs (容斥原理)

注意这里的三元组是按顺序找出来的&#xff0c;不能够随便组合。 由于数组长度不算很大&#xff0c;我们可以实现一层循环。 根据题目&#xff0c;我们分别调取对于当前遍历到的三元组&#xff0c;第一个数不同其余数相同&#xff0c;第二个数不同其余数相同&#xff0c;第三个…

运维-6-采用LPG搭建轻量级日志收集系统

参考Grafana 安装配置教程 1 Grafana Grafana是一个通用的可视化工具。对于Grafana而言&#xff0c;Prometheus这类为其提供数据的对象均称为数据源&#xff08;Data Source&#xff09;。目前&#xff0c;Grafana官方提供了对&#xff1a;Graphite, InfluxDB, OpenTSDB, tde…

v-for遍历数据类型方式

第一种&#xff1a;数组 v-for"(item, index) in list" 属性作用item取数组的每一项的对象&#xff1b;index取数组的每一项的下标&#xff1b; html&#xff1a; <div v-for"(item, index) in list" :key"index"><span>名称&…

探索设计模式:组合模式

探索设计模式&#xff1a;组合模式 &#x1f9d0;1. 概念&#x1f3af;2. 作用&#x1f4e6;3. 用法&#x1f4e6;3.1 绘图示例&#x1f4e6;3.2 文件示例 &#x1f4bb;4. 使用场景 在软件设计中&#xff0c;组合模式&#xff08;Composite Pattern&#xff09;是一种结构型设…

WebLogic:弱口令,木马反弹连接

weblogic WebLogic 是 Oracle 公司开发的应用服务器&#xff0c;主要用作开发、集成、部署和管理大型分布式 Web 应用、网络应用和数据库应用的 Java 应用服务器。它在历史上曾出现过多个安全漏洞&#xff0c;其中包括弱口令、任意文件上传、SSRF、反序列化漏洞等 常见版本&a…

YOLOv8入门 | yaml文件解读,YOLOv8网络结构打印以及网络结构图绘制【小白必看】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录 &#xff1a;《YOLOv8改进有效…

软考高级-系统架构设计师

2024广东深圳考试时间 报考人员可登录中国计算机技术职业资格网&#xff08;http://www.ruankao.org.cn&#xff09;进行网上报名&#xff0c;报名前须扫码绑定个人微信&#xff0c;不允许代报名。 上半年考试报名信息填报时间&#xff1a;2024年3月25日9:00&#xff0d;4月2日…

【ASR系列】【论文阅读】CIF

1. 概念学习 WER(word error rate): 单词错误率,是评价asr系统的一种重要指标,越低越好 是Continuous integrate-and-fire的简称,集成和发射,翻译成积分不太合理,可理解为求和 2. 思想 一个人说了几句话,在说第一句话的时候会不断地对输入的信号集成,说完这句话(达…

计算机毕业设计PySpark+Django高考志愿填报推荐系统 高考预测 高考大数据分析 Hadoop Spark 机器学习 深度学习 Python

在撰写关于《PySpark高考推荐系统》的论文时&#xff0c;推荐算法的实现通常会利用PySpark&#xff0c;这是Apache Spark的Python API。以下是一个使用PySpark中MLlib库的ALS&#xff08;交替最小二乘法&#xff09;算法来构建高考推荐系统的示例代码。在这个示例中&#xff0c…