Segurança reforçada: correção de vulnerabilidade no ImageMagick
Na quinta-feira, 20 de junho de 2019, nosso capitão de suporte soou o alerta vermelho quando foi reportada uma vulnerabilidade que permitia obter acesso root a um servidor da Transloadit. Esse é o nível máximo de privilégio possível em uma máquina e o pior pesadelo de qualquer engenheiro de segurança ou fundador de startup de tecnologia.

Neste post do blog, vamos revelar como o ataque aconteceu, qual foi o impacto, o que já fizemos e o que ainda planejamos fazer para evitar que isso aconteça no futuro.
Contexto
A Transloadit usa diversas ferramentas de codificação para manipular e converter mídia. Para imagens, usamos o ImageMagick e patrocinamos esse projeto há muitos anos. Até hoje, devemos muito ao ImageMagick.
Os clientes da Transloadit constroem seus negócios sobre o nosso e esperam que essa base seja sólida. Isso torna difícil para nós alterar ou atualizar software, já que isso faz com que comportamentos mudem de formas sutis e nem tão sutis. Por isso, até agora, temos lançado novas versões de stack (English), tornando o uso delas opcional. Os clientes podem testar os novos stacks quando for conveniente para eles, enquanto as versões antigas continuam oferecendo o serviço que eles esperam e do qual dependem.
A versão mais antiga, conhecida internamente como imagemagick_stack v1.0.0, é suportada por nós há dez anos. Faz tempo que pretendemos descontinuá-la, mas isso precisa ser feito com cuidado. Se retirarmos um tijolo essencial da base dos nossos clientes, os negócios deles podem acabar desmoronando. Como em qualquer software, são encontrados bugs e vulnerabilidades que precisam ser corrigidos. O ImageMagick não é exceção. Ao longo dos anos, algumas vulnerabilidades graves foram descobertas no imagemagick_stack v1.0.0. Uma delas possibilitava executar comandos do sistema escondidos em imagens SVG especialmente elaboradas.
Isso coloca a Transloadit entre a cruz e a espada. Por um lado, precisamos oferecer essa base robusta que nunca muda; por outro, precisamos atualizar software vulnerável para não colocar nossos clientes em risco. Encaramos esse dilema adotando uma terceira opção, na qual descontinuamos software vulnerável de forma gradual. Ajudamos nossos clientes a abandonar aos poucos o que é antigo e, enquanto isso, ganhamos tempo contendo o software com falhas.
Nossa contenção consiste em:
- Limitar aquilo a que nossas máquinas de codificação têm acesso. Neste caso, apenas arquivos temporários com nomes em hash, o S3 e a obtenção de Jobs de uma fila.
- Escanear imagens SVG (e similares) que contenham comandos do sistema e rejeitá-las antes que o ImageMagick as processe.
- Executar nossos processos com um usuário sem privilégios, que não tem acesso a nenhum segredo além do que foi injetado na memória do seu processo pelo usuário root.
O que aconteceu
Em 20 de junho, Jeremy Matos, engenheiro de segurança sênior do GitLab, reportou que um hacker havia obtido acesso root a um dos nossos servidores. O GitLab mantinha uma campanha no HackerOne na qual convida hackers a expor vulnerabilidades e oferece recompensas por qualquer tentativa de ataque bem-sucedida que seja divulgada a eles de forma responsável. O GitLab adquiriu o Gitter.im em 2017, e o Gitter (pense no Slack, mas para projetos de código aberto) usava nossos serviços desde 2014. Quando você envia uma imagem junto com suas mensagens de chat no Gitter, o processo de upload e redimensionamento podia ser feito pela plataforma da Transloadit.
O pesquisador de segurança Sergey Kashatov entrou nesse programa e tentou comprometer o Gitter.im do GitLab fazendo upload de uma imagem com um payload malicioso. Ele achou que tinha encontrado uma vulnerabilidade do GitLab, mas, sem que ele soubesse naquele momento, a imagem acabou sendo processada nos nossos servidores, comprometendo assim a Transloadit. Jeremy percebeu isso rapidamente e repassou a conversa com Sergey até que pudéssemos falar diretamente com Sergey e entender como ele havia obtido acesso root.
Como aconteceu: a análise da “causa raiz”
Richard I. Cook explica em How Complex Systems Fail que
“Atribuir, após o acidente, [o] acidente a uma ‘causa raiz’ é fundamentalmente errado. Como uma falha evidente exige múltiplos defeitos, não existe uma ‘causa’ isolada de um acidente. Há múltiplos fatores que contribuem para os acidentes.”
Embora talvez existam gradações e às vezes seja suficiente apontar a principal anomalia contribuinte, neste caso achamos útil descrever mais de uma.
Como indicado anteriormente, estávamos cientes das vulnerabilidades do stack v1.0.0 do ImageMagick e contínhamos os danos potenciais das seguintes formas:
Executar nossos processos com um usuário sem privilégios
Essa proteção falhou quando introduzimos um novo executor de processos no início deste ano. Na tentativa de mitigar a lentidão na leitura de metadados, queríamos aproveitar melhor os múltiplos núcleos das nossas máquinas de codificação e paralelizar esse trabalho iniciando várias instâncias do mesmo processo. Para isso, implementamos um orquestrador existente que já tinha sido muito usado em produção.
No entanto, ao migrar para o novo supervisor, deixamos de garantir que ele continuasse iniciando
seus processos com o usuário sem privilégios. Em vez disso, ele iniciava os processos de leitura de
metadados como o usuário ubuntu, que tem privilégio para acessar mais arquivos e até se tornar
root. Isso passou despercebido por dois motivos: A) não tínhamos monitoramento em produção que
garantisse que nossos processos continuassem rodando com o usuário limitado e B) em desenvolvimento
e testes, rodamos tudo com o mesmo usuário por conveniência, então essa situação pareceria
completamente normal para a maioria dos desenvolvedores.
Escanear imagens SVG (e similares)
Nossa filtragem, que rejeitaria payloads maliciosos, verifica todos os vetores de ataque possíveis, mas não fazia isso de forma recursiva para inclusões. Arquivos SVG podem referenciar outros arquivos com a intenção de incorporá-los. Nesse sentido, arquivos SVG são muito parecidos com arquivos HTML: um amontoado de tags XML que descreve como as coisas devem ser renderizadas, podendo até incluir outras imagens como parte disso. Enquanto outros hackers optaram por entregar payloads maliciosos diretamente, Sergey decidiu fazer upload de um SVG válido que referenciava outro arquivo contendo os comandos maliciosos do sistema. Ele disfarçou essa inclusão e deu a ela uma extensão .jpeg, enganando ainda mais nosso sistema, que acreditou ser seguro repassá-la ao ImageMagick.
Impacto
Sergey divulgou esse problema de forma responsável e não roubou nem excluiu nenhum dado. É claro que é possível que outro hacker tenha explorado essa vulnerabilidade antes de Sergey descobri-la e tenha, sim, roubado ou excluído dados. Nossa investigação revela zero indícios nesse sentido, mas isso não pode ser totalmente descartado.
Se um hacker mal-intencionado tivesse usado esse exploit e obtido acesso root a uma máquina de codificação, ele teria conseguido:
- Inspecionar arquivos temporários. Esses arquivos consistem na entrada ou na saída de um Robot e existem por pouco tempo na máquina de codificação. No entanto, os arquivos temporários são nomeados por UUIDv4 sem hifens e não podem ser rastreados até o usuário ou cliente original.
- Acessar os buckets S3 da Transloadit
Um pequeno ponto positivo nessa descoberta alarmante é que, alguns anos antes, já tínhamos limitado aquilo a que nossas máquinas de codificação têm acesso. Assim, mesmo com acesso root, as máquinas não conseguiriam acessar recursos da AWS (além do S3), nosso banco de dados ou os segredos dos nossos clientes.
Medidas corretivas
Naturalmente, nós imediatamente:
- Melhoramos nossa filtragem para lidar com payloads maliciosos referenciados externamente e não
permitimos mais esse tipo raro de imagem em um stack vulnerável. A Assembly agora termina com
um erro e emite um aviso pedindo que você atualize para o stack
v2.0.3. - Removemos o novo processo supervisor e voltamos a executar nosso processo com um usuário sem privilégios, adicionando monitoramento em produção para sermos acionados caso isso volte a mudar.
- Criamos uma biblioteca em C que impede o ImageMagick de fazer qualquer requisição de rede por conta própria.
- Rotacionamos todas as nossas chaves (por exemplo, as dos nossos próprios buckets S3) e limitamos ainda mais o acesso IAM das máquinas de codificação, que agora só têm acesso de escrita aos poucos buckets de que precisam (por exemplo, tmp.transloadit.com). Também tornamos a rotação de chaves muito mais fácil, para que possamos fazê-la num piscar de olhos como precaução geral.
- Recompensamos Sergey pelo trabalho, já que o GitLab obviamente tem a política de não conceder recompensas por vulnerabilidades descobertas em sistemas que não são gerenciados por ele.
- Atualizamos todas as nossas máquinas para a LTS mais recente do Ubuntu, a bionic, que garante mais quatro anos de patches e oferece ferramentas adicionais para isolar ainda mais nossos processos de codificação.
Isso deve resolver os problemas imediatos. Pedimos a Sergey que confirmasse que a Transloadit não está mais vulnerável, e ele confirmou. Isso não significa, porém, que terminamos. Ainda estão na nossa lista:
- Usar o usuário sem privilégios também em desenvolvimento e testes. Isso pode deixar o desenvolvimento um pouco mais lento, mas foi essa discrepância entre produção e desenvolvimento que permitiu que essa vulnerabilidade passasse despercebida.
- Utilizar as novas ferramentas do nosso sistema operacional para isolar ainda mais nossos processos de codificação e dar a eles acesso apenas ao arquivo temporário em que estão trabalhando.
- Iniciar o procedimento de descontinuação para remover o imagemagick_stack v1.0.0. Vamos mapear
quem ainda o usa e emitir avisos lembrando essas pessoas de testar um stack mais recente. Também
vamos enviar e-mails aos clientes e oferecer toda a ajuda necessária para que migrem sem
problemas para stacks mais modernos. Quando o último cliente deixar de usá-lo, removeremos
v1.0.0completamente. - Implementar uma allowlist de variáveis de ambiente para nossas ferramentas de codificação. Mesmo que nossas máquinas de codificação só tenham acesso de escrita aos nossos buckets S3, realmente não há necessidade de o ImageMagick saber disso.
Recomendações
Não acreditamos que seja necessário você rotacionar nenhuma senha, já que não houve acesso a senhas ou dados similares. Não temos nenhuma indicação de que esse ataque tenha sido realizado com sucesso antes de Sergey. Embora consideremos o acesso não autorizado a arquivos temporários de codificação o pior cenário possível, felizmente nem tudo é tão sombrio. Esses arquivos temporários são anonimizados, muitas vezes não estão completos (pois estão sendo baixados) e são removidos assim que a codificação é concluída e o upload termina.
Ainda assim, não podemos descartar a possibilidade de que um hacker tenha obtido arquivos temporários e, claro, a própria mídia pode conter informações de identificação (por exemplo, uma foto de alguém com um crachá ou uma placa de rua que revele sua localização; se repassada ao Google ou ao Facebook, essas empresas podem identificar quem aparece na imagem). Por isso, recomendamos que você informe isso aos seus clientes, assim como estamos informando a você.
Felizmente, nenhuma credencial vazou em consequência dessa vulnerabilidade, mas isso não é motivo para acomodação. Embora trabalhemos todos os dias para alcançar os mais altos níveis de segurança, 100% de segurança sempre será um mito. Por isso, é melhor nos dar acesso de escrita apenas a um único bucket, ou até a uma única pasta, do que nos dar acesso root a tudo só para que possamos escrever nesse único bucket ou pasta.
E, se você ainda não fez isso, também é uma boa ideia atualizar seu Robot
/image/resize para
"imagemagick_stack": "v2.0.3".
Conclusão
Ficamos profundamente preocupados com isso. Manter nossos clientes seguros a qualquer custo é vital para a continuidade da Transloadit, e nossa empresa significa tudo para nós. Nas últimas semanas, trabalhamos sem parar para implementar atualizações, para que algo assim nunca mais possa acontecer. Também estamos trabalhando com Sergey e outros pesquisadores de vulnerabilidades como ele para garantir isso. Mais atualizações ainda estão por vir, mas já sentimos a necessidade de revelar esse problema de segurança. Esperamos que isso dê a você, como cliente, tempo suficiente para lidar com a situação da forma mais adequada para o seu negócio.
Lamento profundamente os erros da nossa parte que levaram a essa vulnerabilidade em produção. Se você tiver dúvidas ou preocupações após ler este texto, não hesite em entrar em contato. É claro que estou mais do que disposto a fornecer qualquer esclarecimento adicional.
