Inyección de objetos corruptos con DL y Fiddle en Ruby
Publicado por usa el 2013-05-14
Traducción de David Padilla
Existe una vulnerabilidad en DL y Fiddle en Ruby donde se puede utilizar cadenas corruptas en llamadas a systema sin importar el nivel de $SAFE establecido. Se le ha asignado el identificador CVE a esta vulnerabilidad CVE-2013-2065.
Impacto
Funciones nativas expuestas en Ruby con DL o Fiddle no validan los valores de los objetos que se les pasan. Esto puede resultar que se acepten objetos corruptos como entrada cuando se debería levantar una excepción de clase SecurityError.
Ejemplo de código vulnerable 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".taintEjemplo de código vulnerable 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".taintTodos los usuarios utilizando una versión afectada deberían de actualizar a la última versión o utilizar una de las soluciones propuestas inmediatamente.
Nota: nada de esto previene utilizar desplazamientos de memoria numéricos como valores de apuntador. Los números no son corrompibles asi que si se pasa un desplazamiento de memoria numérico este no puede ser validado. Por ejemplo:
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_iEn este caso, lo que se está pasando es la dirección en memoria del objeto la cual no puede ser validada por DL / Fiddle. En este caso, se debe de validar el objeto antes de pasar la dirección de memoria:
user_input = "uname -rs".taint
raise if $SAFE >= 1 && user_input.tainted?
my_function DL::CPtr[user_input].to_iSoluciones Alternas
Si por alguna razón no puede actualizar la versión de Ruby, se puede utilizar este parche como solución alterna:
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
endVersiones afectadas
- Todas las versiones de Ruby 1.9 anteriores a p-426
- Todas las versiones de Ruby 2.0 anteriores a p-195
- Antes de la revisión 40728
Las versiones de Ruby 1.8 no son afectadas
Creditos
Gracias a Vit Ondruch por reportar este problema.
Historial
- Publicado originalente 2013-05-14 13:00:00 (UTC)
Noticias recientes
Publicado Ruby 4.0.0 preview3
Nos complace anunciar la publicación de Ruby 4.0.0-preview3. Ruby 4.0 introduce Ruby::BOX y “ZJIT”, y agrega muchas mejoras.
Publicado por naruse el 2025-12-18
Publicación de Ruby 3.4.8
Ruby 3.4.8 ha sido publicado.
Publicado por k0kubun el 2025-12-17
Publicación de Ruby 4.0.0 preview2
Nos complace anunciar el lanzamiento de Ruby 4.0.0-preview2. Ruby 4.0 actualiza su versión de Unicode a 17.0.0, entre otras novedades.
Publicado por naruse el 2025-11-17
Publicación de Ruby 3.3.10
Ruby 3.3.10 ha sido publicado.
Publicado por nagachika el 2025-10-23