# GCP - AppEngine Privesc

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

## App Engine

App Engineの詳細については次を参照してください：

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

これらは、**`gcloud` cli** を使って App をデプロイするために必要な権限です。おそらく **`get`** と **`list`** は **不要** かもしれません。

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`**
```bash
cd python-docs-samples/appengine/flexible/hello_world
gcloud app deploy #Upload and start application inside the folder
```
少なくとも10～15分は待ってください。もし動作しない場合は、**deploy another of times** を実行して数分待ってください。

> [!NOTE]
> 使用する Service Account を指定することは可能ですが、デフォルトでは App Engine default SA が使用されます。

アプリケーションの URL は次のような形式になります: `https://<proj-name>.oa.r.appspot.com/` または `https://<service_name>-dot-<proj-name>.oa.r.appspot.com`

### 同等の権限を更新

AppEngine を新規作成する権限はなく、更新する権限だけある場合があります。その場合、現在の App Engine を更新する方法は次のとおりです:
```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
```
もし**already compromised a AppEngine**で、権限**`appengine.applications.update`**と使用するサービスアカウントに対する**actAs**を持っている場合、AppEngine が使用するサービスアカウントを次のように変更できます:
```bash
gcloud app update --service-account=<sa>@$PROJECT_ID.iam.gserviceaccount.com
```
### `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`

これらの権限があれば、**login via ssh in App Engine instances** が **flexible**（**standard** ではない）タイプで可能です。 一部の **`list`** および **`get`** 権限は、実際には必須ではない場合があります。
```bash
gcloud app instances ssh --service <app-name> --version <version-id> <ID>
```
### `appengine.applications.update`, `appengine.operations.get`

これはアプリケーションをセットアップする際に google が使用するバックグラウンドの SA を変更するだけだと思います。したがって、これを悪用して service account を steal することはできないと思います。
```bash
gcloud app update --service-account=<sa_email>
```
### `appengine.versions.getFileContents`, `appengine.versions.update`

これらの権限の使い方や有用性はよく分かりません（コードを変更すると新しいバージョンが作成されるため、単にコードやそのバージョンのIAMロールを更新できるかは不明ですが、おそらく可能だと思います。もしかするとbucket内のコードを変更することで??）。

### `bigquery.tables.delete`, `bigquery.datasets.delete` & `bigquery.models.delete` (`bigquery.models.getMetadata`)

テーブル、データセット、またはモデルを削除するには:
```bash
# Table removal
bq rm -f -t <PROJECT_ID>.<DATASET>.<TABLE_NAME>

# Dataset removal
bq rm -r -f <PROJECT_ID>:<DATASET>

# Model removal
bq rm -m <PROJECT_ID>:<DATASET_NAME>.<MODEL_NAME>
```
### Scheduled Queries の悪用

`bigquery.datasets.get`、`bigquery.jobs.create`、および `iam.serviceAccounts.actAs` の権限があれば、アイデンティティは dataset のメタデータを照会し、BigQuery ジョブを起動し、より高い権限を持つ Service Account を使ってそれらを実行できます。

この攻撃により、悪意のある Scheduled Queries を用いてクエリを自動化（選択した Service Account の権限で実行）することが可能になります。例えば、これにより機密データが読み取られ、攻撃者がアクセスできる別の table や dataset に書き込まれることで、データを外部に抽出することなく間接的かつ継続的な exfiltration を促進する可能性があります。

攻撃者が目的のクエリを実行するために必要な権限を持つ Service Account を特定したら、その Service Account を使って実行される Scheduled Query 設定を作成し、結果を定期的に任意の dataset に書き込ませることができます。
```bash
bq mk \
--transfer_config \
--project_id=<PROJECT_ID> \
--location=US \
--data_source=scheduled_query \
--target_dataset=<DEST_DATASET> \
--display_name="Generic Scheduled Query" \
--service_account_name="<SERVICE_ACCOUNT>@<PROJECT_ID>.iam.gserviceaccount.com" \
--schedule="every 10 minutes" \
--params='{
"query": "SELECT * FROM `<PROJECT_ID>.<SOURCE_DATASET>.<source_table>`;",
"destination_table_name_template": "<destination_table>",
"write_disposition": "WRITE_TRUNCATE"
}'

```
### バケットに対する書き込みアクセス

前述のとおり appengine versions は name フォーマットが `staging.<project-id>.appspot.com` のバケット内にいくつかのデータを生成します。GCP ユーザーはドメイン名 `appspot.com` を使ってバケットを生成する権限がないため、このバケットを事前に pre-takeover することはできません。

しかし、このバケットに対する読み取り & 書き込みアクセスがあれば、バケットを監視し、変更が行われるたびに可能な限り素早くコードを改変することで、AppEngine version に紐づいた SA に対して権限昇格を行うことが可能です。こうすることで、そのコードから作成されるコンテナは **backdoored code** を実行します。

詳細と **PoC** は下記のページの該当情報を参照してください：

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

### Artifact Registry に対する書き込みアクセス

App Engine が Artifact Registry 内に docker images を作成するにも関わらず、**サービス内のイメージを変更した場合でも** App Engine インスタンスを削除（つまり新しいインスタンスがデプロイされる）しても、**実行されるコードは変わらない** ということがテストで確認されました。\
バケットの場合と同様に **Race Condition attack を行えば実行されるコードを上書きできる可能性がある** かもしれませんが、これはテストされていません。

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