A vulnerabilidade “Dirty Pipe” do Linux e suas aplicações em contêineres (CVE-2022-0847)
9 de março de 2022
0 minutos de leituraO que é a vulnerabilidade “Dirty Pipe”? (CVE-2022-0847)
Recentemente, CVE-2022-0847 foi criada para descrever uma falha no kernel do Linux que pode ser explorada para permitir que qualquer processo modifique arquivos, independentemente das permissões ou da propriedade. A comunidade de segurança deu à vulnerabilidade o nome “Dirty Pipe” por sua semelhança com a “Dirty COW”, uma vulnerabilidade de escalonamento de privilégios relatada em CVE-2016-5195, e porque a falha está na implementação do pipeline do kernel. Há várias referências a essa vulnerabilidade documentadas no banco de dados de vulnerabilidades Snyk Intel, caso você queira se aprofundar.
Neste artigo, vamos falar sobre os riscos aos quais suas cargas de trabalho em contêineres estão expostas e analisar em detalhes como o conteúdo de imagens de contêineres e outros arquivos normalmente somente leitura pode ser modificado por um agente mal-intencionado, independentemente do UID e das permissões do sistema de arquivos.
Para começar, veja o que você pode fazer agora para proteger seus sistemas contra a Dirty Pipe.
Em resumo: atualize seus hosts Linux
A única correção conhecida para essa vulnerabilidade é atualizar seus hosts Linux para uma das seguintes versões do kernel:
5.16.11
5.15.25
5.10.102
Não há outras opções de mitigação capazes de proteger seus sistemas caso um agente mal-intencionado consiga acesso ao seu ambiente.
Como a Dirty Pipe afeta suas imagens de contêineres
Noções básicas sobre imagens de contêineres

Uma imagem de contêiner é basicamente formada por um conjunto de camadas sobrepostas. Quando um contêiner é iniciado, o mecanismo de execução (Docker, containerD, cri-O etc.) combina essas camadas e apresenta o resultado agregado ao processo como sistema de arquivos. Essas camadas são sempre somente leitura, e qualquer alteração é feita em uma camada de leitura e gravação, criada especificamente para cada instância do contêiner seguindo o padrão copy-on-write (COW). Essa camada de leitura e gravação é temporária e é destruída quando o contêiner é removido do sistema. Também é possível omitir essa camada iniciando o contêiner no modo somente leitura, tornando-o efetivamente imutável.
É comum recomendar que os processos dos contêineres sejam executados como usuários sem privilégios e que os sistemas de arquivos raiz sejam somente leitura. Essas medidas dificultam muito que um agente mal-intencionado explore vulnerabilidades da aplicação para ampliar o ataque, pois tornam muito mais difícil incluir código ou scripts próprios no sistema de arquivos do contêiner. Confira nosso guia de segurança para contêineres para conhecer outras práticas recomendadas.
Explorando a Dirty Pipe em um contêiner
Os detalhes técnicos de como a vulnerabilidade Dirty Pipe funciona estão fora do escopo deste artigo — consulte o artigo original sobre a descoberta para ver todos os detalhes —, mas, em linhas gerais, é possível executar uma sequência relativamente simples de etapas para alterar o conteúdo de praticamente qualquer arquivo, mesmo que suas permissões e/ou configurações de propriedade impeçam esse tipo de ação. Por exemplo, usando o código de prova de conceito write_anything do artigo mencionado acima, vamos criar uma imagem com este Dockerfile:

Em seguida, executamos o contêiner no modo somente leitura e usamos o executável write_anything para alterar /etc/passwd.

Eu não deveria ter conseguido fazer isso, porque o arquivo é somente leitura, pertence ao root e está em um sistema de arquivos raiz somente leitura.
Agora, vamos encerrar e remover esse contêiner, iniciar outro e verificar o arquivo /etc/passwd no novo contêiner.

A alteração no arquivo persistiu porque o conteúdo real da camada da imagem, que é somente leitura no sistema host, foi modificado pelo processo do contêiner anterior. Essa alteração permanecerá nesse host até que a imagem seja removida e/ou substituída.
Camada de imagem de baixo nível antes de executar o exploit

