# GCP - Storage Privesc

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

## Storage

Informazioni di base:

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

### `storage.objects.get`

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

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

### `storage.objects.setIamPolicy`

Questa permissione può darti la possibilità 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 usando 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 funzionalità "interoperability" di Cloud Storage, pensata per **interazioni cross-cloud** come con AWS S3, prevede la **creazione di HMAC keys per Service Accounts e utenti**. Un attaccante può sfruttarla generando **un HMAC key per un Service Account con privilegi elevati**, elevando così i **privilegi all'interno di Cloud Storage**. Mentre le HMAC keys associate agli utenti sono recuperabili solo tramite la web console, sia le access key sia le secret key rimangono **permanentemente accessibili**, consentendo di conservarle come backup per l'accesso. Al contrario, le HMAC keys legate ai Service Account sono accessibili via API, ma le loro access e secret key non sono recuperabili dopo la creazione, aggiungendo un livello di complessità per un 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"storage-sa@{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 può essere trovato [qui](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 **creare un nuovo oggetto** all'interno di un bucket è necessario `storage.objects.create` e, secondo [la docs](https://cloud.google.com/storage/docs/access-control/iam-permissions#object_permissions), serve anche `storage.objects.delete` per **modificare** un oggetto esistente.

Una modalità di sfruttamento molto **comune** per i bucket scrivibili è quando il **bucket contiene file di un web server**: potresti essere in grado di **inserire nuovo codice** che verrà utilizzato dall'applicazione web.

### Composer

**Composer** è **Apache Airflow** gestito in GCP. Ha diverse caratteristiche interessanti:

- Gira all'interno di un **cluster GKE**, quindi la **SA che il cluster usa è accessibile** dal codice che gira in Composer
- Tutti i componenti di un ambiente Composer (**codice dei DAGs**, plugin e dati) sono memorizzati in un bucket GCP. Se un attaccante ha permessi di lettura e scrittura su di esso, potrebbe monitorare il bucket e **ogni volta che viene creato o aggiornato un DAG, caricare una versione backdoored** in modo che l'ambiente Composer recuperi dallo storage la versione backdoored.

**Puoi trovare una PoC di questo attacco nel 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 pushato nel bucket e poi il nuovo container viene costruito da quel codice. Pertanto, **sovrascrivendo il codice prima che la nuova versione venga costruita è possibile far eseguire codice arbitrario alla cloud function**.

**Puoi trovare una PoC di questo attacco nel 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 dentro un bucket con nome: `staging.<project-id>.appspot.com`. All'interno di questo bucket è possibile trovare una cartella chiamata `ae` che conterrà una cartella per ogni versione dell'app AppEngine e dentro queste cartelle si troverà il file `manifest.json`. Questo file contiene un json con tutti i file che devono essere usati per creare quella specifica versione. Inoltre, è possibile trovare i **nomi reali dei file, la URL a essi dentro il bucket GCP (i file nel bucket hanno cambiato nome con il loro sha1 hash) e l'hash sha1 di ciascun file.**

_Note che non è possibile effettuare un pre-takeover di questo bucket perché gli utenti GCP non sono autorizzati a generare bucket usando il dominio appspot.com._

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

L'attacco menzionato può essere eseguito in molti modi diversi; tutti iniziano monitorando 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 file **`manifest.json`** con il nuovo nome del bucket e gli sha1 hash dei file. Poi, quando viene creata una nuova versione nel bucket, basta modificare il `manifest.json` e caricare quello maligno.
- Caricare una versione modificata di **`requirements.txt`** che utilizzi dipendenze con codice maligno e aggiornare il `manifest.json` con il nuovo filename, URL e l'hash relativo.
- Caricare un **`main.py` o `app.yaml` modificato** che esegua il codice maligno e aggiornare il `manifest.json` con il nuovo filename, URL e l'hash relativo.

**Puoi trovare una PoC di questo attacco nel repo:** [**https://github.com/carlospolop/Monitor-Backdoor-AppEngine**](https://github.com/carlospolop/Monitor-Backdoor-AppEngine)

### GCR

- **Google Container Registry** memorizza le immagini dentro bucket; se puoi **scrivere in quei bucket** potresti essere in grado di **move laterally** verso 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 top level subdomains sono specificati [qui](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.

## **Riferimenti**

- [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}}
