Taint Object mem-bypass DL dan Fiddle pada Ruby (CVE-2013-2065)

Ada kelemahan pada DL dan Fiddle di Ruby di mana string yand di-taint dapat digunakan pada system call, terlepas dari tingkat $SAFE yang diset di Ruby. Kelemahan ini sudah di-assign dengan identifier CVE-2013-2065.

Dampak

Fungsi native yang di-expose ke Ruby dengan DL atau Fiddle tidak melakukan pengecekan terhadap nilai taint yang diset pada suatu object. Ini dapat mengakibatkan object yang di-taint tersebut diterima sebagai input ketika seharusnya exception SecurityError terjadi.

Berikut ini contoh kode DL yang memiliki kelemahan tersebut.

def fungsiku(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
fungsiku "uname -rs".taint

Berikut ini contoh kode Fiddle yang memiliki kelemahan tersebut.

def fungsiku(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
fungsiku "uname -rs".taint

Semua pengguna yang menjalankan rilis yang memiliki kelemahan ini sebaiknya meng-upgrade atau menggunakan solusi lain secepatnya.

Ingat bahwa ini tidak menghindari offset memory numerik dari digunakan sebagai nilai pointer. Angka tidak dapat di-taint, jadi kode yang memberikan offset memory numerik tidak dapat dicek. Contohnya:

def fungsiku(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
fungsiku DL::CPtr[user_input].to_i

Dalam hal ini, lokasi memory diberikan, dan Dl/Fiddle tidak dapat memastikan bahwa object itu di-taint. Harap cek nilai taint dari input user sebelum memberikan lokasi memory.

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

Solusi-Solusi Lain

Jika Anda tidak dapat meng-upgrade Ruby, monkey patch di bawah ini dapat digunakan sebagai solusi lain.

class Fiddle::Function
  alias :old_call :call
  def call(*args)
    if $SAFE >= 1 && args.any? { |x| x.tainted? }
      raise SecurityError, "parameter yang sudah di-taint tidak diizinkan"
    end
    old_call(*args)
  end
end

Versi-Versi yang Terpengaruh

  • Semua ruby versi 1.9 sebelum ruby 1.9.3 patchlevel 426
  • Semua versi 2.0 sebelum 2.0.0 patchlevel 195
  • sebelum trunk revisi 40728

Ruby versi 1.8 tidak terpengaruh.

Credits

Terima kasih kepada Vit Ondruch untuk menginformasikan masalah ini.

History

  • Originally published at 2013-05-14 13:00:00 (UTC)