Fastjson 反序列化-fastjson反序列化
2023-2-14
| 2023-4-12
0  |  0 分钟
type
status
date
slug
summary
tags
category
icon
password

FastJson简介

FastJson是阿里巴巴开源的Java对象和JSON格式字符串的快速转换的工具库,和google的Gson用法相似 1.将对象转换为Json字符串toJSONString() 2.将Json字符串转换为对象parseObject() FastJson反序列化漏洞(1.2.24-1.2.68)

原理

实例
把JSON反序列化的语句是 JSON.parseObject(json,User.class),在指定JSON时,还需要指定其所属的类,显得代码就很臃肿,所以在1.2.24版本中加入两个新特性,1.默认开启Auto Type选项.2.在处理@Type形式传入的类时,会默认调用该类的set\get\is函数 实例
所以在这个JSON反序列化接口处,我们传入恶意的JSON,就可以调用任意类的构造方法以及属性相关的get,set方法。 如果某类的相关方法里有危险的代码(如执行某个命令),我们就可以构造恶意JSON达到RCE的作用。
另外,JSON.parseObject(“{”@type“:”org.example.App$User“,”id“:”123“}”,Feature.SupportNonPublicField) ,可以直接为private成员赋值(不加Feature.SupportNonPublicField是无法对private成员赋值的) ## 版本1.2.24f astjson由于没有对@type进行安全性验证,使攻击者传入危险的类,通过rmi服务指定的攻击机上的恶意class文件,导致命令执行。 反序列化流程 1.进入调用parse方法,进入后,加载一些默认配置,然后判断解析的内容是否为null,如果为null,直接返回null;否则根据内容、默认配置等新建一个DefaultJSONParser实例(新建的时候会新建JSONScanner实例,调用父类JSONLexerBase进行实例化,实例化JSONScanner的时候,会初始化一个ch属性的值—-获取内容的第一个char,然后在调用DefaultJSONParser的另一个实例化方法,此处根据ch属性的值;判断给传入的JSONLexer实例中的token设值,如果是对象设值为12,如果是数组设置为14,然后将lexer扫描器向后移动扫描得到下一个位置的char;否则直接取下一个token值)。
2.实例化完成后调用DefaultJSONParse实例的parse方法,进入后首先判断token是否合法,不合法(1、5、10、11、13、15、16、17、19、24、25)直接报错,否则进行其他的对应的逻辑处理(如:jsonObject反序列化的话进入parseObject方法,再次判断lexer解析器token,合法再进行后续操作)
3.lexer.skipWhitespace()判断,白名单(此处白名单是指不需要进行处理的内容,不是autotype白名单)中的ch直接跳过,不进行处理;
4.然后经过一系列处理,获得key值,判断如果key是否为@type、autotype支持是否打开;如果key是@type,且autotype打开了则先获取typeName。
  1. 判断是否开启忽略autotype,如果开启了则不继续做处理,否则判断传入的object实例类型名称是否与typeName相同如果相同设置clazz为object的class,否则继续判断;typeName中如果全部是数字则不给clazz赋值,否则进入checkAutoType检测返回clazz。
6.对传入的typeName进行检测,如果为null,直接返回null;否则判断是否存在自定义autotype自定义扩展—-autotypehandler,如果存在则使用自定义扩展处理autotype并返回clazz;否则判断SafeMode是否开启,如果开启,直接报错不支持autotype;否则判断typeName的长度是否在3到192之间(不太清楚为什么要这么限制),如果不在直接返回错误autotype不支持。
7.如果第6点满足条件,则继续判断传入的expectClass是否为null、Object、Serializable、Closeable、Cloneable、EventListener、Iterable、Collection,如果都不满足,则执行反序列化流程,并将类加入到mappings列表
8.然后判断是否在白名单、是否在mappings列表中、是否有@type注解,如果都满足,就直接return执行反序列化流程,并将类加入到mappings列表,检测typeName是否在黑名单、是否继承自RowSet、DataSource、ClassLoader这些类,条件只要满足一个,则直接抛出错误
9.如果第8点有一个不满足,则会进入autoTypeSupport判断,它主要用来打开autotype功能,默认是false未打开,直接抛出错误。如果打开了,则执行反序列化流程,并将类加入到mappings列表

版本1.2.24-TemplatesImpl利用链

此版本漏洞基于JDK7u21反序列化漏洞的TemplatesImpl调用链, 主要的要点在满以下三个变量
_bytecodes _name _tfactory 还有就是调用newTransformer的方法

了解TemplatesImpl

XSL 指扩展样式表语言, 它是一个 XML 文档的样式表语言,类似CSS之于HTML;
XSLT是XSL转换语言,它是XSL的一部分,用于转换 XML 文档,可将一种 XML 文档转换为另外一种 XML 文档,如XHTML;

JDK7u21反序列化漏洞原理

