Abusing Roles/ClusterRoles in Kubernetes
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
Accéder à n'importe quelle ressource avec un verbe spécifique
En RBAC, certaines autorisations présentent des risques importants :
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, potentiellement en train de divulguer des données sensibles.get
: Autorise l'accès aux secrets des comptes de service, posant une menace pour la sécurité.
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 :
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
Créez le pod avec :
Une ligne de ce tweet avec quelques ajouts :
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 PrivilegesCré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 :
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:
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 :
É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 :
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).
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:
Contournement de la protection en lecture seule de hostPath
Comme indiqué dans cette recherche, il est possible de contourner la protection :
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 :
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 :
Ou utilisez l'API REST :
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 :
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 :
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):
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éé:
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 PrivescLa 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 :
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.
É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
Modifiez votre fichier .yaml et ajoutez les lignes commentées :
Consultez les journaux du 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:
Vérifiez le statut 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 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:
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
Dernière mise à jour