首页 > 其他分享 >fastjson反序列化 TODO

fastjson反序列化 TODO

时间:2023-08-15 15:22:15浏览次数:45  
标签:fastjson name value atomic hobby 序列化 TODO

参考链接

fastjson反序列化入门文章
https://tttang.com/archive/1579/
https://xz.aliyun.com/t/12096
ASM动态加载相关,如何查看内存生成的类的源码
https://juejin.cn/post/6974566732224528392#heading-6
https://blog.csdn.net/wjy160925/article/details/85288569
关闭ASM去调试
https://blog.csdn.net/qq_45854465/article/details/120960671
toJSONString()方法的源码分析(较浅)
https://blog.csdn.net/qq_31615049/article/details/85013129

Fastjson流程分析

先写个例子

package fastjson.pojo;


public class User{
    private String name;
    private int age;
    private String hobby;

    public User() {
    }

    public User(String name, int age, String hobby) {
        this.name = name;
        this.age = age;
        this.hobby = hobby;
    }

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

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

    public int getAge() {
//        System.out.println("调用了getAge");
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }
    @Override
    public String toString() {
        return "user{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", hobby='" + hobby + '\'' +
                '}';
    }
}
package fastjson;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import fastjson.pojo.User;


public class EasyStart extends User {
    public static void main(String[] args) {

        //序列化对象,会调用getter方法
        SerializeConfig.getGlobalInstance().setAsmEnable(false);
        User user = new User("Jasper",22,"fuck_some_people");
//        String s1 = JSON.toJSONString(user);
        String s2 = JSON.toJSONString(user, SerializerFeature.WriteClassName);
        System.out.println(s2);
        System.out.println("---------------------------------------");
//        String s2 = "{\"@type\":\"fastjson.pojo.User\",\"age\":22,\"hobby\":\"fuck_some_people\",\"name\":\"Jasper\"}";
        ParserConfig.getGlobalInstance().setAsmEnable(false);
        //情况1,parse里面调setter
        Object o1 = JSON.parse(s2);
        System.out.println(o1);
        System.out.println(o1.getClass().getName());
        System.out.println("---------------------------------------");
        //情况2,parseObject是parse的封装,所以会调setter,另外JSON.toJSON会调getter
        Object o2 = JSON.parseObject(s2);
        System.out.println(o2);
        System.out.println(o2.getClass().getName());
        System.out.println("---------------------------------------");
        //情况3,parseObject在里边调了setter
        Object o3 = JSON.parseObject(s2,Object.class);
        System.out.println(o3);
        System.out.println(o3.getClass().getName());
        System.out.println("---------------------------------------");
    }
}

输出结果:

调用了getName
{"@type":"fastjson.pojo.User","age":22,"hobby":"fuck_some_people","name":"Jasper"}
---------------------------------------
调用了setName
user{name='Jasper', age=22, hobby='fuck_some_people'}
fastjson.pojo.User
---------------------------------------
调用了setName
调用了getName
{"name":"Jasper","age":22,"hobby":"fuck_some_people"}
com.alibaba.fastjson.JSONObject
---------------------------------------
调用了setName
user{name='Jasper', age=22, hobby='fuck_some_people'}
fastjson.pojo.User
---------------------------------------

目前来看,序列化会调getter;反序列化会调setter,有的还会调getter。
这里我看大部分文章都没分析为什么会调用,这里我跟了一下源码,下面是分析结果。

序列化分析

get:450, FieldInfo
getPropertyValueDirect:110, FieldSerializer
write:196, JavaBeanSerializer
write:275, JSONSerializer
toJSONString:559, JSON
toJSONString:548, JSON
main:16, EasyStart

get里反射调用了getter

public Object get(Object javaObject) throws IllegalAccessException, InvocationTargetException {
    if (method != null) {
        Object value = method.
            invoke(javaObject, new Object[0]);
        return value;
    }
    return field.get(javaObject);
}

注意:需要用下面的语句把ASM关掉,会进到动态生成的类里,调试不了。
:::info
SerializeConfig.getGlobalInstance().setAsmEnable(false);
:::

