Como encontrar desserialização de YAML com Snyk Code
Calum Hutton
23 de fevereiro de 2023
0 minutos de leituraConduzi uma pesquisa para tentar identificar problemas de injeção de YAML em projetos de código aberto usando Snyk Code. Embora essa vulnerabilidade não seja nova, o impacto potencial da injeção de YAML é alto, o que a tornou uma boa candidata para pesquisa. Essa pesquisa levou à descoberta de vários problemas em projetos de código aberto escritos em Python, PHP e Ruby. Este artigo se concentra no problema encontrado no geokit-rails versão 2.3.2, um plugin para Ruby on Rails
YAML
YAML é mais do que um simples formato de intercâmbio de dados, como JSON. A especificação descreve vários recursos avançados que merecem atenção em uma investigação de segurança, como:
Tags personalizadas (por exemplo, PyYAML)
Âncoras e aliases
Atributos mesclados
Fluxos com vários documentos
YAML também pode ser usado para serializar dados binários e objetos arbitrários em várias linguagens, o que pode levar a vulnerabilidades de desserialização. Essas vulnerabilidades são o foco desta pesquisa, pois a exploração bem-sucedida costuma levar à execução remota de código (RCE).
Desserialização de YAML em Ruby
Em Ruby, a análise de YAML faz parte da linguagem, portanto não são necessárias bibliotecas adicionais. Se uma aplicação usar o parser nativo de YAML do Ruby, estará vulnerável a ataques de desserialização caso YAML.load() ou YAML.load_file() seja usado em vez de YAML.safe_load() ou YAML.safe_load_file(), respectivamente. Uma alternativa segura por padrão para analisar YAML está disponível no projeto SafeYAML.
O script e a saída a seguir demonstram uma forma insegura de carregar YAML com YAML.load().
A variável var contém um hash simples do Ruby, enquanto a variável yaml contém o hash equivalente serializado no formato YAML. As duas instruções puts exibem o mesmo hash, porque a variável yaml foi desserializada de volta de uma string YAML para um hash por meio de YAML.load(). Objetos mais complexos também podem ser serializados e desserializados dessa forma.
Nos estágios iniciais desta pesquisa, encontrei um gadget universal de desserialização de YAML para Ruby que funcionava nas versões 2.x a 3.x do Ruby e que, ao ser desserializado, disparava a execução de comandos arbitrários.
A carga YAML acima executa o comando id durante a desserialização se for analisada com YAML.load() ou YAML.load_file().
Estudo de caso: geokit-rails (2.3.2)
A gem geokit-rails é um plugin para Ruby on Rails que oferece serviços de localização para a aplicação. O plugin usa o método inseguro YAML.load() por meio do método retrieve_location_from_cookie_or_service() em geokit-rails/ip_geocode_lookup.rb:
Os dados enviados ao método inseguro YAML.load() vêm do parâmetro cookies do Ruby on Rails, que contém os cookies enviados na solicitação. Isso é uma boa notícia para um invasor, pois os cookies podem ser controlados diretamente pela criação de uma solicitação HTTP adequada.
Prova de conceito
Configurei uma aplicação Rails com o plugin geokit-rails (versão 2.3.2) no Ruby 3.0.0. A solicitação HTTP a seguir foi enviada à aplicação para explorar o problema. Ela inclui a carga YAML codificada na URL no cookie geo_location.
Na aplicação Rails, a carga foi desserializada e executada, rodando o comando id para comprovar a execução de comandos.
Em um sistema que utiliza geokit-rails, um invasor que explore essa vulnerabilidade pode iniciar uma RCE, potencialmente assumindo o controle total do sistema.
Correção
Esse problema foi divulgado de forma responsável ao mantenedor do geokit-rails e corrigido na versão 2.5.0 do software, substituindo por JSON o YAML que continha as informações de coordenadas. Com base nesta pesquisa, aprimoramos as regras do Snyk Code para detectar injeções de YAML, o que significa que agora mais desses problemas podem ser detectados nos projetos dos usuários.
Comece a jogar Capture the Flag
Aprenda a resolver desafios de Capture the Flag assistindo à gravação sob demanda do nosso workshop virtual introdutório.


