- Andres Freund, da Microsoft, descobriu um backdoor embutido no xz Utils, usado em quase todos os ambientes Linux/Unix, enquanto investigava uma anomalia de desempenho no SSH em sistemas Debian
- O código malicioso foi incluído no xz Utils 5.6.0 e 5.6.1 e foi projetado para permitir que um invasor com uma chave privada específica escondesse código em um certificado de login SSH e o executasse em dispositivos com o backdoor
- O invasor tentou enganchar a rotina de autenticação do
sshdvialiblzma, usando tarballs de release, arquivos de teste, scripts de build e o IFUNC do glibc, em vez do código-fonte do GitHub - O backdoor verificava condições de build de pacote em amd64/x86_64, glibc e distribuições derivadas de Debian ou Red Hat, e foi incluído por um período em Fedora Rawhide, Fedora 41, Debian testing/unstable/experimental, openSUSE Tumbleweed/MicroOS e alguns releases do Kali Linux
- A persona de desenvolvedor Jia Tan se envolveu na manutenção do xz Utils ao longo de anos; o caso é rastreado como CVE-2024-3094, e surgiram ferramentas de detecção e análise como a página de verificação da Binarly e o xzbot
Descoberta e alcance do impacto
- Andres Freund é desenvolvedor e engenheiro ligado a trabalhos com PostgreSQL na Microsoft e percebeu sinais anormais ao investigar um fenômeno em que o login via SSH consumia CPU em excesso e gerava erros no valgrind em sistemas Debian
- A causa era uma atualização do xz Utils, e Freund revelou na Open Source Security List que essa atualização era um backdoor intencionalmente inserido em um software de compressão
- O xz Utils fornece compressão e descompressão de dados sem perda em praticamente todos os sistemas operacionais da família Unix, incluindo Linux, e também oferece suporte ao formato legado .lzma
- Filippo Valsorda avaliou o caso como “talvez o exemplo mais bem executado entre os ataques de cadeia de suprimentos descritos publicamente, e um cenário de pesadelo com um upstream malicioso, competente e privilegiado em uma biblioteca amplamente usada”
O comportamento que o backdoor visava
- O código malicioso foi adicionado ao xz Utils 5.6.0 e 5.6.1, alterando a forma como o software funciona
- O backdoor manipulava o sshd, o executável usado para conexões SSH remotas
- Alguém com uma chave criptográfica pré-definida podia esconder o código desejado em um certificado de login SSH, enviá-lo e executá-lo no dispositivo com o backdoor
- O código realmente enviado não foi identificado, então não se sabe que tipo de código o invasor pretendia executar
- Em teoria, quase qualquer ação seria possível, incluindo roubo de chaves criptográficas ou instalação de malware
Como a biblioteca de compressão alcançou o SSH
- Uma biblioteca pode manipular o funcionamento interno dos executáveis aos quais está vinculada
- A implementação mais comum do
sshdno OpenSSH não é vinculada ao liblzma por padrão - Debian e várias distribuições Linux adicionaram patches para conectar o
sshdao systemd- O systemd é o programa que carrega vários serviços durante a inicialização
- O systemd é vinculado ao liblzma
- Por causa desse caminho de ligação, o xz Utils pôde afetar o
sshd
Indícios de preparação ao longo de anos
- Em 2021, um usuário chamado JiaT75 deixou seu primeiro commit conhecido em um projeto de código aberto
- Foi uma mudança no projeto libarchive que trocou a função safe_fprint por uma variante conhecida havia muito tempo como menos segura, algo que ninguém percebeu na época
- Em 2022, JiaT75 enviou um patch para a mailing list do xz Utils
- Logo depois, um novo participante chamado Jigar Kumar pressionou dizendo que Lasse Collin não atualizava o xz Utils com frequência nem rapidez suficientes
- Dennis Ens e outros novos participantes também pressionaram Collin a incluir mais mantenedores
- Em janeiro de 2023, JiaT75 fez seu primeiro commit no xz Utils e passou a se envolver mais profundamente nas atividades do projeto com o nome Jia Tan
- Trocou o contato de Collin no oss-fuzz pelo seu próprio contato
- Pediu uma mudança que desativava a funcionalidade IFUNC durante os testes do oss-fuzz, impedindo a detecção posterior das alterações maliciosas que entrariam no xz Utils
- Em fevereiro de 2024, Tan publicou os commits do xz Utils 5.6.0 e 5.6.1, e essa atualização implementou o backdoor
- Depois disso, Tan ou outras pessoas pediram a desenvolvedores do Ubuntu, Red Hat e Debian que integrassem a atualização ao sistema operacional
Distribuições afetadas e condições de execução
- Segundo a Tenable, a versão com backdoor ou atualizações relacionadas entrou nos seguintes releases
- Fedora Rawhide: distribuição de desenvolvimento do Fedora Linux
- Fedora 41
- Debian testing, unstable, experimental: de 5.5.1alpha-0.1 a 5.6.1-1
- openSUSE Tumbleweed e openSUSE MicroOS: versões com xz backdoorado entre 7 e 28 de março
- Kali Linux: incluiu o xz-utils 5.6.0-0.2 entre 26 e 28 de março
- Segundo a análise de Sam James, o script malicioso verificava se o alvo do build era amd64/x86_64, se usava o nome linux-gnu e se utilizava GCC e GNU ld
- Ele também verificava se era um build de pacote Debian ou se
RPM_ARCHerax86_64 - O ataque parece ter mirado ambientes que usam glibc em sistemas amd64 e fazem builds de distribuições derivadas de Debian ou Red Hat
- Não se sabia, naquele momento, se outros sistemas eram vulneráveis
Forma de implementação e técnicas de ocultação
- Sam James resumiu que o backdoor era composto por vários elementos
- o tarball de release distribuído pelo upstream não era igual ao código do GitHub
- o build-to-host.m4 do tarball de release diferia bastante do que estava no upstream do GitHub
- havia arquivos de teste manipulados na pasta
tests/do repositório gittests/files/bad-3-corrupt_lzma2.xztests/files/good-large_compressed.lzma
- um script chamado por
build-to-host.m4descompactava os dados de teste maliciosos e modificava o processo de build - o IFUNC do glibc era usado para fazer hooking ou redirecionamento em tempo de execução da rotina de autenticação do OpenSSH
- HD Moore confirmou que o estágio final do backdoor só era executado ao compilar a biblioteca em amd64 e criar pacotes Debian ou RPM
- Segundo análises dos pesquisadores, no processo de verificação da chave pública SSH, se uma certa função de fingerprint e a chave pública correspondessem, o conteúdo da chave seria descriptografado com uma chave pré-compartilhada antes da verificação real da chave pública
- Se o conteúdo descriptografado estivesse em um formato específico, ele era enviado diretamente para
system - Se o fingerprint não correspondesse ou o conteúdo descriptografado não estivesse no formato esperado, o processo voltava à verificação normal da chave, o que dificultava que o usuário percebesse a diferença
Cadeia de execução resumida pela Akamai
- Pesquisadores da Akamai avaliaram que o backdoor foi incluído apenas nos releases em tarball do código-fonte, e não no repositório GitHub do xz, numa tentativa de evitar detecção
- O backdoor foi montado ao longo de vários commits
- durante o processo de build, o uso de IFUNC permitia que o malware interceptasse a função de resolução de símbolos
- um objeto compartilhado ofuscado foi escondido dentro dos arquivos de teste
- um script era executado durante o build da biblioteca para extrair esse objeto compartilhado
- o landlocking, uma funcionalidade de segurança que restringe privilégios de processos, era desativado
- A cadeia de execução se desenrolava em várias etapas
build-to-host.m4era executado durante o build da biblioteca e decodificavabad-3-corrupt_lzma2.xzcomo um script bash- esse script bash decodificava
good-large_compressed.lzmade forma ainda mais complexa para criar outro script - esse script extraía o objeto compartilhado
liblzma_la-crc64-fast.oe o adicionava ao processo de compilação do liblzma
- Esse objeto compartilhado era compilado dentro do liblzma e substituía o processo normal de resolução de nomes de função
- A biblioteca maliciosa podia trocar o ponteiro da função
RSA_public_decryptdo OpenSSH por uma função maliciosa criada por ela - Segundo a análise de Filippo Valsorda, essa função maliciosa extraía comandos do certificado do cliente de autenticação, confirmava que se tratava do agente de ameaça e então os passava para
system(), alcançando execução remota de código antes da autenticação
Jia Tan e as dúvidas restantes
- Sabe-se muito pouco sobre Jia Tan
- Essa persona de desenvolvedor se envolveu também em dezenas de outros softwares de código aberto nos últimos anos
- Não se sabe se havia uma pessoa real por trás do nome de usuário Jia Tan ou se era um personagem totalmente fabricado
- Análises técnicas adicionais podem ser consultadas no fio de Filippo Valsorda no Bluesky, na análise de Kevin Beaumont e no material divulgado por Freund na sexta-feira
CVE e ferramentas de verificação
- O identificador de rastreamento dessa vulnerabilidade é CVE-2024-3094
- A página xz.fail da Binarly detecta a implementação IFUNC e se baseia em análise comportamental
- isso permite detectar automaticamente condições invariantes mesmo que um backdoor semelhante seja implantado em outro lugar
- O xzbot oferece recursos para análise e experimentação
- honeypot: servidor vulnerável falso para detectar tentativas de exploração
- ed448 patch: patch no
liblzma.sopara usar sua própria chave pública ED448 - backdoor format: formato do payload do backdoor
- backdoor demo: CLI que aciona RCE assumindo conhecimento da chave privada ED448
1 comentários
Comentários no Hacker News
O objetivo era facilitar a criação de testes para o XZ usando um framework de testes padronizado
Foi algo que Jia escreveu em 2022-06-17: como ainda havia muitos recursos não testados, isso ajudaria a aumentar a cobertura de testes para a estabilidade do projeto no longo prazo
Ou seja, foi uma mudança preparada havia bastante tempo
Parece que o mecanismo de linking que permitiu à lib se intrometer em
RSA_public_decryptnão foi muito discutidoFala-se bastante de coisas como separação de processos, mas pouco sobre esse redirecionamento de chamada de função
Talvez fosse possível linkar componentes centrais, como o código que entra via SSH, com bibliotecas usando um modelo hierárquico de confiança, algo como “confio em você no ponto em que eu te chamo, mas não permito que você se injete por conta própria em outros pontos de chamada”
Isso pode provocar a reação automática de “segurança por obscuridade”, dizendo que não adianta porque há formas de contornar, mas ainda assim pode ser visto como redução da superfície de ataque
Mas, no sistema operacional, há vários contextos de segurança sobrepostos. No caso do backdoor do XZ, trata-se principalmente de segurança baseada em capabilities no nível de módulo, mas também existem capabilities no nível de programa, isolamento no nível de memória (paginação), isolamento no nível de microarquitetura etc.
Fazer esses elementos funcionarem em conjunto e ainda entregar desempenho é bem difícil, e a migração de sistemas da família Unix para esse modelo parece praticamente impossível, porque exigiria substituir o próprio conceito de processo
Isso quebrou os testes do XZ, de repente apareceram contas fazendo lobby para desativar esses testes, e o resultado foi que o exploit se tornou possível
./configure && make) para aplicar um patch no ifunc resolver e fazê-lo chamar o objeto malicioso fornecidoO arquivo de objeto comprometido é linkado com a flag de linker
now, de modo que, no momento em que a biblioteca é carregada, o ifunc é resolvido imediatamente; nesse instante, a tabela de links do processo ainda está gravável, então o resolver alterado é chamadoEssa é justamente a parte importante: quando a biblioteca era carregada, ele conseguia simplesmente interceptar na memória a função
RSA_public_decryptUm texto que analisa muito bem o processo de injeção do backdoor: https://research.swtch.com/xz-script
dlopenem bibliotecas de compressão: https://github.com/systemd/systemd/pull/31550Nesse sentido, é uma forma de linking mais segura
ltracemonitora os símbolos chamados seria suficienteNão entendo por que dizem que “quase” infectou o mundo inteiro
Pelo menos três distribuições Linux bastante populares, Arch, Gentoo e openSUSE Tumbleweed, distribuíram o backdoor por algumas semanas, e no Tumbleweed ele certamente estava funcionando
Foram algumas semanas com SSH contendo backdoor; chamar isso de “quase” parece pouco
Como ele só funcionava nos alvos deb/rpm, na prática foi barrado antes de chegar à produção
Isso não quer dizer que esteja tudo bem; se isso tivesse passado tempo suficiente sem ser descoberto para entrar no RHEL ou no Debian/Ubuntu stable, teríamos recebido alertas de lugares como bancos e instituições de saúde
Com execução remota de código antes da autenticação, seria difícil dizer “não fomos afetados” a menos que a rede fosse fortemente restrita e houvesse bom logging de fluxos
Ao comparar com
cmp -loliblzma.so.5.6.1dexz-5.6.1-1exz-5.6.1-2, há apenas diferenças muito pequenasParece que isso não era sabido antes de escreverem o aviso
https://github.com/QubesOS/qubes-issues/issues/9067#issuecom...
Mas não sei como obter dados para sustentar isso
Aposto 101 dólares que, nos próximos 12 meses, algo parecido será descoberto em ambiente real
Porque os mantenedores vão começar a olhar com desconfiança para commits antigos uns dos outros
Basta olhar para codebases importantes, pouco conhecidas e com pouquíssimos mantenedores
Se eu tivesse algo assim e funcionasse bem, acho que depois eu o “descobriria” usando outra conta e faria com que fosse corrigido
As conclusões pessoais que tiro deste caso são várias
Primeiro, tarballs de distribuição de código-fonte que contêm código diferente do repositório de origem são ruins e deveríamos nos afastar deles. Outro grande ataque à cadeia de suprimentos, o event-stream, explorou um ponto parecido
Como consequência, artefatos gerados automaticamente devem sempre ser commitados
Segundo, artefatos gerados automaticamente que todo mundo passa no Page Down durante a revisão de código são um problema. Se esse tipo de arquivo está no repositório, também deveria haver testes automáticos para verificar se alguém não o manipulou, e isso também ajuda a não deixar arquivos gerados automaticamente ficarem obsoletos
Terceiro, como consequência de 1 e 2, autotools é ruim, e a cultura de autotools também é ruim
Quarto, a Libsystemd é um problema para o ecossistema. Ao dizer isso, a pessoa é rotulada como hater de systemd, mas ela é grande, complexa, tem muitas dependências, e a maioria dos programas usa apenas uma parte muito pequena dela. Incentivar todos os serviços a dependerem dela só para notificações de inicialização é loucura
Quinto, existe uma cultura de que reutilização de código é sempre boa e que não há problema em depender de uma biblioteca grande por causa de uma funcionalidade pequena, mas isso não é verdade. Dependências são um ônus de manutenção e um risco de segurança, e precisam ser ponderadas contra a funcionalidade que trazem
Sexto, também é um problema quando mantenedores de distribuições aplicam patches grandes em pacotes. Isso cria forks de fato, amplamente usados, de bibliotecas e aplicações que os mantenedores reais não acompanham
Sétimo, do ponto de vista de desenvolvedores, o OSS precisa se tornar financeiramente sustentável. Liblzma e xz-utils devem ter dezenas de milhões de instalações, mas dependiam de um único mantenedor que enfrentava problemas de saúde mental
Oitavo, não gosto de dizer isso, mas hoje também precisamos fazer considerações geopolíticas em revisões de código e na transferência de direitos de manutenção
Não há prova de que Jia Tan seja um nome real, nem sequer de que seja uma pessoa real
Se os projetos começarem a recusar contribuições de nomes que soam asiáticos, o próximo ataque simplesmente usará o nome Richard Jones
Vindo do mundo BSD, systemd é chocante, monstruoso e espalha tentáculos por todos os lados
Os consumidores são ingênuos, mas a própria indústria de software também é ingênua em relação a ameaças de segurança
Exploits sociais fazem parte dos exploits de código
O princípio do FOSS de que “quanto mais olhos olhando o código, melhor” está correto, mas só funciona quando esses olhos são treinados. O FOSS precisa de apoio material da indústria
Um engenheiro da MSFT pegou esse exploit, mas ele ainda assim entrou nas versões públicas gerais do Fedora 41, openSUSE e Kali
A cadeia de ferramentas de desenvolvimento e o processo de testes nunca foram projetados para testar segurança. SolarWinds também é uma referência útil: https://www.wired.com/story/the-untold-story-of-solarwinds-t...
Artefatos de release não contêm apenas scripts do autoconf
Há muitos motivos para colocar blobs binários em arquivos de release: recursos de jogos, imagens de firmware, casos de teste etc. Já se comentou que o mpv inclui como casos de teste alguns arquivos de mídia gerados por encoders proprietários, e isso não é ruim; é bom
O sqlite, que é bem mantido, é usado em toda parte e também tem uma excelente suíte de testes. A cada release, ele distribui não um, mas dois tarballs, para etapas diferentes de compilação. Seria fácil parar de fazer isso, mas só aumentaria o trabalho dos mantenedores de pacotes e não ajudaria a melhorar a segurança
O motivo de o Debian compilar a partir de tarballs selecionados é que eles são selecionados por uma pessoa e assinados com uma chave bem conhecida. Claro que também é possível compilar a partir do git, mas é incerto se isso melhoraria a situação. Nem todo projeto assina tags de release e, mesmo quando assina, é mais provável que isso seja automatizado
Queremos que as mudanças sejam revisadas primeiro pelo mantenedor upstream e depois pelo mantenedor do pacote, e preferimos que esses dois atores sejam independentes entre si
Desta vez, um mantenedor upstream corrompido atacou esse processo, mas isso não significa que deveríamos eliminar os mantenedores upstream. Nos últimos anos, essa estrutura impediu várias tentativas de backdoor, e não é um processo que deva ser descartado sem uma análise cuidadosa
O caminho de melhoria continua sendo o mesmo de que temos falado: buscar mais builds reproduzíveis, reduzir a superfície de ataque e a complexidade de build quando possível, e confiar nos mantenedores, mas verificar o trabalho
Pelo contrário, eles ficaram confusos com esse ponto e estão adicionando documentação sobre como implementar datagramas simples sem a libsystemd
O número de instalações de liblzma e xz-utils provavelmente é muito maior que dezenas de milhões. Muitas linguagens, como Python, PHP e Ruby, dependem de libxml2, e a libxml2 usa liblzma. Há muitas outras dependências também
Considerações geopolíticas não são tarefa dos mantenedores. OSS é fornecido sem garantias
Além disso, é possível que “Jia Tan” fosse totalmente falso. Pelos timestamps dos commits, até no mesmo dia o fuso horário muda do Leste Europeu para a Ásia. No mínimo, é certo que havia um jogo de identidade acontecendo
Eu não sabia que a pessoa que descobriu esse problema era um engenheiro da Microsoft trabalhando no Azure Postgres
Obrigado, Microsoft; agora passei a gostar mais do Azure
Porque foi assim que esse problema foi descoberto
Depois, deveriam olhar para a biblioteca problemática e procurar outliers parecidos, em que uma persona falsa assume o controle de um projeto
Parece ser uma prática comum ignorar esse tipo de erro
Eu realmente não suporto esse tipo de enquadramento
Parece que o mantenedor original do xz passou a responsabilidade para Jia Tan sem tê-lo visto pessoalmente, ou pelo menos sem nem ter falado com ele por chamada
Fico me perguntando se é comum se comunicar apenas por e-mail ou GitHub
Depois deste caso, acho que alguns mantenedores de projetos open source vão ficar mais cautelosos
Eu mesmo já conversei só por texto, sem fazer ideia de quem era a pessoa real, e já assumi ou passei a manutenção de bibliotecas
Mas acho que, neste caso, concluir que “os mantenedores precisam ser mais cuidadosos” é completamente errado
A responsabilidade pelo que as pessoas puxam para dentro de seus projetos não é dos mantenedores, e sim de quem trabalha nesses projetos
Ou você confia no mantenedor, ou não confia; e, no momento em que começa a depender de uma biblioteca, você implicitamente concorda em continuar atualizando em quem está confiando
Milhões de empresas estão pegando carona no trabalho de desenvolvedores open source não remunerados
Então não surpreende que eles saiam e que problemas apareçam
Isso teria acrescentado que confiança nas intenções da pessoa?
Participei de uns seis projetos open source de portes variados, de 100 a 30 mil estrelas no GitHub, e nunca falei por chamada com ninguém; comunicação baseada em texto era o padrão
Mas conhecer a pessoa pessoalmente não necessariamente resolve o problema
Muito tempo atrás, trabalhei anonimamente em um projeto open source, cujo nome não quero revelar aqui. O programador líder tinha um co-mantenedor que parecia conhecê-lo bastante bem
Esse co-mantenedor continuava fazendo gaslighting comigo e com outros mantenedores posteriores, nos diminuindo e nos culpando por bugs minúsculos até nos fazer sair. Tirando os insultos, nem era como uma bronca educativa ao estilo Linus Torvalds
O mantenedor líder o incentivava porque concordava com o ponto técnico central das alegações dele
Anos depois, esse co-mantenedor tentou tomar o projeto de forma hostil, e as coisas não saíram como ele esperava. Pouco depois, várias correspondências privadas vieram a público, revelando que ele sempre quis aquilo e que o gaslighting contra os outros mantenedores fazia parte desse objetivo
Isso aconteceu mesmo os dois se conhecendo
Todo mundo acha que esse backdoor foi pego cedo, mas ele talvez já tenha cumprido seu objetivo
Especialmente se o alvo fossem desenvolvedores usando distribuições rolling release como Kali ou Debian
No começo da semana dei uma olhada no tráfego SSH, mas na época não dei muita importância
Claro, isso pode ser um falso positivo: https://www.nubi-network.com/news.php?id=21
O meme de que “Lasse Collin não atualizava o xz Utils com frequência ou rapidez suficiente” foi um erro
Não entendo por que o SSH usa xz
Ele precisa mesmo? Isso é realmente tão importante?
O OpenSSH puxou a libsystemd para oferecer notificações de inicialização, e a libsystemd puxou a liblzma. Normalmente, o código da liblzma não entra no OpenSSH
Mas, por ser compilado como dependência da libsystemd, o script de build é executado no mesmo ambiente da libsystemd e do OpenSSH
O payload do ataque estava escondido no diretório de testes da liblzma como um blob binário ofuscado, disfarçado de caso de teste de compressão
Ao compilar o lzma a partir do código-fonte no git e gerar os scripts de build com autotools, não havia nada suspeito. Mas, nos tarballs de código-fonte usados pelos empacotadores das distribuições, o autotools já havia sido executado, e o atacante substituiu a saída gerada automaticamente, difícil de ler, do script
Esse script verificava se a liblzma estava sendo compilada no mesmo ambiente que o OpenSSH e se estava sendo compilada para entrar em pacotes
.debou.rpm; se ambas as condições fossem verdadeiras, ele injetava o payload de ataque no OpenSSHDepois disso, o payload fazia várias verificações, como se o OpenSSH tinha sido iniciado normalmente por um script de init ou executado manualmente, e se havia ferramentas comuns de depuração; ele só se anexava ao processo em execução quando parecia um boot “natural”, sem ferramentas de depuração
Durante a execução, ele colocava um hook na verificação de chave privada e, se a chave privada correta tentasse fazer login, chamava o restante dos pacotes recebidos via
system, fornecendo execução remota de código com privilégios de root