反序列化分析

反序列化函数底层大差不差,最多是多了一些判断,这里只以parse()为例:

setValue:96, FieldDeserializer
deserialze:593, JavaBeanDeserializer
deserialze:188, JavaBeanDeserializer
deserialze:184, JavaBeanDeserializer
parseObject:368, DefaultJSONParser
parse:1327, DefaultJSONParser
parse:1293, DefaultJSONParser
parse:137, JSON
parse:128, JSON
main:22, EasyStart

setValue()里有反射调用setter方法:

public void setValue(Object object, Object value) {
    if (value == null //
        && fieldInfo.fieldClass.isPrimitive()) {
        return;
    }

    try {
        Method method = fieldInfo.method;
        if (method != null) {
            if (fieldInfo.getOnly) {
                if (fieldInfo.fieldClass == AtomicInteger.class) {
                    AtomicInteger atomic = (AtomicInteger) method.invoke(object);
                    if (atomic != null) {
                        atomic.set(((AtomicInteger) value).get());
                    }
                } else if (fieldInfo.fieldClass == AtomicLong.class) {
                    AtomicLong atomic = (AtomicLong) method.invoke(object);
                    if (atomic != null) {
                        atomic.set(((AtomicLong) value).get());
                    }
                } else if (fieldInfo.fieldClass == AtomicBoolean.class) {
                    AtomicBoolean atomic = (AtomicBoolean) method.invoke(object);
                    if (atomic != null) {
                        atomic.set(((AtomicBoolean) value).get());
                    }
                } else if (Map.class.isAssignableFrom(method.getReturnType())) {
                    Map map = (Map) method.invoke(object);
                    if (map != null) {
                        map.putAll((Map) value);
                    }
                } else {
                    Collection collection = (Collection) method.invoke(object);
                    if (collection != null) {
                        collection.addAll((Collection) value);
                    }
                }
            } else {
                method.invoke(object, value);
            }
            return;
        } else {
            final Field field = fieldInfo.field;
            
            if (fieldInfo.getOnly) {
                if (fieldInfo.fieldClass == AtomicInteger.class) {
                    AtomicInteger atomic = (AtomicInteger) field.get(object);
                    if (atomic != null) {
                        atomic.set(((AtomicInteger) value).get());
                    }
                } else if (fieldInfo.fieldClass == AtomicLong.class) {
                    AtomicLong atomic = (AtomicLong) field.get(object);
                    if (atomic != null) {
                        atomic.set(((AtomicLong) value).get());
                    }
                } else if (fieldInfo.fieldClass == AtomicBoolean.class) {
                    AtomicBoolean atomic = (AtomicBoolean) field.get(object);
                    if (atomic != null) {
                        atomic.set(((AtomicBoolean) value).get());
                    }
                } else if (Map.class.isAssignableFrom(fieldInfo.fieldClass)) {
                    Map map = (Map) field.get(object);
                    if (map != null) {
                        map.putAll((Map) value);
                    }
                } else {
                    Collection collection = (Collection) field.get(object);
                    if (collection != null) {
                        collection.addAll((Collection) value);
                    }
                }
            } else {
                if (field != null) {
                    field.set(object, value);
                }
            }
        }
    } catch (Exception e) {
        throw new JSONException("set property error, " + fieldInfo.name, e);
    }
}

注意:需要用下面的语句把ASM关掉,会进到动态生成的类里,调试不了。
:::info
ParserConfig.getGlobalInstance().setAsmEnable(false);
:::

利用点分析

从输出结果还可以看到,如果序列化的字符串里用@type指定了类名User,那么即使parseObject(s2, Object.class)指定序列化成Object.class,还是会反序列化成User
image.png
这意味着,反序列化成什么样的对象,是受传入的序列化字符串控制的,而前面说了Fastjson在反序列化和序列化的时候,都会自动调用getter和setter方法,那么如果我们传入有危险getter/setter方法的类的序列化字符串就能利用了。

