Omijanie zaufania obiektu w DL i Fiddle w Ruby (CVE-2013-2065)

Zamieszczone przez usa 2013-05-14
Tłumaczone przez crabonature

Wykryto lukę bezpieczeństwa w modułach DL i Fiddle w Ruby gdzie niepewne napisy (tainted strings - napisy, które są wprowadzane z zewnętrznych źródeł np. pliku, klawiatury, sieci itp. Są oznaczone specjalną flagą - Object#taint, Object#untaint, Object#tainted?) mogą być wykorzystane przez wywołania systemowe niezależnie od ustawionego poziomu $SAFE w Ruby. Luce tej został przypisany identyfikator CVE-2013-2065.

Wpływ

Natywne funkcje wystawione dla Rubiego z DL lub Fiddle nie sprawdzają wartości taint ustawionej w przekazywanych obiektach. Może to spowodować zaakceptowanie niepewnych obiektów jako zaufane dane wejściowe, w momencie gdy powinien zostać zgłoszony wyjątek SecurityError.

Przykładowy kod DL ilustrujący lukę będzie wyglądać mniej więcej tak:

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

Przykładowy kod Fiddle ilustrujący lukę będzie wyglądać mniej więcej tak:

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

Wszyscy użytkownicy podatnych wersji powinni natychmiast zaktualizować Ruby lub skorzystać z obejścia problemu.

Zauważ, że to nie powstrzymuje od użycia numerycznych offsetów pamięci jako wartości wskaźników. Numery nie mogą być tainted, więc kod przekazujący numeryczny offset pamięci nie może być sprawdzony. Dla przykładu:

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

W tym przypadku adres w pamięci jest przekazywany, więc zaufanie obiektu nie może być określone przez DL / Fiddle. W takim przypadku proszę sprawdzać zaufanie danych wprowadzanych przez użytkownika przed przekazaniem adresu w pamięci:

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

Obejście problemu

Gdy nie możesz zaktualizować Rubiego, ta łatka - monkey patch - może być użyta jako obejście problemu:

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

Dotyczy wersji

  • Dla 1.9 wszystkie wcześniejsze wersje od 1.9.3 patchlevel 426
  • Dla 2.0 wszystkie wcześniejsze wersje od 2.0.0 patchlevel 195
  • Wcześniej niż rewizja trunk 40728

Wersje 1.8 nie są podatne.

Podziękowania

Podziękowania dla Vita Ondrucha za zgłoszenie tego problemu.

Historia

  • Opublikowane 2013-05-14 13:00:00 (UTC)

Aktualności

Wydano Ruby 2.2.0

Jest nam miło ogłosić wydanie Rubiego 2.2.0.

Zamieszczone przez naruse 2014-12-25

Wydano Ruby 2.2.0-rc1

Jest nam miło ogłosić wydanie Rubiego 2.2.0-rc1. Po RC1, wszystkie zmiany zostaną ograniczone tylko do poprawiania błędów. Finalne wydanie Rubiego 2.2.0 jest zaplanowane na 25...

Zamieszczone przez naruse 2014-12-18

Więcej aktualności...