TemplatesImpl实现了javax.xml.transform.Templates接口,javax.xml.transform属于JAXP(,是一个处理XSL转换XSLT的包,定义了用于处理转换指令以及执行从源到结果的转换的API。
javax.xml.transform.Templates是用来处理XSLT模板的,它只定义了两个方法:XSLTC和Translets
XSLTC指xslt compiler或xslt compiling,可以把XSLT文件编译成一个或者多个Java的class文件,通过这种方式可以加速xsl的转换速度。这些class或者class的集合被称为Translets,他们被转换时自动会继承AbstractTranslet。
TemplatesImpl主要是通过获取Translet的Class或字节码来创建 XSLTC 模板对象。XSLTC生成的Translets,需要转为模板对象,可以用TemplatesImpl定义和处理。
XML-XSLT-HTML的转换在Java中一般有以下4个步骤:
创建一个TransformFactory对象; 调用TransformFactory.newTemplates通过XSL样式表创建一个Templates对象; 调用Templates.newTransformer创建一个Transformer对象; 最后通过Transformer.transform将源-XML文档转换为目标-HTML文档。
执行恶意代码需要两个条件:一是调用defineTransletClasses获取Evil的Class对象,二是将Class对象实例化调用构造方法。_bytecodes被赋值为我们定义的恶意类的字节码,该类需要继承com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet _class必须为null _name必须不为null _tfactory必须是TransformerFactoryImpl实例
总结 com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl本身是用来进行xsl转换的,主要通过XSLTC接收xsl文档生成的Translets类的字节码来创建 XSLTC模板对象。那么由于需要处理字节码,其在内部定义了类加载器并重载了defineClass,defineClass能够返回字节码的Class对象方便后续的实例化,而这也是我们能够利用它执行恶意代码的关键。
通过构造恶意类的字节码并使用defineClass返回其Class对象,实例化后即可执行我们想要的结果。

FastJson的利用

TemplatesImpl类本身就存在反序列化漏洞,会将成员变量_bytecodes的数据作为类的字节码进行newInsantce操作从而调用其构造方法或static块。故可以fastjson为契机去调用此类。 但是由于_name 和_bytecodes 是私有属性,所以需要FASTJSON反序列化接口有Feature.SupportNonPublicField参数才能实现,利用条件很苛刻,但是条件允许的话就很方便,payload打过去就完事。
“_tfactory这个字段在TemplatesImpl既没有get方法也没有set方法,这没关系,我们设置_tfactory为{ },fastjson会调用其无参构造函数得_tfactory对象,这样就解决了某些版本中在defineTransletClasses()用到会引用_tfactory属性导致异常退出。“
_bytecodes的类长这样,编译生成Evil.class,将字节码读出并用base64加密,作为_bytecodes

版本1.2.24-JdbcRowSetImpl利用链

com.sun.rowset.JdbcRowSetImpl,通过JNDI注入来实现RCE。而且其原理就是setter的自动调用,但需注意JNDI注入有JDK版本限制,高版本需要进行绕过。
我们的payload一般长这样
把这个payload打过去,会执行setAutoCommit(),又setAutoCommit()执行了connct()函数,其如下。 connect()会对dataSourceName属性进行一个InitialContext.lookup(dataSourceName),从而实现JNDI注入。

版本1.2.25-1.2.47

Fastjson 1.2.25改动 autotype 默认为False状态 增加 checkAutoType 方法,在该方法中进行黑名单校验,同时增加白名单机制 流程 autoType默认关闭,会先走黑名单,如果指定类不在黑名单中再走白名单的判断,符合后再去loadClass该类 autoType开启,会先走一个白名单acceptList的判断(白名单默认为空,需要手动添加白名单),如果当前@Type指定的要反序列化的类以acceptList数组中某一元素开头则直接loadClass去加载
从1.2.25到1.2.41都是对黑白名单机制的绕过和优化 1.2.25黑名单
在1.2.42中,在ParserConfig类中黑名单改为了哈希黑名单,防止对黑名单进行分析绕过 payload:需开启autoType ,通过双写L和;进行绕过 在1.2.43版本时在checkAutoType方法中对双写L进行了过滤
payload:通过“[”进行绕过 在1.2.44版本中,对’‘[’’进行了检查过滤 1.2.25-1.2.32通用payload
这里指定jdk自带的class类,未开启autotype不进入黑白名单判断,之后调用deserialize方法时,会去调用loadClass 加载JdbcRowSetImpl,而strVal的值是在上面通过判断键是否为”val”,是的话再提取val键对应的值赋给objVal变量,而objVal在后面会赋值给strVal变量。 最终会将JdbcRowSetImpl,的className与class对象的映射缓存到mappings中,再一次进入checkAutoType方法后,会先从mappings中拿出class对象赋值给clazz.
1.2.33-1.2.47 还是通过指定java.lang.class将JdbcRowSetImpl缓存到mappings里,但是在第二次进入checkAutoType方法时,如果开启checkAutoType进行黑白名单检测,会不调用getMapping,if条件中的typeName为空,方法不抛出异常.
1.2.48在TypeUtils#loadClass中禁止了cache的使用,使用class缓存到mapping的方式就不能用了 参考文章及来源:https://cloud.tencent.com/developer/article/1957185https://www.sohu.com/a/479240064_121124363 原文链接:https://blog.csdn.net/liu649983697/article/details/125049990 https://www.cnblogs.com/CoLo/p/15842880.html#fastjson-1225-1242-bypass
反序列化
  • 漏洞
  • 反序列化
  • 代码审计
  • General-generaldocker常用操作
    目录