Camada de imagem de baixo nível depois de executar o exploit

Na verdade, se você tiver vários contêineres em execução no mesmo host, uma alteração como essa poderá ser vista imediatamente por qualquer contêiner que compartilhe essa camada base da imagem (com exceção daqueles que já tenham modificado o mesmo arquivo em sua própria camada de leitura e gravação).
Três contêineres monitorando seus arquivos /etc/passwd com watch enquanto um quarto contêiner executa o exploit write_anywhere.

A Dirty Pipe coloca em risco todos os volumes montados do host

Como você talvez já saiba, montar volumes do host (também chamados de bind mounts) nos seus contêineres nunca é uma boa ideia. Em condições normais, essa recomendação existe porque uma configuração incorreta simples pode conceder ao contêiner acesso não intencional para modificar arquivos no host. A Dirty Pipe agrava o problema: volumes montados do host ficam vulneráveis a esse exploit mesmo quando são montados com a flag :ro.

Escalonamento de privilégios com a Dirty Pipe
Um dos exemplos de prova de conceito do exploit que está circulando usa essa falha para obter privilégios elevados: modifica um binário existente com o bit suid habilitado para contornar as proteções normais contra esse tipo de ação. Isso não é um problema exclusivo de contêineres, mas o exploit pode ser usado dentro deles. Por exemplo, em tese, um invasor poderia explorar uma vulnerabilidade de execução remota de código (RCE) em uma aplicação e injetar esse código de prova de conceito para obter acesso root ao contêiner. Na prática, isso contorna as configurações do contêiner e/ou do Kubernetes que limitam esse comportamento.
Há medidas de mitigação?
Como mencionamos acima, atualizar os sistemas host é a única forma conhecida de proteger seus sistemas contra essa vulnerabilidade. As medidas de mitigação dos mecanismos de contêineres e do Kubernetes operam em um nível alto demais para oferecer muita proteção contra um exploit no nível do kernel como esse.
Não basta atualizar nossas imagens base?
Infelizmente, não. A falha não está no sistema de arquivos das imagens base, mas no kernel dos servidores host, compartilhado por todos os contêineres em execução. Você pode confirmar isso executando uname -a em vários contêineres com imagens base diferentes: todos informarão a versão do kernel do host.

E as configurações SecurityContext do Kubernetes?
As configurações SecurityContext do Kubernetes, como readonlyRootFilesystem:true, runAsNonRoot:true, runAsUser: e AllowPrivilegeEscalation:false, são ineficazes porque qualquer usuário pode explorar essa vulnerabilidade e contornar essas configurações.
Isso não significa que você deva deixar de usar essas configurações. Pelo contrário: elas são ótimos exemplos de defesa em profundidade e protegem seus clusters contra muitos outros tipos de ataque.
Na verdade, temos um guia rápido de segurança do Kubernetes que explica as configurações SecurityContext e por que você deve usá-las para reforçar a segurança das implantações das suas aplicações no Kubernetes. Você também pode verificar seus manifestos do Kubernetes com as ferramentas gratuitas de análise de IaC da Snyk para encontrar e corrigir configurações incorretas como essas. Acesse o link abaixo para começar a usar hoje mesmo.
Conclusão
Se ainda não fez isso, atualize seus hosts imediatamente. Se algum dos tópicos acima despertou seu interesse, confira os links a seguir para se aprofundar.
Blog da CM4All: Artigo sobre a descoberta da vulnerabilidade Dirty Pipe
Blog da Snyk: Entenda os detalhes da criação de imagens, das camadas e da análise de vulnerabilidades em contêineres
Guia rápido da Snyk: 10 configurações de SecurityContext do Kubernetes que você precisa conhecer
ArsTechnica: O Linux foi atingido por sua vulnerabilidade mais grave em anos
Proteja a infraestrutura desde a origem
A Snyk automatiza a segurança e a conformidade de IaC nos fluxos de trabalho e detecta recursos com configurações divergentes ou ausentes.