1.2.24漏洞调试

还有很多东西没学,暂时卡住了。
image.png

标签:fastjson,name,value,atomic,hobby,序列化,TODO
From: https://www.cnblogs.com/sketchpl4ne/p/17631389.html

相关文章

  • delphi 自带 的JOSN 序列化 三
    TConverterEx<T:class>=class(TJsonConverter)publicfunctionCanConvert(ATypeInf:PTypeInfo):Boolean;override;functionReadJson(constAReader:TJsonReader;ATypeInf:PTypeInfo;constAExistingValue:TValue;constASerializer:......
  • 漏洞复现报告:CVE-2020-2551 IIOP反序列化漏洞
    1.漏洞描述: 2020年1月15日,Oracle发布了一系列的安全补丁,其中OracleWebLogicServer产品有高危漏洞,漏洞编号CVE-2020-2551,CVSS评分9.8分,漏洞利用难度低,可基于IIOP协议执行远程代码。Weblogic是一个服务器,可以做web服务器也可以做应用服务器WebLogic是美国Oracle公司出品的......
  • 序列化 - Kryo序列化详解
    什么是序列化序列化是指将数据结构或对象转换为可存储或传输的格式,以便在稍后的时间点重新构建或恢复原始数据结构或对象的过程。在计算机科学和编程中,序列化通常用于将内存中的数据转换为可以在磁盘上保存或通过网络传输的形式,以便在需要时进行持久化存储或在不同系统之间进行数......
  • 序列化 - jdk序列化详解
    当谈到在Java中将对象转换为字节流以便于存储、传输或持久化时,不可避免地会涉及到JDK序列化。JDK序列化是Java编程语言提供的一种机制,允许开发者将对象转换为字节序列,以便在稍后的时间点能够重新构建或恢复对象的状态。本文将深入介绍JDK序列化的概念、用法以及一些相关的......
  • fastjson配置统一的日期格式转换
    importcom.alibaba.fastjson.serializer.SerializeConfig;importcom.alibaba.fastjson.serializer.SerializerFeature;importcom.alibaba.fastjson.serializer.ToStringSerializer;importcom.alibaba.fastjson.support.config.FastJsonConfig;importcom.alibaba.fast......
  • 数据序列化工具Protobuf编码&避坑指南
    我们现在所有的协议、配置、数据库的表达都是以protobuf来进行承载的,所以我想深入总结一下protobuf这个协议,以免踩坑。先简单介绍一下ProtocolBuffers(protobuf),它是Google开发的一种数据序列化协议(与XML、JSON类似)。它具有很多优点,但也有一些需要注意的缺点:优点:效......
  • URLDNS的反序列化调试分析
    Java反序列化(0):URLDNS的反序列化调试分析URLDNS链子是Java反序列化分析的第0课,网上也有很多优质的分析文章。笔者作为Java安全初学者,也从0到1调试了一遍,现在给出调试笔记。一.Java反序列化前置知识Java原生链序列化:利用Java.io.ObjectInputStream对象输出流的writerObject......
  • springboot~alibaba.fastjson2序列化时过滤字段
    当我们使用阿里的alibaba.fastjson2进行json序列化时,你可以通过方法参数PropertyFilter来实现对字段的获取,将需要序列化的字段写到PropertyFilter对象里,当然也可以将不进行序列化的写到这里,进行逻辑非操作即可实体classPerson{privateStringfirstName;privateStr......
  • 序列化
    什么是序列化我们把对象(变量)从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。为什么要序列化1.持久保存状态需知一个软件/程序的执行就在处理一系列状态的变化,在编程语言中,'状......
  • delphi 自带的JSON序列化类
    unitUnit1;interfaceusesWinapi.Windows,Winapi.Messages,System.SysUtils,System.Variants,System.Classes,Vcl.Graphics,Vcl.Controls,Vcl.Forms,Vcl.Dialogs,System.JSON.Serializers,Vcl.StdCtrls;typeTForm1=class(TForm)Memo1:TMemo......