# GCP - AppEngine Privesc

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

## App Engine

For more information about App Engine check:

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

Those are the needed permissions to **deploy an App using `gcloud` cli**. Maybe the **`get`** and **`list`** ones could be **avoided**.

You can find python code examples in [https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/appengine](https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/appengine)

By default, the name of the App service is going to be **`default`**, and there can be only 1 instance with the same name.\
To change it and create a second App, in **`app.yaml`**, change the value of the root key to something like **`service: my-second-app`**

<details>
<summary>Deploy App Engine application</summary>

```bash
cd python-docs-samples/appengine/flexible/hello_world
gcloud app deploy #Upload and start application inside the folder
```

</details>

Give it at least 10-15min, if it doesn't work call **deploy another of times** and wait some minutes.

> [!NOTE]
> It's **possible to indicate the Service Account to use** but by default, the App Engine default SA is used.

The URL of the application is something like `https://<proj-name>.oa.r.appspot.com/` or `https://<service_name>-dot-<proj-name>.oa.r.appspot.com`

### Update equivalent permissions

You might have enough permissions to update an AppEngine but not to create a new one. In that case this is how you could update the current App Engine:

<details>
<summary>Update existing App Engine application</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>

If you have **already compromised a AppEngine** and you have the permission **`appengine.applications.update`** and **actAs** over the service account to use you could modify the service account used by AppEngine with:

<details>
<summary>Update App Engine service account</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`

With these permissions, it's possible to **login via ssh in App Engine instances** of type **flexible** (not standard). Some of the **`list`** and **`get`** permissions **could not be really needed**.

<details>
<summary>SSH into App Engine instance</summary>

```bash
gcloud app instances ssh --service <app-name> --version <version-id> <ID>
```

</details>

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

I think this just change the background SA google will use to setup the applications, so I don't think you can abuse this to steal the service account.

<details>
<summary>Update application service account</summary>

```bash
gcloud app update --service-account=<sa_email>
```

</details>

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

Not sure how to use these permissions or if they are useful (note that when you change the code a new version is created so I don't know if you can just update the code or the IAM role of one, but I guess you should be able to, maybe changing the code inside the bucket??).

### Write Access over the buckets

As mentioned the appengine versions generate some data inside a bucket with the format name: `staging.<project-id>.appspot.com`. 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`.

However, with read & write access over this bucket, it's possible to escalate privileges to the SA attached to the AppEngine version by monitoring the bucket and any time a change is performed, modify as fast as possible the code. This way, the container that gets created from this code will **execute the backdoored code**.

For more information and a **PoC check the relevant information from this page**:

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

### Write Access over the Artifact Registry

Even though App Engine creates docker images inside Artifact Registry. It was tested that **even if you modify the image inside this service** and removes the App Engine instance (so a new one is deployed) the **code executed doesn't change**.\
It might be possible that performing a **Race Condition attack like with the buckets it might be possible to overwrite the executed code**, but this wasn't tested.

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



