Iniezione di ogetti corrotti in DL e Fiddle

Esiste una vulnerabilità in DL e Fiddle in Ruby che consente di utilizzare stringhe tainted in chiamate di sistema, indipendentemente dal livello di $SAFE. Alla vulnerabilità è stato assegnato l’identificatore CVE CVE-2013-2065.

Impatto

Le funzioni native esposte a Ruby con DL o Fiddle non controllano il valore di taint degli oggetti passati. Questo potrebbe risultare in oggetti tainted accettati come input invece di sollevare un’eccezione di classe SecurityError.

Esempio di codice vulnerabile con 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

Esempio di codice vulnerabile con 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

Tutti gli utenti che utilizzano una versione affetta devono aggiornare alla versione più recente o utilizzare una delle soluzioni proposte immediatamente.

Nota: tutto questo non impedisce l’utilizzo di offset numerici come puntatori. I numeri non possono essere marchiati come tainted, quindi gli offset numerici non possono essere convalidati. Ad esempio:

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

In questo caso viene passato un indirizzo di memoria, che non può essere convalidato da DL / Fiddle. È quindi necessario controllare il taint dell’input dell’utente prima di passare l’indirizzo di memoria:

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

Soluzioni alternative

Se per qualche motivo non è possibile aggiornare la versione di Ruby, è possibile utilizzare questa patch come soluzione alternativa:

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

Versioni soggette alla vulnerabilità

  • Tutte le versioni di Ruby 1.9 precedenti alla versione a p-426
  • Tutte le versioni di Ruby 2.0 precedenti alla versione a p-195
  • Prima della revisione 40728

Le versioni di Ruby 1.8 non sono soggette alla vulnerabilità.

Riconoscimenti

Grazie a Vit Ondruch por aver segnalato questo problema.

Cronologia

  • Pubblicato per la prima volta il giorno 2013-05-14 alle ore 13:00:00 (UTC)