Abusing Roles/ClusterRoles in Kubernetes
Aqui você pode encontrar algumas configurações de Funções e ClusterRoles potencialmente perigosas.
Lembre-se de que você pode obter todos os recursos suportados com kubectl api-resources
Escalação de Privilégios
Referindo-se como a arte de obter acesso a um principal diferente dentro do cluster com privilégios diferentes (dentro do cluster Kubernetes ou para nuvens externas) do que os que você já possui, no Kubernetes existem basicamente 4 técnicas principais para escalar privilégios:
Ser capaz de fazer-se passar por outros usuários/grupos/SAs com melhores privilégios dentro do cluster Kubernetes ou para nuvens externas
Ser capaz de criar/alterar/executar pods onde você pode encontrar ou anexar SAs com melhores privilégios dentro do cluster Kubernetes ou para nuvens externas
Ser capaz de ler segredos pois os tokens dos SAs são armazenados como segredos
Ser capaz de escapar para o nó de um contêiner, onde você pode roubar todos os segredos dos contêineres em execução no nó, as credenciais do nó e as permissões do nó dentro da nuvem em que está sendo executado (se houver)
Uma quinta técnica que merece menção é a capacidade de executar port-forward em um pod, pois você pode ser capaz de acessar recursos interessantes dentro desse pod.
Acessar Qualquer Recurso ou Verbo (Coringa)
O coringa (*) dá permissão sobre qualquer recurso com qualquer verbo. É usado por administradores. Dentro de um ClusterRole, isso significa que um atacante poderia abusar de qualquer namespace no cluster
Acessar Qualquer Recurso com um verbo específico
No RBAC, certas permissões representam riscos significativos:
create
: Concede a capacidade de criar qualquer recurso do cluster, arriscando escalonamento de privilégios.list
: Permite listar todos os recursos, potencialmente vazando dados sensíveis.get
: Permite acessar segredos de contas de serviço, representando uma ameaça à segurança.
Criar Pod - Roubar Token
Um atacante com permissões para criar um pod, poderia anexar uma Conta de Serviço privilegiada ao pod e roubar o token para se passar pela Conta de Serviço. Efetivamente escalando privilégios para ela.
Exemplo de um pod que irá roubar o token da conta de serviço bootstrap-signer
e enviá-lo para o atacante:
Criação e Escape de Pods
O seguinte indica todos os privilégios que um contêiner pode ter:
Acesso privilegiado (desabilitando proteções e definindo capacidades)
Desativar os namespaces hostIPC e hostPid que podem ajudar a escalar privilégios
Desativar o namespace hostNetwork, dando acesso para roubar privilégios da nuvem dos nós e melhor acesso às redes
Montar o / do host dentro do contêiner
Crie o pod com:
Uma linha de este tweet e com algumas adições:
Agora que você pode escapar para o nó, verifique as técnicas pós-exploração em:
Furtividade
Provavelmente você deseja ser mais furtivo, nas próximas páginas você pode ver o que seria capaz de acessar se criar um pod habilitando apenas alguns dos privilégios mencionados no modelo anterior:
Privileged + hostPID
Apenas privilegiado
hostPath
hostPID
hostNetwork
hostIPC
Você pode encontrar exemplos de como criar/abusar das configurações de pods privilegiados anteriores em https://github.com/BishopFox/badPods
Criar Pod - Mover para a nuvem
Se você pode criar um pod (e opcionalmente uma conta de serviço), talvez consiga obter privilégios no ambiente de nuvem ao atribuir funções de nuvem a um pod ou a uma conta de serviço e depois acessá-lo. Além disso, se você puder criar um pod com o namespace de rede do host, poderá roubar a função IAM da instância do nó.
Para mais informações, consulte:
pagePod Escape PrivilegesCriar/Patch Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs e Cronjobs
É possível abusar dessas permissões para criar um novo pod e estabelecer privilégios como no exemplo anterior.
O yaml a seguir cria um daemonset e exfiltra o token do SA dentro do pod:
Execução de Pods
pods/exec
é um recurso no Kubernetes usado para executar comandos em um shell dentro de um pod. Isso permite executar comandos dentro dos contêineres ou obter um shell interno.
Portanto, é possível entrar em um pod e roubar o token do SA, ou entrar em um pod privilegiado, escapar para o nó e roubar todos os tokens dos pods no nó e (abusar) do nó:
port-forward
Esta permissão permite encaminhar uma porta local para uma porta no pod especificado. Isso é destinado a facilitar a depuração de aplicativos em execução dentro de um pod, mas um atacante pode abusar disso para obter acesso a aplicativos interessantes (como bancos de dados) ou vulneráveis (sites?) dentro de um pod:
Escape de /var/log/ com Permissão de Escrita nos Hosts
Conforme indicado nesta pesquisa, se você puder acessar ou criar um pod com o diretório /var/log/
dos hosts montado nele, você pode escapar do contêiner.
Isso ocorre basicamente porque quando o Kube-API tenta obter os logs de um contêiner (usando kubectl logs <pod>
), ele solicita o arquivo 0.log
do pod usando o endpoint /logs/
do serviço Kubelet.
O serviço Kubelet expõe o endpoint /logs/
que basicamente está expondo o sistema de arquivos /var/log
do contêiner.
Portanto, um atacante com acesso para escrever na pasta /var/log/ do contêiner poderia abusar desses comportamentos de 2 maneiras:
Modificando o arquivo
0.log
de seu contêiner (geralmente localizado em/var/logs/pods/namespace_pod_uid/container/0.log
) para ser um link simbólico apontando para/etc/shadow
, por exemplo. Em seguida, você poderá exfiltrar o arquivo shadow dos hosts fazendo:
Se o atacante controlar qualquer principal com as permissões para ler
nodes/log
, ele pode simplesmente criar um symlink em/host-mounted/var/log/sym
para/
e quando acessarhttps://<gateway>:10250/logs/sym/
ele listará o sistema de arquivos raiz dos hosts (alterar o symlink pode fornecer acesso a arquivos).
Um laboratório e um exploit automatizado podem ser encontrados em https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts
Bypassing proteção readOnly
Se você tiver sorte e a capacidade altamente privilegiada CAP_SYS_ADMIN
estiver disponível, você pode simplesmente remontar a pasta como rw:
Bypassing hostPath readOnly protection
Conforme declarado nesta pesquisa, é possível contornar a proteção:
O que foi feito para evitar escapes como os anteriores foi, em vez de usar uma montagem hostPath, usar um PersistentVolume e um PersistentVolumeClaim para montar uma pasta do host no contêiner com acesso de gravação:
Impersonando contas privilegiadas
Com um privilégio de impersonação de usuário, um atacante poderia se passar por uma conta privilegiada.
Basta usar o parâmetro --as=<username>
no comando kubectl
para se passar por um usuário, ou --as-group=<group>
para se passar por um grupo:
Ou utilize a REST API:
Listagem de Segredos
A permissão para listar segredos poderia permitir que um atacante realmente leia os segredos acessando o endpoint da API REST:
Lendo um segredo - forçando IDs de token
Enquanto um atacante em posse de um token com permissões de leitura requer o nome exato do segredo para usá-lo, ao contrário do privilégio mais amplo de listar segredos, ainda existem vulnerabilidades. As contas de serviço padrão no sistema podem ser enumeradas, cada uma associada a um segredo. Esses segredos têm uma estrutura de nome: um prefixo estático seguido de um token alfanumérico aleatório de cinco caracteres (excluindo certos caracteres) de acordo com o código-fonte.
O token é gerado a partir de um conjunto limitado de 27 caracteres (bcdfghjklmnpqrstvwxz2456789
), em vez do intervalo alfanumérico completo. Essa limitação reduz o total de combinações possíveis para 14.348.907 (27^5). Consequentemente, um atacante poderia executar um ataque de força bruta para deduzir o token em questão de horas, potencialmente levando a uma escalada de privilégios ao acessar contas de serviço sensíveis.
Solicitações de Assinatura de Certificado
Se você tiver os verbos create
no recurso certificatesigningrequests
(ou pelo menos em certificatesigningrequests/nodeClient
). Você pode criar um novo CeSR de um novo nó.
De acordo com a documentação, é possível aprovar automaticamente essas solicitações, então, nesse caso, você não precisa de permissões extras. Caso contrário, você precisaria ser capaz de aprovar a solicitação, o que significa atualizar em certificatesigningrequests/approval
e approve
em signers
com o nome do recurso <signerNameDomain>/<signerNamePath>
ou <signerNameDomain>/*
Um exemplo de uma função com todas as permissões necessárias é:
Portanto, com a aprovação do CSR do novo nó, você pode abusar das permissões especiais dos nós para roubar segredos e escalar privilégios.
Nos este post e este outro, a configuração de inicialização do TLS do GKE K8s é configurada com assinatura automática e é abusada para gerar credenciais de um novo Nó K8s e então abusar deles para escalar privilégios roubando segredos. Se você tiver os privilégios mencionados, você poderia fazer a mesma coisa. Note que o primeiro exemplo contorna o erro que impede um novo nó de acessar segredos dentro de contêineres porque um nó só pode acessar os segredos dos contêineres montados nele.
A maneira de contornar isso é apenas criar credenciais de nó para o nome do nó onde o contêiner com os segredos interessantes está montado (mas apenas verifique como fazer isso no primeiro post):
Configmaps aws-auth do AWS EKS
Principais que podem modificar configmaps
no namespace kube-system em clusters EKS (precisam estar na AWS) podem obter privilégios de administrador do cluster sobrescrevendo o configmap aws-auth.
Os verbos necessários são update
e patch
, ou create
se o configmap não foi criado:
Você pode usar aws-auth
para persistência dando acesso a usuários de outras contas.
No entanto, aws --profile other_account eks update-kubeconfig --name <cluster-name>
não funciona de uma conta diferente. Mas na verdade aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing
funciona se você colocar o ARN do cluster em vez de apenas o nome.
Para fazer o kubectl
funcionar, certifique-se de configurar o kubeconfig da vítima e nos argumentos de execução da aws adicione --profile other_account_role
para que o kubectl use o perfil da outra conta para obter o token e entrar em contato com a AWS.
Escalando no GKE
Existem 2 maneiras de atribuir permissões K8s a princípios do GCP. Em qualquer caso, o princípio também precisa da permissão container.clusters.get
para poder obter credenciais para acessar o cluster, ou você precisará gerar seu próprio arquivo de configuração do kubectl (siga o próximo link).
Ao falar com o endpoint da API do K8s, o token de autenticação do GCP será enviado. Em seguida, o GCP, por meio do endpoint da API do K8s, primeiro verificará se o princípio (por e-mail) tem algum acesso dentro do cluster, e então verificará se ele tem qualquer acesso via GCP IAM. Se qualquer um desses for verdadeiro, ele será respondido. Se não, um erro sugerindo dar permissões via GCP IAM será dado.
Então, o primeiro método é usando GCP IAM, as permissões do K8s têm suas equivalentes permissões do GCP IAM, e se o princípio tiver, ele poderá usá-las.
pageGCP - Container PrivescO segundo método é atribuir permissões K8s dentro do cluster identificando o usuário pelo seu e-mail (incluídas as contas de serviço do GCP).
Criar token de serviceaccounts
Princípios que podem criar TokenRequests (serviceaccounts/token
) Ao falar com o endpoint da API do K8s SAs (informações de aqui).
ephemeralcontainers
Princípios que podem atualizar
ou patch
pods/ephemeralcontainers
podem obter execução de código em outros pods, e potencialmente escapar para seu nó adicionando um contêiner efêmero com um securityContext privilegiado.
ValidatingWebhookConfigurations ou MutatingWebhookConfigurations
Princípios com qualquer um dos verbos create
, update
ou patch
sobre validatingwebhookconfigurations
ou mutatingwebhookconfigurations
podem ser capazes de criar uma dessas webhookconfigurations para poder escalar privilégios.
Para um exemplo de mutatingwebhookconfigurations
confira esta seção deste post.
Escalar
Como você pode ler na próxima seção: Prevenção de Escalação de Privilégios Incorporada, um princípio não pode atualizar nem criar funções ou clusterroles sem ter essas novas permissões. Exceto se ele tiver o verbo escalate
sobre roles
ou clusterroles
.
Então ele pode atualizar/criar novas funções, clusterroles com melhores permissões do que as que ele tem.
Proxy de nós
Princípios com acesso ao sub-recurso nodes/proxy
podem executar código em pods via a API do Kubelet (de acordo com isto). Mais informações sobre autenticação do Kubelet nesta página:
Você tem um exemplo de como obter RCE falando autorizado a uma API do Kubelet aqui.
Excluir pods + nós não escalonáveis
Princípios que podem excluir pods (verbo delete
sobre o recurso pods
), ou expulsar pods (verbo create
sobre o recurso pods/eviction
), ou alterar o status do pod (acesso a pods/status
) e podem tornar outros nós não escalonáveis (acesso a nodes/status
) ou excluir nós (verbo delete
sobre o recurso nodes
) e têm controle sobre um pod, poderiam roubar pods de outros nós para que sejam executados no nó comprometido e o atacante possa roubar os tokens desses pods.
Status dos Serviços (CVE-2020-8554)
Principais que podem modificar services/status
podem definir o campo status.loadBalancer.ingress.ip
para explorar a CVE-2020-8554 não corrigida e lançar ataques de MiTM contra o cluster. A maioria das mitigações para a CVE-2020-8554 apenas previnem serviços ExternalIP (de acordo com este).
Status dos Nós e Pods
Principais com permissões de update
ou patch
sobre nodes/status
ou pods/status
, poderiam modificar rótulos para afetar as restrições de agendamento impostas.
Prevenção de Escalação de Privilégios Incorporada
O Kubernetes possui um mecanismo incorporado para prevenir a escalação de privilégios.
Esse sistema garante que os usuários não podem elevar seus privilégios modificando funções ou associações de funções. A aplicação dessa regra ocorre no nível da API, fornecendo uma proteção mesmo quando o autorizador RBAC está inativo.
A regra estipula que um usuário só pode criar ou atualizar uma função se possuir todas as permissões que a função compreende. Além disso, o escopo das permissões existentes do usuário deve estar alinhado com o da função que ele está tentando criar ou modificar: seja em todo o cluster para ClusterRoles ou restrito ao mesmo namespace (ou em todo o cluster) para Roles.
Existe uma exceção à regra anterior. Se um principal tem o verbo escalate
sobre roles
ou clusterroles
ele pode aumentar os privilégios de funções e clusterroles mesmo sem possuir as permissões ele mesmo.
Obter e Modificar RoleBindings/ClusterRoleBindings
Aparentemente essa técnica funcionava antes, mas de acordo com meus testes, não está mais funcionando pelo mesmo motivo explicado na seção anterior. Você não pode criar/modificar um rolebinding para conceder a si mesmo ou a um SA diferente alguns privilégios se você ainda não os tiver.
O privilégio de criar Rolebindings permite a um usuário associar funções a uma conta de serviço. Esse privilégio pode potencialmente levar a uma escalação de privilégios porque permite ao usuário associar privilégios de administrador a uma conta de serviço comprometida.
Outros Ataques
Aplicativo de Proxy Sidecar
Por padrão, não há nenhuma criptografia na comunicação entre pods. Autenticação mútua, de duas vias, pod a pod.
Criar um aplicativo de proxy sidecar
Crie seu .yaml
Edite seu arquivo .yaml e adicione as linhas descomentadas:
Veja os logs do proxy:
Mais informações em: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
Controlador de Admissão Malicioso
Um controlador de admissão intercepta solicitações ao servidor da API do Kubernetes antes da persistência do objeto, mas após a solicitação ser autenticada e autorizada.
Se um atacante de alguma forma conseguir injetar um Controlador de Admissão de Mutação, ele será capaz de modificar solicitações já autenticadas. Sendo capaz de potencialmente elevar privilégios e, mais comumente, persistir no cluster.
Exemplo de https://blog.rewanthtammana.com/creating-malicious-admission-controllers:
Verifique o status para ver se está pronto:
Em seguida, implante um novo pod:
Quando você vir o erro ErrImagePull
, verifique o nome da imagem com qualquer uma das consultas:
Como pode ver na imagem acima, tentamos executar a imagem nginx
, mas a imagem executada final foi rewanthtammana/malicious-image
. O que acabou de acontecer!!?
Aspectos Técnicos
O script ./deploy.sh
estabelece um controlador de admissão de webhook de mutação, que modifica solicitações para a API do Kubernetes conforme especificado em suas linhas de configuração, influenciando os resultados observados:
O trecho acima substitui a primeira imagem do container em todos os pods por rewanthtammana/malicious-image
.
Melhores Práticas
Desativar a Montagem Automática de Tokens de Conta de Serviço
Pods e Contas de Serviço: Por padrão, os pods montam um token de conta de serviço. Para aumentar a segurança, o Kubernetes permite desativar esse recurso de montagem automática.
Como Aplicar: Defina
automountServiceAccountToken: false
na configuração de contas de serviço ou pods a partir da versão 1.6 do Kubernetes.
Atribuição Restritiva de Usuário em RoleBindings/ClusterRoleBindings
Inclusão Seletiva: Garanta que apenas os usuários necessários sejam incluídos em RoleBindings ou ClusterRoleBindings. Audite regularmente e remova usuários irrelevantes para manter a segurança rigorosa.
Funções Específicas do Namespace em Vez de Funções em Toda a Cluster
Funções vs. ClusterRoles: Prefira usar Funções e RoleBindings para permissões específicas do namespace em vez de ClusterRoles e ClusterRoleBindings, que se aplicam a todo o cluster. Esse enfoque oferece um controle mais preciso e limita o escopo das permissões.
Utilize ferramentas automatizadas
Referências
Última actualización