# GCP - AppEngine Privesc

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

## App Engine

Per maggiori informazioni su App Engine consulta:

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

### `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`

Questi sono i permessi necessari per **distribuire un'App usando la CLI `gcloud`**. Forse i permessi **`get`** e **`list`** potrebbero essere **evitati**.

Puoi trovare esempi di codice Python in [https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/appengine](https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/appengine)

Per default, il nome del servizio App sarà **`default`**, e può esistere solo 1 istanza con lo stesso nome.\
Per cambiarlo e creare una seconda App, in **`app.yaml`**, modifica il valore della chiave radice con qualcosa come **`service: my-second-app`**

<details>
<summary>Distribuire un'applicazione App Engine</summary>
```bash
cd python-docs-samples/appengine/flexible/hello_world
gcloud app deploy #Upload and start application inside the folder
```
</details>

Concedi almeno 10–15 minuti; se non funziona richiamo **deploy another of times** e attendi qualche minuto.

> [!NOTE]
> **È possibile indicare il Service Account da usare** ma, per impostazione predefinita, viene usato il Service Account predefinito di App Engine.

L'URL dell'applicazione è del tipo `https://<proj-name>.oa.r.appspot.com/` o `https://<service_name>-dot-<proj-name>.oa.r.appspot.com`

### Aggiorna permessi equivalenti

Potresti avere permessi sufficienti per aggiornare un AppEngine ma non per crearne uno nuovo. In tal caso ecco come potresti aggiornare l'App Engine corrente:

<details>
<summary>Aggiorna l'applicazione App Engine esistente</summary>
```bash
# Find the code of the App Engine in the buckets
gsutil ls

# Download code
mkdir /tmp/appengine2
cd /tmp/appengine2
## In this case it was found in this custom bucket but you could also use the
## buckets generated when the App Engine is created
gsutil cp gs://appengine-lab-1-gcp-labs-4t04m0i6-3a97003354979ef6/labs_appengine_1_premissions_privesc.zip .
unzip labs_appengine_1_premissions_privesc.zip

## Now modify the code..

## If you don't have an app.yaml, create one like:
cat >> app.yaml <<EOF
runtime: python312

entrypoint: gunicorn -b :\$PORT main:app

env_variables:
A_VARIABLE: "value"
EOF

# Deploy the changes
gcloud app deploy

# Update the SA if you need it (and if you have actas permissions)
gcloud app update --service-account=<sa>@$PROJECT_ID.iam.gserviceaccount.com
```
</details>

Se hai **già compromesso un AppEngine** e hai il permesso **`appengine.applications.update`** e **actAs** sul service account da usare, potresti modificare il service account usato da AppEngine con:

<details>
<summary>Aggiorna service account di 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`

Con queste autorizzazioni è possibile accedere via ssh alle istanze di App Engine di tipo **flexible** (non **standard**). Alcune delle autorizzazioni **`list`** e **`get`** **potrebbero non essere realmente necessarie**.

<details>
<summary>SSH in un'istanza di App Engine</summary>
```bash
gcloud app instances ssh --service <app-name> --version <version-id> <ID>
```
</details>

### `appengine.applications.update`, `appengine.operations.get`

Penso che questo cambi solo il service account di background che Google userà per configurare le applicazioni, quindi non credo si possa abusarne per rubare il service account.

<details>
<summary>Aggiorna il service account dell'applicazione</summary>
```bash
gcloud app update --service-account=<sa_email>
```
</details>

### `appengine.versions.getFileContents`, `appengine.versions.update`

Non sono sicuro di come usare queste permission o se siano utili (nota che quando cambi il codice viene creata una nuova versione quindi non so se puoi semplicemente aggiornare il codice o il ruolo IAM di una versione esistente, ma immagino che dovrebbe essere possibile, magari cambiando il codice dentro il bucket??).

### Accesso in scrittura sui bucket

Come menzionato le appengine versions generano alcuni dati dentro un bucket con il nome nel formato: `staging.<project-id>.appspot.com`. Nota che non è possibile effettuare un pre-takeover di questo bucket perché gli utenti GCP non sono autorizzati a creare bucket usando il dominio `appspot.com`.

Tuttavia, con accesso in lettura e scrittura su questo bucket, è possibile escalare i privilegi all'SA associato alla versione AppEngine monitorando il bucket e ogni volta che viene effettuata una modifica, modificare il codice il più rapidamente possibile. In questo modo il container che viene creato da questo codice **eseguirà il backdoored code**.

Per maggiori informazioni e una **PoC consulta le informazioni rilevanti da questa pagina**:

{{#ref}}
gcp-storage-privesc.md
{{#endref}}

### Accesso in scrittura su Artifact Registry

Anche se App Engine crea immagini Docker dentro Artifact Registry, è stato testato che **anche se modifichi l'immagine all'interno di questo servizio** e rimuovi l'istanza di App Engine (quindi ne viene deployata una nuova) il **codice eseguito non cambia**.\
Potrebbe essere possibile che effettuando un **Race Condition attack come con i bucket sia possibile sovrascrivere il codice eseguito**, ma questo non è stato testato.

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