Não pode ser contido: Encontrando uma vulnerabilidade de injeção de comando em Kubernetes
Comentários editoriais e adicionais por Tricia Howard
Resumo executivo
O pesquisador de segurança da Akamai, Tomer Peled, descobriu recentemente uma vulnerabilidade de alta gravidade em Kubernetes, que foi atribuída ao CVE-2023-3676 com uma pontuação CVSS de 8,8.
Essa descoberta levou à identificação de mais duas vulnerabilidades, pois compartilham a mesma causa raiz: chamada de função insegura e falta de sanitização de entrada do usuário.
A vulnerabilidade permite a execução remota de código com privilégios de SISTEMA em todos os pontos de extremidade do Windows em um cluster em Kubernetes. Para explorar essa vulnerabilidade, o invasor precisa aplicar um arquivo YAML mal-intencionado no cluster.
Essa vulnerabilidade pode ser explorada em instalações padrão de Kubernetes e foi testada em implantações locais e no Azure Kubernetes Service.
Fornecemos um arquivo YAML de prova de conceito, bem como uma regra OPA para bloquear essa vulnerabilidade.
Introdução
YAML (que significa YAML Ain't Markup Language) é uma linguagem de serialização de dados semelhante a JSON, usada principalmente em arquivos de configuração. Como tal, ela desempenha um papel importante em Kubernetes, o sistema de orquestração de contêineres recém-onipresente que ajuda as organizações a automatizar a implantação, o dimensionamento e o gerenciamento de aplicações em contêineres. A estrutura de Kubernetes usa arquivos YAML para basicamente tudo, desde a configuração da Interface de rede do contêiner até o gerenciamento do pod e até mesmo o manuseio secreto.
Arquivos YAML em Kubernetes foram os assuntos de pesquisas nos últimos anos. Considerando que Kubernetes depende do YAML para a configuração de cluster, esse tópico de pesquisa é particularmente interessante de se aprofundar.
Como YAML e Kubernetes foram explorados anteriormente?
Em 2022, o CVE-2022-1471 foi encontrado dentro do construtor de SnakeYAML, um analisador conhecido de arquivos YAML. A vulnerabilidade permitiu a criação de objetos não seguros, o que poderia levar à execução de código em aplicações vulneráveis que o utilizam. Outro exemplo que mostra o possível impacto dos arquivos YAML pode ser visto neste aviso de CVE sobre o CVE-2021-25749, escrito pela equipe de segurança de Kubernetes. Essa vulnerabilidade permite que os invasores contornem a verificação de quem tem permissão para executar como raiz, escrevendo incorretamente o nome no arquivo YAML.
Como parte de nossa pesquisa sobre Kubernetes, encontramos o CVE-2017-1002101 e o CVE-2021-25741. Essas vulnerabilidades demonstraram como os invasores podem usar condições de corrida e symlinks em conjunto com um subpropriedade subPath em um arquivo YAML para obter acesso a dados privilegiados fora do contêiner.
Essas vulnerabilidades anteriores nos inspiraram a seguir a direção do processamento de caminhos na base de código de Kubernetes, o que acabou levando à descoberta da vulnerabilidade que estamos discutindo hoje.
Nesta publicação do blog, demonstraremos como um invasor com privilégios de "aplicação", os privilégios necessários para interagir com API de Kubernetes, pode injetar código que será executado em máquinas Windows remotas com privilégios de SISTEMA.
Detalhes da vulnerabilidade
Quando um pod é criado, o usuário tem a opção de criar um diretório compartilhado entre o pod e o host. Esse recurso, chamado volumes, é útil, por exemplo, ao servir websites através de um contêiner em um pod. Podemos querer compartilhar os arquivos do website de um diretório compartilhado com o host; dessa forma, poderemos alterar o layout do website como gostaríamos e não precisaríamos recompilar uma imagem contendo o website toda vez.
A ativação de volumes é feita com a inclusão do parâmetro de volume no arquivo YAML do pod. Os locais para onde montar o volume estão listados no mountPath (o local no contêiner) e no hostPath (o local no host).
O mais importante para nós é quepodemos montar nosso diretório compartilhado ou arquivo em um local escolhido usando a subpropriedade subPath. Todas as propriedades relevantes para os volumes podem ser vistas na Figura 1.
A análise de nosso arquivo YAML é realizada pelo kubelet , um serviço central em Kubernetes que é responsável pela execução de aplicações em contêineres em um nó. Como parte do patch para o CVE-2021-25741, o kubelet valida todos os parâmetros no arquivo YAML e garante que nenhum symlink seja criado como resultado do uso do parâmetro subPath chamando a função interna "isLinkPath". A função é exibida na Figura 2.
A função toma como parâmetro o subPath fornecido pelo usuário no arquivo YAML. Em seguida, ela usa esse caminho para criar um comando PowerShell destinado a determinar o tipo de caminho (ou seja, se é um symlink ou não). O comando PowerShell formatado é então chamado imediatamente pelo "exec.Command", que é uma chamada de função.
A presença de "exec.Command" combinada com uma entrada não sanitizada fornecida pelo usuário, é fortemente indicada em uma oportunidade de injeção de comando.
O PowerShell permite que os usuários avaliem valores dentro das strings antes de serem usados. Isso pode ser feito adicionando $(<experssion_to_be_evaluated>) à sua string, por exemplo (Figura 3).
PS> echo “the value of 1+1 is $(1+1)
Output:
the value of 1+1 is 2
Fig. 3: Exemplo do PowerShell avaliando expressões dentro das strings
Este exemplo é muito simples, mas na verdade qualquer comando PowerShell pode ser inserido entre parênteses e será avaliado, como por exemplo, $(Start-Process cmd), $(Invoke-Expression exp) e outros itens do PowerShell.
Um invasor pode abusar dessa avaliação de subPath para alcançar o código vulnerável e executar qualquer comando com o qual deseja com privilégios do SISTEMA (contexto próprio do kubelet) dos nós remotose obter controle sobre todos os nós do Windows no cluster. A Figura 4 mostra um valor de subPath mal-intencionado.
Prova de conceito que mostra o CVE-2023-3676
A prova de conceito é simplesmente um arquivo YAML que contém a avaliação do comando PowerShell. Você pode encontrar esse arquivo, bem como um vídeo que mostra o terminal que está sendo iniciado, em nosso repositório do GitHub.
Este CVE levou à descoberta e correção de mais vulnerabilidades de injeção de comando. Eles receberam coletivamente os números CVE-2023-3955 e CVE-2023-3893.
Análise de patches
A equipe de Kubernetes optou por corrigir essa classe de vulnerabilidades passando os parâmetros das variáveis de ambiente em vez de pela entrada do usuário (Figura 5). Ao passar os valores dessa maneira, os parâmetros são tratados como strings, portanto, não serão avaliados como expressões pelo PowerShell.
Será que estou vulnerável?
Como mencionamos acima, todas as versões de Kubernetes abaixo de 1.28 estão vulneráveis a este CVE. Há vários métodos para determinar se um dos nós em seu cluster é um nó do Windows. Um método é executar o comando mostrado na Figura 6.
kubectl get nodes -o wide --show-labels | grep “os=windows” Saída: akswin000000 Ready agent 4d17h v1.26.6 agentpool=win,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=windows… akswin000001 Ready agent 4d17h v1.26.6 agentpool=win,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=windows… |
Fig. 6: Um comando kubectl para determinar se um dos nós em seu cluster é um nó do Windows
Mitigação
A aplicação de patches é a maneira mais confiável de se proteger contra essa vulnerabilidade. Nos casos em que a aplicação de patches não é uma opção, descrevemos várias formas potenciais de proteção contra essa vulnerabilidade, e você pode escolher a que melhor se adapta ao seu ambiente.
Soluções anteriores
Para o CVE-2023-3676, os administradores de Kubernetes podem desativar o uso do Volume.Subpath. Isso garantirá que seu cluster esteja seguro contra essa vulnerabilidade, mas desativará um mecanismo que às vezes é importante para clusters em produção.
OPA
Open Policy Agent (OPA) é um agente de código-fonte aberto que permite que os usuários recebam dados sobre o tráfego que entra e sai dos nós e tomem ações baseadas em políticas sobre os dados recebidos. O OPA usa a Rego como a linguagem para seu mecanismo, com a qual os administradores podem criar regras para impedir que determinados arquivos YAML sejam implementados. A Figura 7 ilustra uma regra que negará a criação de pods com um subPath mal-intencionado.
package kubernetes.admission
deny[msg] {
input.request.kind.kind == "Pod"
path := input.request.object.spec.containers.volumeMounts.subPath
not startswith(path, "$(")
msg := sprintf("malicious path: %v was found", [path])
}
Fig. 7: Uma regra que bloqueará a criação de pods com um subPath mal-intencionado
RBAC
O RBAC (Role-Based Access Control, controle de acesso baseado em função) é um método que segmenta as operações do usuário de acordo com quem ele é. Por exemplo, cada usuário só pode criar pods em seu próprio namespace ou pode exibir apenas informações para namespaces permitidos. Isso pode ajudar a limitar o número de usuários que podem executar ações em um cluster e ajudar a concentrar a atenção naqueles que têm os privilégios relevantes para a exploração.
Conclusão
O CVE-2023-3676 requer privilégios baixos e, portanto, define um nível baixo para os invasores: Tudo o que eles precisam ter é o acesso a um nó e aplicar privilégios. Como discutimos nesta publicação do blog, a exploração bem-sucedida dessa vulnerabilidade levará à execução remota de código em qualquer nó do Windows na máquina com privilégios de SISTEMA.
O alto impacto associado à facilidade de exploração geralmente significa que há uma maior chance de ver esse ataque (e ataques semelhantes) nas organizações. Na verdade, o único fator limitante com essa vulnerabilidade é seu escopo. Ele é restrito aos nós do Windows, que não são muito populares atualmente.
É importante que os administradores corrijam seus clusters de Kubernetes para a versão mais recente disponível para evitar a exploração dessas vulnerabilidades. Se a aplicação de patches não estiver disponível imediatamente, recomendamos que você use um dos métodos descritos acima para ajudar a se defender contra essa vulnerabilidade.
Queremos agradecer à equipe de Kubernetes por sua resposta muito rápida e boa comunicação.
Cronograma de divulgação
13/07/2023 – Vulnerabilidade divulgada à equipe de Kubernetes.
19/07/2023 – CVEs atribuídos pela equipe de Kubernetes
23/08/2023 – Kubernetes publicou correções de CVE
13/09/2023 – Postagem do blog publicada