Posté par usa le 2013-05-14
Traduit par Jean-Denis Vauguet
Les modules DL
et Fiddle
de Ruby comportaient une vulnérabilité mettant
en œuvre une chaîne de caractère « contaminée » (tainted string, marquée
avec la méthode Object#tain
). Des appels systèmes pouvaient être fait en
utilisant de telles chaînes de caractères, ignorant le niveau $SAFE
de
Ruby. Cette vulnérabilité porte l’identifiant CVE-2013-2065.
Explications et impact
Les fonctions natives exposées à Ruby via DL
ou Fiddle
ne vérifiaient pas
la valeur du drapeau taint
des objets manipulées. Cela pouvait causer des
situations où des chaînes de caractères marquées comme contaminées étaient
tout de même acceptées comme des données valides pour des exceptions de type
SecurityError
.
Un exemple de code utilisant DL
illustrant cette vulnérabilité :
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
Un autre exemple, avec 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
Tous les rubyistes utilisant une version affectée par cette vulnérabilité sont invités à mettre à jour Ruby, ou à utiliser le palliatif décrit ci-après.
Veuillez notez que le correctif n’empêche pas l’utilisation d’offset
numériques, car les nombres ne peuvent être marqués par Object#taint
. Dans
l’exemple suivant :
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
l’adresse mémoire est utilisée sans qu’il soit possible de déterminer si elle est valide ou non. Dans ce cas, il est recommandé de vérifier l’état de la donnée en entrée avant de passer l’adresse mémoire :
user_input = "uname -rs".taint
raise if $SAFE >= 1 && user_input.tainted?
my_function DL::CPtr[user_input].to_i
Palliatif
Si vous êtes dans l’impossibilité de mettre à jour Ruby, il est tout de même possible de palier cette vulnérabilité avec le monkey patching suivant :
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
Versions affectées
- Toutes les versions de la branche 1.9 avant la 1.9.3-p426
- Toutes les versions de la branche 2.0 avant la 2.0.0-p195
- Les versions de développement avant la révision 40728
La branche 1.8 n’est pas concernée.
Remerciements
Merci à Vit Ondruch pour avoir mis en lumière cette vulnérabilité.
Historique
- Initialement publié le 14 mai 2013 à 13:00:00 (UTC)