Ruby 中 DL 和 Fiddle 的对象污染绕过漏洞 (CVE-2013-2065)

Ruby 中的 DL 和 Fiddle 存在一个漏洞,被污染的字符串可以被系统调用使用,而忽略 Ruby 中设置的 $SAFE 级别。此漏洞已被分配 CVE 标识符 CVE-2013-2065。

影响

通过 DL 或 Fiddle 暴露给 Ruby 的本地函数不会检查传入对象的污染值。这可能导致在应该引发 SecurityError 异常时,接受被污染的对象作为输入。

受影响的 DL 代码如下所示

def my_function(user_input)
  handle    = DL.dlopen(nil)
  sys_cfunc = DL::CFunc.new(handle['system'], DL::TYPE_INT, 'system')
  sys       = DL::Function.new(sys_cfunc, [DL::TYPE_VOIDP])
  sys.call user_input
end

$SAFE = 1
my_function "uname -rs".taint

受影响的 Fiddle 代码如下所示

def my_function(user_input)
  handle    = DL.dlopen(nil)
  sys = Fiddle::Function.new(handle['system'],
                             [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
  sys.call user_input
end

$SAFE = 1
my_function "uname -rs".taint

所有运行受影响版本的用户都应立即升级或使用其中一种解决方法。

请注意,这不会阻止将数字内存偏移量用作指针值。数字不能被污染,因此无法检查传递数字内存偏移量的代码。例如

def my_function(input)
  handle    = DL.dlopen(nil)
  sys = Fiddle::Function.new(handle['system'],
                             [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
  sys.call input
end

$SAFE = 1
user_input = "uname -rs".taint
my_function DL::CPtr[user_input].to_i

在这种情况下,传递的是内存位置,DL / Fiddle 无法确定对象的污染情况。在这种情况下,请在传递内存位置之前检查用户输入的污染情况

user_input = "uname -rs".taint
raise if $SAFE >= 1 && user_input.tainted?
my_function DL::CPtr[user_input].to_i

解决方法

如果您无法升级 Ruby,可以使用以下猴子补丁作为解决方法

class Fiddle::Function
  alias :old_call :call
  def call(*args)
    if $SAFE >= 1 && args.any? { |x| x.tainted? }
      raise SecurityError, "tainted parameter not allowed"
    end
    old_call(*args)
  end
end

受影响的版本

  • 所有 ruby 1.9 版本,早于 ruby 1.9.3 patchlevel 426
  • 所有 ruby 2.0 版本,早于 ruby 2.0.0 patchlevel 195
  • 早于主干版本 40728

ruby 1.8 版本不受影响。

鸣谢

感谢 Vit Ondruch 报告此问题。

历史

  • 最初发布于 2013-05-14 13:00:00 (UTC)