Abusing Roles/ClusterRoles in Kubernetes
Last updated
Last updated
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aqui você pode encontrar algumas configurações potencialmente perigosas de Roles e ClusterRoles.
Lembre-se de que você pode obter todos os recursos suportados com kubectl api-resources
Refere-se à 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 impersonar outros usuários/grupos/SAs com melhores privilégios dentro do cluster kubernetes ou para nuvens externas
Ser capaz de criar/patch/exec 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 já que os tokens SAs são armazenados como segredos
Ser capaz de escapar para o nó a partir 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.
O coringa (*) concede 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.
No RBAC, certas permissões apresentam riscos significativos:
create
: Concede a capacidade de criar qualquer recurso de cluster, arriscando a escalada 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.
Um atacante com permissões para criar um pod pode anexar uma Conta de Serviço privilegiada ao pod e roubar o token para se passar pela Conta de Serviço. Isso efetivamente eleva os privilégios.
Exemplo de um pod que irá roubar o token da conta de serviço bootstrap-signer
e enviá-lo para o atacante:
O seguinte indica todos os privilégios que um contêiner pode ter:
Acesso privilegiado (desativando proteções e definindo capacidades)
Desativar namespaces hostIPC e hostPid que podem ajudar a escalar privilégios
Desativar o namespace hostNetwork, dando acesso para roubar privilégios de nuvem dos nós e melhor acesso às redes
Montar hosts / dentro do contêiner
Crie o pod com:
One-liner do este tweet e com algumas adições:
Agora que você pode escapar para o nó, verifique as técnicas de pós-exploração em:
Você provavelmente quer ser mais discreto, nas páginas seguintes você pode ver o que você seria capaz de acessar se criar um pod apenas habilitando alguns dos privilégios mencionados no template anterior:
Privileged + hostPID
Privileged only
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
Se você pode criar um pod (e opcionalmente uma conta de serviço) você pode ser capaz de obter privilégios no ambiente de nuvem ao atribuir funções de nuvem a um pod ou a uma conta de serviço e então acessá-lo. Além disso, se você pode criar um pod com o namespace de rede do host, você pode roubar o IAM da função da instância do nó.
Para mais informações, verifique:
Pod Escape PrivilegesÉ possível abusar dessas permissões para criar um novo pod e estabelecer privilégios como no exemplo anterior.
O seguinte yaml cria um daemonset e exfiltra o token da SA dentro do pod:
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 dentro.
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 (ab)usar o nó:
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 (webs?) dentro de um pod:
Como indicado nesta pesquisa, se você puder acessar ou criar um pod com o diretório /var/log/
do host montado nele, você pode escapar do contêiner.
Isso acontece basicamente porque, quando a Kube-API tenta obter os logs de um contêiner (usando kubectl logs <pod>
), ela 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 expõe 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 desse comportamento 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 symlink apontando para /etc/shadow
, por exemplo. Então, você poderá exfiltrar o arquivo shadow do host fazendo:
Se o atacante controla qualquer principal com as permissões para ler nodes/log
, ele pode simplesmente criar um symlink em /host-mounted/var/log/sym
para /
e ao acessar https://<gateway>:10250/logs/sym/
ele listará o sistema de arquivos root do host (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
Se você tiver sorte e a capacidade altamente privilegiada CAP_SYS_ADMIN
estiver disponível, você pode apenas remontar a pasta como rw:
Conforme declarado em esta pesquisa, é possível contornar a proteção:
Que tinha como objetivo prevenir escapes como os anteriores, ao invés de usar um hostPath mount, usar um PersistentVolume e um PersistentVolumeClaim para montar uma pasta do host no contêiner com acesso gravável:
Com um privilégio de imitação de usuário, um atacante poderia imitar uma conta privilegiada.
Basta usar o parâmetro --as=<username>
no comando kubectl
para imitar um usuário, ou --as-group=<group>
para imitar um grupo:
Ou use a API REST:
A permissão para listar segredos poderia permitir que um atacante realmente lesse os segredos acessando o endpoint da API REST:
Enquanto um atacante na 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. 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 por 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.
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 resourceName <signerNameDomain>/<signerNamePath>
ou <signerNameDomain>/*
Um exemplo de um papel com todas as permissões necessárias é:
Então, com o novo CSR do nó aprovado, você pode abusar das permissões especiais dos nós para roubar segredos e escalar privilégios.
No este post e neste aqui, a configuração do GKE K8s TLS Bootstrap é configurada com assinatura automática e é abusada para gerar credenciais de um novo nó K8s e, em seguida, abusar delas para escalar privilégios roubando segredos. Se você tiver os privilégios mencionados, poderá 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):
Os principais que podem modificar configmaps
no namespace kube-system em clusters EKS (precisam estar na AWS) podem obter privilégios de administrador do cluster ao sobrescrever o aws-auth configmap.
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 kubectl
funcionar, apenas 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 contatar a AWS.
Existem 2 maneiras de atribuir permissões K8s a principais do GCP. Em qualquer caso, o principal também precisa da permissão container.clusters.get
para poder coletar credenciais para acessar o cluster, ou você precisará gerar seu próprio arquivo de configuração kubectl (siga o próximo link).
Ao se comunicar com o endpoint da API K8s, o token de autenticação do GCP será enviado. Então, o GCP, através do endpoint da API K8s, primeiro verificará se o principal (por e-mail) tem algum acesso dentro do cluster, depois verificará se ele tem algum 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á fornecido.
Então, o primeiro método é usar GCP IAM, as permissões K8s têm suas permissões equivalentes do GCP IAM, e se o principal as tiver, poderá usá-las.
GCP - Container PrivescO segundo método é atribuir permissões K8s dentro do cluster identificando o usuário pelo seu e-mail (contas de serviço do GCP incluídas).
Principais que podem criar TokenRequests (serviceaccounts/token
) ao se comunicar com o endpoint da API K8s SAs (informações de aqui).
Principais que podem atualizar
ou patch
pods/ephemeralcontainers
podem ganhar execução de código em outros pods, e potencialmente sair para seu nó adicionando um contêiner efêmero com um securityContext privilegiado.
Principais 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.
Como você pode ler na próxima seção: Prevenção de Escalação de Privilégios Integrada, um principal não pode atualizar nem criar roles ou clusterroles sem ter ele mesmo essas novas permissões. Exceto se ele tiver o verbo escalate
sobre roles
ou clusterroles
.
Então ele pode atualizar/criar novas roles, clusterroles com melhores permissões do que as que possui.
Principais com acesso ao sub-recurso nodes/proxy
podem executar código em pods via a API Kubelet (de acordo com isso). Mais informações sobre autenticação Kubelet nesta página:
Você tem um exemplo de como obter RCE falando autorizado a uma API Kubelet aqui.
Principais que podem deletar pods (delete
verbo sobre pods
recurso), ou evictar pods (create
verbo sobre pods/eviction
recurso), ou mudar o status do pod (acesso a pods/status
) e podem tornar outros nós não agendáveis (acesso a nodes/status
) ou deletar nós (delete
verbo sobre nodes
recurso) 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.
Princípios 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 MiTM contra o cluster. A maioria das mitig ações para a CVE-2020-8554 apenas impede serviços ExternalIP (de acordo com isso).
Princípios com permissões de update
ou patch
sobre nodes/status
ou pods/status
, poderiam modificar rótulos para afetar as restrições de agendamento aplicadas.
Kubernetes possui um mecanismo integrado para prevenir a escal ação de privilégios.
Este sistema garante que os usuários não podem elevar seus privilégios modificando funções ou vinculações de funções. A aplicação desta regra ocorre no nível da API, fornecendo uma salvaguarda mesmo quando o autorizar 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 alinhar-se 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.
Há uma exceção à regra anterior. Se um princípio tem o verbo escalate
sobre roles
ou clusterroles
, ele pode aumentar os privilégios de funções e clusterroles mesmo sem ter as permissões ele mesmo.
Aparentemente, essa técnica funcionou antes, mas de acordo com meus testes, não está mais funcionando pela mesma razão explicada na seção anterior. Você não pode criar/modificar um rolebinding para dar a si mesmo ou a um SA diferente alguns privilégios se você não os tiver.
O privilégio de criar Rolebindings permite que um usuário vincule funções a uma conta de serviço. Esse privilégio pode potencialmente levar à escal ação de privilégios porque permite que o usuário vincule privilégios de administrador a uma conta de serviço comprometida.
Por padrão, não há nenhuma criptografia na comunicação entre pods. Autenticação mútua, bidirecional, pod a pod.
Crie seu .yaml
Edite seu .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/
Um controlador de admissão intercepta solicitações ao servidor API do Kubernetes antes da persistência do objeto, mas após a solicitação ser autenticada e autorizada.
Se um atacante conseguir de alguma forma injetar um Controlador de Admissão de Mutação, ele poderá modificar solicitações já autenticadas. Sendo capaz de potencialmente realizar privesc, e mais comumente persistir no cluster.
Exemplo de https://blog.rewanthtammana.com/creating-malicious-admission-controllers:
Verifique o status para ver se está pronto:
Então, implante um novo pod:
Quando você pode ver o erro ErrImagePull
, verifique o nome da imagem com uma das consultas:
Como você pode ver na imagem acima, tentamos executar a imagem nginx
, mas a imagem final executada é rewanthtammana/malicious-image
. O que acabou de acontecer!!?
O script ./deploy.sh
estabelece um controlador de admissão de webhook mutável, que modifica as 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 contêiner em cada pod por rewanthtammana/malicious-image
.
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 a desativação desse recurso de automontagem.
Como Aplicar: Defina automountServiceAccountToken: false
na configuração de contas de serviço ou pods a partir da versão 1.6 do Kubernetes.
Inclusão Seletiva: Certifique-se de que apenas os usuários necessários estejam incluídos em RoleBindings ou ClusterRoleBindings. Audite regularmente e remova usuários irrelevantes para manter a segurança rigorosa.
Papéis vs. ClusterRoles: Prefira usar Roles e RoleBindings para permissões específicas de namespace em vez de ClusterRoles e ClusterRoleBindings, que se aplicam em todo o cluster. Essa abordagem oferece um controle mais fino e limita o escopo das permissões.
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)