Introduction
Cet article fait suite au premier chapitre qui traitait des méthodes d’élévation de privilèges dans AWS suivant la compromission d’une instance EC2 (https://www.xmco.fr/audit-fr-fr/welcome-to-the-cloud-partie-1-aws/).
Pour ce deuxième chapitre sur les méthodes de reconnaissance sur les machines virtuelles en environnements cloud, nous nous intéresserons à GCP (Google Cloud Platform) et plus particulièrement à Compute Engine.
GCP et le Compute Engine
Au sein du CSP GCP, les instances de calcul « standards » sont les VM de Compute Engine.
Pour rappel, une instance de VM de Compute Engine est un serveur virtuel hébergé au sein des infrastructures de GCP. Ces dernières sont instanciées dans une zone (emplacement logique dans une région GCP comme Belgique (europe-west-1) ou Iowa (us-central1-c)) spécifiée à la création.
Lors du déploiement d’une nouvelle VM, seuls les paramètres suivants sont nécessaires si un sous-réseau est configuré dans la région de la zone sélectionnée :
- un nom pour la VM ;
- une zone parmi les 112 disponibles (à l’heure de l’écriture de cet article).
À partir de ces informations, GCP déploiera automatiquement une VM de type « n1-standard-1 » avec une image Debian au sein du VPC par défaut.
Élévation de privilèges 101
Cette section, à l’instar du précédent billet de blog, mettra en avant les différentes méthodes pouvant être utilisées une fois l’accès à une VM acquis. Ces techniques d’élévations de privilèges porteront uniquement sur les particularités apportées par les environnements cloud et non sur celles apportées par les différents OS pouvant être déployés.
Metadata
Les environnements cloud de par leur nature comportent de nombreuses similitudes. Et quel que soit le CSP utilisé, certains concepts fondamentaux se retrouvent. Le 1er exemple est celui des metadata. En effet, les instances de calcul (et les services cloud de manière plus générale) ont besoin d’obtenir des informations leur permettant d’avoir un certain contexte dans le cloud. C’est notamment à cette fin que les metadata sont utilisées par les VM.
Ces dernières sont exposées au travers d’un service HTTP spécifique accessible au travers de l’adresse IP caractéristique 169.254.169.254 (ou via le nom de domaine « metadata.google.internal »).
Toutefois, à la différence d’AWS qui permet à ses utilisateurs d’avoir un service de metadata accessible en 2 versions (la première étant facilement exploitable au travers des vulnérabilités de type SSRF, la seconde offrant une meilleure protection), GCP ne propose qu’une seule version du service qui, par défaut, nécessite un en-tête HTTP spécifique (Metadata-Flavor). Cette implémentation rend donc plus difficiles les exploitations des vulnérabilités de type SSRF sur GCP.
Ces metadata comportent de nombreuses informations classées par catégorie. Par exemple :
- /project : informations sur le projet GCP où se situe la VM;
- /instance/attributes : informations sur les attributs de l’instance (clés SSH, scripts de démarrage, etc.);
- /instance/scheduling : informations sur les planifications liées à l’instance (maintenance, redémarrage, etc.) ;
- /instance/tags : informations sur les tags de l’instance.
Service Account
Afin d’accéder aux différents services au sein de GCP, l’instance doit être capable de communiquer avec ces derniers. Et afin de vérifier les autorisations, un mécanisme commun doit être utilisé. C’est à cet effet que les comptes de service sont utilisés.
La gestion des accès au sein de GCP se fait à l’aide du mécanisme RBAC (« Role Based Access Control »). À l’instar de la gestion chez AWS, l’utilisation des rôles est au cœur de ce système. Ces rôles ont un certain nombre de permissions positionnées sur un périmètre défini.
Obtenir l’accès à un compte de service permet donc d’obtenir un accès à un certain nombre d’actions, telles que la lecture de données en base de données, la suppression de buckets, etc. Ces droits sont définis par le rôle associé au compte de service au sein de GCP.
Pour utiliser ce compte de service, l’instance passe donc par le service de metadata afin de récupérer des identifiants de connexion temporaires. Or, si l’instance est capable de le faire, un attaquant ayant compromis l’instance est également en moyen de le faire.
Une fois ces informations récupérées, ces dernières peuvent être réutilisées de la manière suivante :
Note : En plus des metadata, les éléments suivants peuvent être recherchés sur une instance afin d’identifier des informations de connexion :
- Code source applicatif;
- Variables d’environnement (GOOGLE_APPLICATION_CREDENTIALS);
- Fichiers de configuration (ex. : ~/.config/gcloud, C:\Users\<USERNAME>\AppData\Roaming\gcloud, etc.).
Une autre spécificité propre à GCP est l’utilisation de comptes de service « par défaut ». En effet, en créant une instance sans spécifier de compte de service, GCP va automatiquement utiliser le compte de service PROJECT_NUMBER-compute@developer.gserviceaccount.com qui possède des droits très élevés dus au rôle prédéfini Editeur (qui permet d’accéder en lecture et en écriture à un grand nombre de services, à l’exception notable d’IAM).
Toutefois, ce comportement est limité par la mise en place d’une sécurité propre à GCP qui permet de restreindre les permissions d’un compte de service en définissant des périmètres (scope). Ces périmètres sont liés aux API Cloud (i.e. les services GCP) et permettent de définir différents niveaux d’accès:
- Accès par défaut (accès en lecture seule à Storage et Service Management, accès en écriture à Stackdriver Logging et Monitoring ainsi qu’accès en lecture et écriture sur Service Control) ;
- Accès complet à toutes les API Cloud (permissions égales à celles du rôle associé au compte de service) ;
- Accès personnalisés (différents niveaux peuvent être définis pour chaque API Cloud, généralement activé, désactivé, lecture seule, lecture et écriture).
Ainsi, par défaut, bien que le compte de service associé à l’instance soit très privilégié, ses permissions peuvent dans les faits se voir très limitées. Il est toutefois à noter qu’avec les accès par défaut, l’API Storage est accessible en lecture, représentant un risque pour la confidentialité des données stockées au sein du projet GCP.
Ces scopes peuvent être récupérées de la manière suivante :
Afin d’identifier les permissions liées à un compte de service, il est possible d’utiliser la méthode projects.testIamPermissions comme mentionné au sein de l’article suivant: https://hackingthe.cloud/gcp/enumeration/enumerate_service_account_permissions/
Une fois les permissions identifiées, les mêmes questions que celles mises en avant au sein du premier article de cette série peuvent être posées.
La section dédiée au Cloud du blog HackTricks possède également une page recensant les élévations de privilèges les plus connues au sein de GCP (cf. https://cloud.hacktricks.xyz/pentesting-cloud/gcp-security/gcp-privilege-escalation).
Startup script
Au travers du service de metadata, il est également possible de récupérer les startup scripts. Ces scripts contiennent des commandes qui sont exécutées avec l’utilisateur root au démarrage de l’instance et permettent d’assurer différentes automatisations de tâches. Ces derniers peuvent être passés directement à la machine en ligne de commande, via la console ou être stockés sur un Cloud Storage (notamment si leur taille dépasse 256 kB).
Différents types de scripts peuvent être trouvés en fonction de l’OS de l’instance:
- Script bash pour Linux ;
- Script non bash (commençant par un shebang avec l’interpréteur à utiliser) pour Linux ;
- Script Command shell (.cmd), Powershell (.ps1) ou batch (.bat) pour Windows.
Ces scripts sont accessibles de la manière suivante:
Au sein de ces startup script, il est possible d’identifier des informations intéressantes telles que:
- Des mots de passe / secrets applicatifs;
- Des mots de passe / secrets système;
- Des informations sur les droits du copte de service en cas d’action avec la CLI GCP;
- Des détails sur la configuration du système et des applicatifs.
Enfin, bien que cela sorte du contexte direct de la compromission d’une VM, un point intéressant à noter est que le résultat des commandes exécutées au sein des startup scripts est identifiable au travers des logs de la console série (serial console):
La permission compute.instances.getSerialPortOutput est toutefois nécessaire pour pouvoir consulter ces logs.
Guests attributes
Une autre particularité du service de metadata de GCP est la possibilité d’enregistrer des paires clé/valeurs appelées guest attributes.
Ces valeurs peuvent être lues et modifiées par n’importe quel utilisateur ou application de la VM et ce, sans droits spécifiques. Toutefois, pour lire ces valeurs en dehors de la VM, la permission compute.instances.getGuestAttributes est nécessaire.
Note : Ces attributs spécifiques doivent être activés pour pouvoir être utilisés (clé enable-guest-attributes à TRUE au sein de la configuration des metadata).
Déplacement latéral
De la même manière que décrite au sein de l’article précédent, les fonctionnalités réseau peuvent représenter un puissant levier pour se déplacer latéralement sur une infrastructure cloud.
Afin de scanner le réseau de la manière la plus efficace possible, il peut être intéressant de regarder les informations réseau contenues au sein des metadata de l’instance, notamment dans la catégorie network-interfaces. On pourra trouver au sein de cette dernière des informations allant du nom du réseau aux serveurs DNS en passant par le masque de sous-réseau.
Le prochain article de cette série se concentrera sur les machines virtuelles (VM) d’Azure.
Cheatsheet
Action | Commande |
Accès au service de metadata | curl -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/ ou Invoke-RestMethod -Headers @{'Metadata-Flavor' = 'Google'} -Uri"http://metadata.google.internal/computeMetadata/v1/" |
Récupérer le nom du compte de service | curl -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/" |
Récupérer le scope du compte de service par défaut | curl -H "Metadata-Flavor:Google" http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/scopes |
Récupérer le bearer token du compte de service par défaut | curl -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" | jq ".access_token" |
Récupérer les startup scripts | curl -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/attributes/startup-script" |
Récupérer les guests attributes | curl -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/guest-attributes/<NAMESPACE>/<KEY>" |
Écrire sur les guests attributes | curl -X PUT --data "<DATA>" -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/guest-attributes/<NAMESPACE>/<KEY>" |
Récupérer les informations liées aux cartes réseau | curl -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/ |
Bibliographie
- https://about.gitlab.com/blog/2020/02/12/plundering-gcp-escalating-privileges-in-google-cloud-platform/
- https://hackingthe.cloud/gcp/enumeration/enumerate_service_account_permissions/
- https://cloud.hacktricks.xyz/pentesting-cloud/gcp-security
- https://cloud.google.com/compute/docs/metadata/overview
- https://cloud.google.com/compute/docs/metadata/manage-guest-attributes
- https://cloud.google.com/compute/docs/access/service-accounts
- https://cloud.google.com/compute/docs/access/create-enable-service-accounts-for-instances
- https://cloud.google.com/compute/docs/instances/startup-scripts/linux
- https://cloud.google.com/compute/docs/instances/startup-scripts/windows