Abusing Roles/ClusterRoles in Kubernetes
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ici, vous pouvez trouver certaines configurations de Roles et ClusterRoles potentiellement dangereuses.
N'oubliez pas que vous pouvez obtenir toutes les ressources prises en charge avec kubectl api-resources
Se référant à l'art d'obtenir l'accès à un principal différent au sein du cluster avec des privilèges différents (au sein du cluster kubernetes ou vers des clouds externes) de ceux que vous avez déjà, dans Kubernetes, il existe essentiellement 4 techniques principales pour escalader les privilèges :
Être capable de s'imposer à d'autres utilisateurs/groupes/SAs avec de meilleurs privilèges au sein du cluster kubernetes ou vers des clouds externes
Être capable de créer/patcher/exécuter des pods où vous pouvez trouver ou attacher des SAs avec de meilleurs privilèges au sein du cluster kubernetes ou vers des clouds externes
Être capable de lire des secrets car les tokens des SAs sont stockés en tant que secrets
Être capable de s'échapper vers le nœud depuis un conteneur, où vous pouvez voler tous les secrets des conteneurs s'exécutant dans le nœud, les identifiants du nœud et les permissions du nœud au sein du cloud dans lequel il s'exécute (le cas échéant)
Une cinquième technique qui mérite d'être mentionnée est la capacité de faire un port-forward dans un pod, car vous pourriez être en mesure d'accéder à des ressources intéressantes au sein de ce pod.
Le wildcard (*) 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 namespace dans le cluster.
Dans RBAC, certaines permissions présentent des risques significatifs :
create
: Accorde la capacité de créer n'importe quelle ressource de cluster, risquant une élévation de privilèges.
list
: Permet de lister toutes les ressources, pouvant potentiellement révéler des données sensibles.
get
: Permet d'accéder aux secrets des comptes de service, posant une menace pour la sécurité.
Un attaquant ayant les permissions de créer un pod pourrait attacher un compte de service privilégié dans le pod et voler le token pour usurper l'identité du compte de service. Élevant effectivement les privilèges.
Exemple d'un pod qui volera le token du compte de service bootstrap-signer
et l'enverra à l'attaquant :
Les éléments suivants indiquent tous les privilèges qu'un conteneur peut avoir :
Accès privilégié (désactivation des protections et définition des capacités)
Désactiver les namespaces hostIPC et hostPid qui peuvent aider à élever les privilèges
Désactiver le namespace hostNetwork, donnant accès pour voler les privilèges cloud des nœuds et un meilleur accès aux réseaux
Monter les hôtes / à l'intérieur du conteneur
Créez le pod avec :
One-liner de ce tweet et avec quelques ajouts :
Maintenant que vous pouvez échapper au nœud, consultez les techniques post-exploitation dans :
Vous voulez probablement être plus furtif, dans les pages suivantes, vous pouvez voir ce à quoi vous pourriez accéder si vous créez un pod en n'activant que certains des privilèges mentionnés dans le modèle précédent :
Privileged + hostPID
Privileged seulement
hostPath
hostPID
hostNetwork
hostIPC
Vous pouvez trouver un exemple de comment créer/abuser des configurations de pods privilégiés précédentes dans https://github.com/BishopFox/badPods
Si vous pouvez créer un pod (et éventuellement un compte de service), vous pourriez être en mesure de obtenir des privilèges dans l'environnement cloud en assignant des rôles cloud à un pod ou à un compte de service et ensuite y accéder. De plus, si vous pouvez créer un pod avec l'espace de noms réseau de l'hôte, vous pouvez voler le rôle IAM de l'instance nœud.
Pour plus d'informations, consultez :
Il est possible d'abuser de ces permissions pour créer un nouveau pod et établir des privilèges comme dans l'exemple précédent.
Le yaml suivant crée un daemonset et exfiltre le token du SA à l'intérieur du pod :
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 de lancer des commandes à l'intérieur des conteneurs ou d'obtenir un shell à l'intérieur.
Par conséquent, il est possible de rentrer dans un pod et voler le token du SA, ou d'entrer dans un pod privilégié, de s'échapper vers le nœud et de voler tous les tokens des pods dans le nœud et (ab)user du nœud :
Cette permission permet de transférer un port local vers un port dans le pod spécifié. Cela est destiné à faciliter le débogage des applications s'exécutant à l'intérieur d'un pod, mais un attaquant pourrait en abuser pour accéder à des applications intéressantes (comme des bases de données) ou vulnérables (webs ?) à l'intérieur d'un pod :
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.
C'est essentiellement parce que lorsque le Kube-API essaie d'obtenir les logs 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 avec accès en écriture dans le dossier /var/log/ du conteneur pourrait abuser de ce comportement 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 symlink pointant vers /etc/shadow
par exemple. Ensuite, vous pourrez exfiltrer le fichier shadow des hôtes en faisant :
Si l'attaquant contrôle un principal avec les permissions pour lire nodes/log
, il peut simplement créer un symlink dans /host-mounted/var/log/sym
vers /
et en accédant à https://<gateway>:10250/logs/sym/
, il listera le système de fichiers racine de l'hôte (changer le symlink peut fournir un accès à des fichiers).
Un laboratoire et un exploit automatisé peuvent être trouvés dans https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts
Si vous avez la chance et que la capacité hautement privilégiée CAP_SYS_ADMIN
est disponible, vous pouvez simplement remonter le dossier en rw :
Comme indiqué dans cette recherche, il est possible de contourner la protection :
Ce qui était censé prévenir les échappements comme les précédents en utilisant, au lieu d'un montage hostPath, un PersistentVolume et un PersistentVolumeClaim pour monter un dossier hôte dans le conteneur avec un accès en écriture :
Avec un privilège de l'imitation d'utilisateur, un attaquant pourrait imiter un compte privilégié.
Il suffit d'utiliser le paramètre --as=<username>
dans la commande kubectl
pour imiter un utilisateur, ou --as-group=<group>
pour imiter un groupe :
Ou utilisez l'API REST :
La permission de lister les secrets pourrait permettre à un attaquant de réellement lire les secrets en accédant au point de terminaison de l'API REST :
Bien qu'un attaquant en possession d'un jeton avec des permissions de lecture nécessite le nom exact du secret pour l'utiliser, contrairement au privilège plus large de lister les secrets, il existe néanmoins 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'exception 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 entraîner une élévation de privilèges en accédant à des comptes de service sensibles.
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 devrez être en mesure d'approuver la demande, ce qui signifie une mise à jour dans certificatesigningrequests/approval
et approve
dans signers
avec resourceName <signerNameDomain>/<signerNamePath>
ou <signerNameDomain>/*
Un exemple de rôle avec toutes les permissions requises est :
Donc, avec le nouveau CSR de nœud approuvé, vous pouvez abuser des permissions spéciales des nœuds pour voler des secrets et escalader des privilèges.
Dans cet article et celui-ci, la configuration de GKE K8s TLS Bootstrap est configurée avec signature automatique et elle est abusée pour générer des identifiants d'un nouveau nœud K8s et ensuite abuser de ceux-ci pour escalader des 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 parce qu'un nœud ne peut accéder qu'aux secrets des conteneurs montés sur lui.
La façon de contourner cela est simplement de créer des identifiants de nœud pour le nom du nœud où le conteneur avec les secrets intéressants est monté (mais vérifiez juste comment le faire dans le premier article) :
Les principaux qui peuvent modifier 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éé :
Vous pouvez utiliser aws-auth
pour la persistance en donnant accès à des 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 de juste le nom.
Pour faire fonctionner kubectl
, assurez-vous simplement de configurer le kubeconfig de la victime et dans les arguments d'exécution aws, ajoutez --profile other_account_role
afin que kubectl utilise le profil de l'autre compte pour obtenir le token et contacter AWS.
Il existe 2 façons d'assigner des permissions K8s aux principaux GCP. Dans tous les cas, le principal a également besoin de la permission container.clusters.get
pour pouvoir rassembler des informations d'identification pour accéder au cluster, sinon vous devrez générer votre propre fichier de configuration kubectl (suivez le lien suivant).
Lorsqu'il communique avec le point de terminaison API K8s, le token d'authentification GCP sera envoyé. Ensuite, GCP, via le point de terminaison 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 sera répondu. Sinon, une erreur suggérant de donner des permissions via GCP IAM sera donnée.
Ensuite, la première méthode consiste à utiliser GCP IAM, les permissions K8s ont leurs permissions GCP IAM équivalentes, et si le principal les a, il pourra les utiliser.
La deuxième méthode consiste à assigner des permissions K8s à l'intérieur du cluster en identifiant l'utilisateur par son e-mail (comptes de service GCP inclus).
Les principaux qui peuvent créer des TokenRequests (serviceaccounts/token
) lorsqu'ils communiquent avec le point de terminaison API K8s SAs (info de ici).
Les principaux qui peuvent update
ou patch
pods/ephemeralcontainers
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 securityContext privilégié.
Les principaux ayant 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.
Comme vous pouvez le lire dans la section suivante : Prévention intégrée de l'escalade de privilèges, un principal ne peut ni mettre à jour ni créer des rôles ou des clusterroles sans avoir lui-même ces nouvelles permissions. Sauf s'il a le verbe escalate
sur roles
ou clusterroles
.
Alors il peut mettre à jour/créer de nouveaux rôles, clusterroles avec de meilleures permissions que celles qu'il a.
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 :
Vous avez un exemple de comment obtenir RCE en parlant autorisé à une API Kubelet ici.
Les principaux qui peuvent supprimer des pods (verbe delete
sur la ressource pods
), ou expulser des pods (verbe create
sur la ressource pods/eviction
), ou changer le statut des pods (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 afin qu'ils soient exécutés dans le nœud compromis et que l'attaquant puisse voler les tokens de ces pods.
Les principaux qui peuvent modifier services/status
peuvent définir le champ status.loadBalancer.ingress.ip
pour exploiter le CVE-2020-8554 non corrigé et lancer des attaques MiTM contre le cluster. La plupart des atténuations pour le CVE-2020-8554 ne préviennent que les services ExternalIP (selon ceci).
Les principaux ayant des permissions update
ou patch
sur nodes/status
ou pods/status
pourraient modifier des étiquettes pour affecter les contraintes de planification appliquées.
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, fournissant une protection même lorsque l'autorisation RBAC est inactive.
La règle stipule qu'un utilisateur ne peut créer ou mettre à jour un rôle que s'il possède toutes les permissions que le rôle comprend. De plus, la portée des permissions 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 existe 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 permissions lui-même.
Apparemment, cette technique a fonctionné 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 donner ou donner à un autre SA 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 conduire à une escalade de privilèges car il permet à l'utilisateur de lier des privilèges d'administrateur à un compte de service compromis.
Par défaut, il n'y a pas de cryptage dans la communication entre les pods. Authentification mutuelle, bidirectionnelle, pod à pod.
Créez votre .yaml
Modifiez votre .yaml et ajoutez les lignes décommentées :
Voir les journaux du proxy :
Plus d'infos sur : https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
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 a été 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. Cela peut potentiellement permettre une élévation de privilèges, et plus généralement persister dans le cluster.
Exemple de https://blog.rewanthtammana.com/creating-malicious-admission-controllers :
Vérifiez l'état pour voir s'il est prêt :
Ensuite, déployez un nouveau pod :
Lorsque vous voyez l'erreur ErrImagePull
, vérifiez le nom de l'image avec l'une des requêtes suivantes :
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 finale est rewanthtammana/malicious-image
. Que s'est-il passé !!?
Le script ./deploy.sh
établit un contrôleur d'admission de webhook mutateur, qui modifie les requêtes à l'API Kubernetes comme spécifié dans ses lignes de configuration, influençant les résultats observés :
Le snippet ci-dessus remplace la première image de conteneur dans chaque pod par rewanthtammana/malicious-image
.
Pods et Comptes de Service : Par défaut, les pods montent un jeton de compte de service. Pour améliorer la sécurité, Kubernetes permet de désactiver cette fonctionnalité d'automontage.
Comment Appliquer : Définissez automountServiceAccountToken: false
dans la configuration des comptes de service ou des pods à partir de la version 1.6 de Kubernetes.
Inclusion Sélective : Assurez-vous que seuls les utilisateurs nécessaires sont inclus dans les RoleBindings ou ClusterRoleBindings. Auditez régulièrement et retirez les utilisateurs non pertinents pour maintenir une sécurité stricte.
Rôles vs. ClusterRoles : Préférez utiliser des Rôles et des RoleBindings pour des permissions spécifiques aux namespaces plutôt que des ClusterRoles et des ClusterRoleBindings, qui s'appliquent à l'échelle du cluster. Cette approche offre un meilleur contrôle et limite la portée des permissions.
Apprenez et pratiquez le Hacking AWS :HackTricks Training AWS Red Team Expert (ARTE) Apprenez et pratiquez le Hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)