SSRF (CWE-918) : forcer le serveur à requêter des ressources internes — métadonnées cloud, APIs privées et escalade vers la compromission totale.
TL;DR
169.254.169.254 retourne des credentials IAM en deux requêtes HTTP — sans authentification requise sur IMDSv1Le Server-Side Request Forgery (CWE-918, OWASP A10:2021) survient quand un attaquant peut amener un serveur à émettre des requêtes HTTP vers une destination arbitraire — interne ou externe. Le serveur agit comme un proxy, les requêtes étant émises depuis une IP interne de confiance. Les pare-feux, groupes de sécurité et règles de routage VPC qui empêchent les clients externes d'atteindre les services internes ne bloquent pas les requêtes provenant du serveur lui-même.
Le SSRF a obtenu sa propre catégorie dans l'OWASP Top 10 en 2021 — la première nouvelle entrée non présente dans A09:2017. La raison : les architectures cloud-first ont rendu chaque instance EC2, fonction Lambda, VM GCE et Azure VM exposée à un endpoint de métadonnées link-local (169.254.169.254) accessible uniquement depuis l'intérieur de l'instance. Une seule vulnérabilité SSRF sur n'importe quelle application s'exécutant dans le cloud devient un chemin direct de vol de credentials.
Le SSRF diffère du CSRF sur un point clé : le CSRF cible le navigateur de la victime et sa session ; le SSRF cible le serveur et sa position réseau. Le SSRF est généralement plus impactant car les services internes n'ont souvent aucune authentification, supposant que l'isolation réseau est suffisante. OWASP A10:2021 référence 385 CVEs mappés sur CWE-918 et note que si les taux d'incidence semblent faibles lors des tests, le potentiel d'exploitation et d'impact supérieur à la moyenne le place dans le Top 10.
L'attaquant identifie un paramètre dont la valeur est utilisée dans une requête HTTP côté serveur. Il peut s'agir d'un champ URL, d'un callback webhook, d'un endpoint d'upload d'image depuis URL, ou d'une fonctionnalité d'import/fetch. Au lieu de soumettre une URL légitime, l'attaquant fournit une adresse interne. Le serveur effectue la requête depuis son propre contexte et, dans le cas le plus simple, retourne la réponse directement.
La différence critique avec une redirection côté client : la requête sortante de l'application contourne tous les contrôles orientés vers l'extérieur. Un WAF inspectant le trafic entrant n'inspecte pas les requêtes sortantes propres de l'application vers le service de métadonnées.
Six classes distinctes de SSRF couvrent l'ensemble de la surface d'attaque :
| Variante | Mécanisme | Cible principale | CVSS typique |
|---|---|---|---|
| SSRF en bande basique | Le serveur retourne la réponse à l'attaquant | Services internes, métadonnées cloud | 7.5 |
| OOB aveugle | Aucune réponse retournée ; callback OOB confirme | Services backend, chaînes second-order | 7.5 |
| Métadonnées cloud | Cible 169.254.169.254 ou équivalent | Credentials IAM AWS/GCP/Azure | 8.5–9.0 |
| Smuggling de protocoles | Schémas non-HTTP (gopher://, file://, dict://) | RCE Redis, lectures système de fichiers, MySQL | 9.0+ |
| Basé sur les en-têtes | En-têtes injectés provoquant des requêtes côté serveur | Routage interne, contournement métadonnées | 8.0–9.2 |
| DNS rebinding | TOCTOU : IP valide à la validation → IP interne à la requête | Contourne les filtres liste d'autorisation | 7.5 |
Le serveur récupère une URL fournie par l'attaquant et retourne le corps de la réponse directement. Tout endpoint acceptant un paramètre URL et retournant son contenu est un candidat. Les surfaces d'attaque incluent les endpoints de prévisualisation de liens, l'upload d'avatar de profil depuis URL, la fonctionnalité d'import depuis flux, et les boutons de test webhook qui affichent la réponse.
Le serveur effectue la requête sortante mais supprime la réponse. La confirmation nécessite un écouteur OOB externe (Burp Collaborator, Interactsh, oast.fun). Le scanner BreachVex utilise un modèle de confiance gradué : un callback DNS seul est traité comme potentiel, un callback HTTP comme une vulnérabilité confirmée de sévérité élevée, et l'exfiltration de données via le corps hors-bande comme confirmée critique. Le DNS seul ne passe jamais à confirmé — les composants d'infrastructure résolvent régulièrement des hostnames sans émettre de requêtes HTTP.
Chaque fournisseur cloud majeur expose un service de métadonnées link-local à 169.254.169.254 (AWS, GCP, Azure, DigitalOcean) ou des adresses équivalentes. Sur AWS avec IMDSv1, deux requêtes suffisent pour obtenir des credentials IAM temporaires — sans token, sans authentification, sans connaissance préalable du nom du rôle. La brèche Capital One de 2019 a suivi exactement ce pattern, exposant 106 millions de dossiers.
Quand la bibliothèque de récupération d'URL supporte des schémas au-delà de http:// et https://, des protocoles alternatifs permettent une communication TCP brute avec les services internes. gopher:// permet d'injecter des octets arbitraires dans une connexion Redis sur le port 6379, en écrivant une tâche cron pour une RCE. file:///etc/passwd lit le système de fichiers local. dict:// interroge Memcached. Ces attaques ne nécessitent pas HTTP — la bibliothèque URL du serveur émet le protocole brut directement.
Les en-têtes HTTP consommés côté serveur peuvent déclencher des requêtes sortantes. L'en-tête X-Forwarded-Host est traité par Angular SSR, Astro, Symfony et Django pour construire des URLs d'API internes. L'injection de X-Forwarded-Host: attacker.com amène le framework à effectuer une requête HTTP vers http://attacker.com/api/config au lieu de l'endpoint interne légitime. CVE-2026-27739 (CVSS 9.2) démontre ce pattern sur Angular SSR.
Capital One 2019 — Un WAF mal configuré sur EC2 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. Impact : 106 millions de dossiers, amende OCC de 80M$, règlement collectif de 190M$. Cause principale : IMDSv1 (sans token requis) et un rôle IAM sur-privilégié.
CVE-2025-6454 — GitLab CE/EE (CVSS 8.5) — La fonctionnalité d'en-têtes personnalisés de webhook introduite dans GitLab 16.11 permettait l'injection CRLF dans les noms d'en-têtes. Un utilisateur authentifié avec le rôle Developer+ pouvait injecter des séquences \r\n pour forger des en-têtes HTTP arbitraires dans les requêtes webhook sortantes, permettant l'accès aux proxies internes et aux services de métadonnées. Corrigé dans les versions 18.1.6, 18.2.6, 18.3.2.
CVE-2025-68437 — Craft CMS GraphQL — Le paramètre _file { url } de la mutation saveAssets récupérait du contenu depuis des URLs arbitraires sans validation. Un attaquant disposant des permissions sur les assets GraphQL pouvait fournir http://169.254.169.254/latest/meta-data/iam/security-credentials/ — les credentials récupérés étaient enregistrés comme asset et récupérables via l'API du CMS.
CVE-2022-22947 — Spring Cloud Gateway (CVSS 10.0) — Les expressions SpEL dans les prédicats de routes créaient une chaîne SSRF→RCE. Exploitée dans la nature dans les 72 heures suivant la divulgation publique, avant que la plupart des organisations puissent appliquer le correctif.
url, callback, webhook, endpoint, redirect, image, src), les en-têtes HTTP (Host, X-Forwarded-Host, Referer), et les endpoints d'import/export de données.https://<id-burp-collaborator>.oastify.com comme valeur de paramètre pour chaque candidat.http://127.0.0.1/, http://169.254.169.254/latest/meta-data/, http://localhost:3000/, http://localhost:9200/.http://2130706433/), IPv6 (http://[::1]/), et chaîne de redirection (https://302.r3dir.me/?r=http://169.254.169.254/).Interactsh (ProjectDiscovery) fournit un écouteur OOB auto-hébergeable. Une requête DNS sans suivi HTTP suggère un SSRF avec l'egress HTTP bloqué — toujours exploitable pour le scan de ports internes via le timing. SSRFmap automatise le fuzzing de paramètres. Nuclei dispose de templates SSRF couvrant les endpoints de métadonnées cloud et les noms de paramètres vulnérables connus depuis un corpus de 80+ noms canoniques (url, webhook, callback, image_url, avatar_url, redirect_uri, etc.).
BreachVex détecte le SSRF via plusieurs techniques complémentaires : l'injection de callbacks hors-bande par paramètre avec un modèle de confiance gradué, l'analyse différentielle de réponse par rapport aux IPs de contrôle RFC 5737, et le sondage direct des services internes courants — endpoints de métadonnées cloud, APIs de conteneurs et d'orchestration, tableaux de bord de monitoring et datastores internes — avec confirmation basée sur des marqueurs.
Les listes de blocage sont contournées par l'encodage, les alias DNS et le mapping IPv6. Seules les listes d'autorisation fonctionnent :
import ipaddress
import socket
import urllib.parse
ALLOWED_HOSTS = frozenset({"api.stripe.com", "hooks.slack.com"})
def validate_url(url: str) -> bool:
parsed = urllib.parse.urlparse(url)
# 1. Liste d'autorisation de schémas — bloque gopher://, file://, dict://, ftp://
if parsed.scheme not in ("http", "https"):
return False
host = (parsed.hostname or "").rstrip(".") # supprimer le point FQDN final (classe CVE-2025-62718)
if not host or host not in ALLOWED_HOSTS:
return False
# 2. Résoudre DNS et valider l'IP résultante — contrecarre les alias DNS et nip.io
try:
results = socket.getaddrinfo(host, None, proto=socket.IPPROTO_TCP)
for (_, _, _, _, sockaddr) in results:
ip = ipaddress.ip_address(sockaddr[0])
# Normaliser IPv6 mappé IPv4 (::ffff:127.0.0.1 → 127.0.0.1)
if isinstance(ip, ipaddress.IPv6Address) and ip.ipv4_mapped:
ip = ip.ipv4_mapped
if ip.is_private or ip.is_loopback or ip.is_link_local or ip.is_reserved:
return False
except (socket.gaierror, ValueError):
return False # fermeture sécurisée sur les erreurs de résolution
return TrueAppliquer IMDSv2 au niveau de l'infrastructure — les correctifs au niveau applicatif sont insuffisants si l'endpoint de métadonnées est accessible :
# Par instance
aws ec2 modify-instance-metadata-options \
--instance-id i-1234567890abcdef0 \
--http-tokens required \
--http-put-response-hop-limit 1
# Vérifier la conformité à l'échelle du compte
aws ec2 describe-instances \
--query "Reservations[].Instances[?MetadataOptions.HttpTokens=='optional'].{ID:InstanceId}" \
--output table
# SCP à l'échelle de l'organisation — bloquer le lancement d'instances avec IMDSv1
{
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Condition": {
"StringEquals": { "ec2:MetadataHttpTokens": "optional" }
}
}La validation au niveau applicatif doit être un dernier recours, pas le seul contrôle. Restreindre l'egress au niveau réseau :
169.254.169.254/32 et 168.63.129.16/32 dans les règles sortantes des groupes de sécuritéCAP_NET_RAW dans les contextes de sécurité des conteneursNe jamais se fier à une liste de blocage d'IPs ou hostnames « mauvais ». Les attaquants les contournent via l'encodage DWORD décimal (2852039166 pour 169.254.169.254), les adresses IPv6 mappées ([::ffff:a9fe:a9fe]), les chaînes de redirection (302.r3dir.me) et le DNS rebinding. Une liste d'autorisation de destinations autorisées est le seul contrôle qui résiste à ces techniques de contournement.
| SSRF | CSRF | |
|---|---|---|
| Qui émet la requête | Le serveur | Le navigateur de la victime |
| Quelle session est utilisée | L'identité réseau du serveur | La session authentifiée de la victime |
| Cible principale | Réseau interne, métadonnées cloud | Actions sur les endpoints authentifiés |
| Impact | Vol de credentials, RCE, exfiltration de données | Modifications d'état non autorisées en tant que victime |
| Nécessite une interaction de la victime | Non | Oui (la victime doit charger la page de l'attaquant) |
| Défense | Liste d'autorisation URL + filtrage d'egress | Cookies SameSite + tokens CSRF |
Le SSRF (CWE-918) est une vulnérabilité web où un attaquant amène un serveur à émettre des requêtes HTTP vers une destination arbitraire. Le serveur agit comme un proxy depuis une IP de confiance, contournant les pare-feux et les contrôles réseau qui bloquent l'accès externe aux ressources internes.
Le CSRF force le navigateur d'une victime à envoyer une requête en utilisant sa session — l'attaque cible l'utilisateur. Le SSRF force le serveur lui-même à émettre des requêtes vers des systèmes internes — l'attaque cible l'infrastructure. L'impact du SSRF est généralement plus sévère car les services internes sont entièrement accessibles depuis le serveur.
Le SSRF a été élevé au rang A10:2021 parce que les déploiements cloud ont rendu chaque instance EC2, Lambda, GCE et Azure VM exposée à un endpoint de métadonnées link-local par défaut. Les attaques SSRF ont progressé de 452 % de 2023 à 2024 (rapport SonicWall 2025 Cyber Threat Report), portées par les outils assistés par IA et les architectures cloud-first.
En 2019, un WAF mal configuré sur EC2 avait une vulnérabilité SSRF. Un attaquant a interrogé l'endpoint AWS IMDSv1 à 169.254.169.254, obtenu des credentials IAM temporaires pour le rôle sur-privilégié ISRM-WAF-Role, énuméré 700+ buckets S3 et exfiltré 30 Go de données. La brèche a exposé 106 millions de dossiers clients et a entraîné une amende OCC de 80M$.
Oui. Le chemin le plus direct utilise le protocole gopher:// ciblant une instance Redis interne sur le port 6379. gopher:// permet une communication TCP brute, permettant à un attaquant d'injecter des commandes Redis qui écrivent une tâche cron ou un fichier SSH authorized_keys — obtenant ainsi une exécution de code à distance (RCE). CVE-2022-22947 (Spring Cloud Gateway, CVSS 10.0) combinait SSRF et injection SpEL pour obtenir une RCE complète, exploitée dans la nature 72 heures après sa divulgation.
Dans le SSRF aveugle, le serveur émet la requête sortante mais ne retourne pas la réponse dans la réponse HTTP. La détection nécessite des techniques hors-bande (OOB) : un serveur de callback contrôlé par l'attaquant (Burp Collaborator, Interactsh) enregistre les résolutions DNS ou les hits HTTP confirmant que le serveur a atteint l'URL cible.
Les contournements de liste de blocage incluent : encodage IP (DWORD décimal 2130706433 au lieu de 127.0.0.1), notation octale/hexadécimale, adresses IPv6 mappées (::ffff:127.0.0.1), alias DNS (localtest.me, nip.io), chaînes de redirection (302.r3dir.me), et différentiels de parseur d'URL (confusion user-info@169.254.169.254). Une liste d'autorisation avec validation IP post-résolution DNS est la seule défense fiable.
IMDSv2 exige une requête PUT avec un en-tête TTL pour obtenir un token de session avant d'accéder aux métadonnées. Il relève considérablement la barre pour le SSRF basique (qui n'émet que des GET). Il est cependant contournable quand le SSRF permet des en-têtes HTTP personnalisés, des requêtes multi-étapes, ou lors de l'exécution dans un navigateur sans tête (générateurs PDF, Puppeteer). Fin 2024, seulement 32 % des instances EC2 appliquaient IMDSv2.
Les tests manuels utilisent Burp Suite Pro avec Burp Collaborator pour la détection OOB. Les outils automatisés incluent Interactsh (écouteur OOB auto-hébergeable), SSRFmap (fuzzer de paramètres automatisé) et Gopherus (générateur de payload gopher:// pour Redis/FastCGI/MySQL). Nuclei dispose de templates SSRF pour les patterns courants.
Utiliser une liste d'autorisation de domaines autorisés, valider le schéma (https uniquement), résoudre DNS et bloquer toute IP privée/link-local/loopback après résolution, désactiver le suivi des redirections, et forcer la connexion à l'IP résolue directement (épinglage DNS) pour prévenir les attaques de DNS rebinding. Ne jamais utiliser uniquement des listes de blocage — les contournements par encodage sont triviaux.