Outil gratuit · 100 % navigateur
SSRF Toolkit
Calcul : ip-address · MIT
01Encodeur d’adresse
Notation pointée, ou toute écriture que WHATWG URL ramène à une IPv4 (0x7f000001, 127.1, ::ffff:127.0.0.1).
{ip} est remplacé par chaque écriture dans la liste copiée. Vide : les écritures seules.
L’interprétation dépend du client. inet_aton (glibc) accepte l’octal, l’hexadécimal et les formes courtes, comme le parseur IPv4 de WHATWG URL. inet_pton les refuse, et le module ipaddress de Python rejette les zéros de tête depuis la version 3.9.5 (CVE-2021-29921). La colonne WHATWG donne la lecture des navigateurs, de Node et des clients qui suivent ce standard, calculée par votre navigateur : testez toujours le client réel de la cible.
| Écriture | Type | new URL().hostname | Lecture |
|---|
Qui accepte quelle écriture
- Entier
- Un seul nombre de 32 bits. inet_aton (glibc) et WHATWG URL l’acceptent en décimal, en hexadécimal (0x) et en octal (0 de tête) ; inet_pton le refuse.
- Pointé
- Quatre parties, chacune en hexadécimal ou en octal. Le zéro de tête signifie octal pour inet_aton et WHATWG ; le module ipaddress de Python refuse les zéros de tête depuis la 3.9.5 (CVE-2021-29921).
- Forme courte
- Formes a.b et a.b.c d’inet_aton, reprises par WHATWG : la dernière partie remplit les octets restants.
- Mixte
- Chaque partie choisit sa base. Utile contre les filtres qui cherchent un motif précis (0x7f, 0177).
- Encodage URL
- WHATWG décode les %XX de l’hôte avant de l’analyser. Un filtre qui teste la chaîne brute ne voit pas l’adresse.
- Unicode
- WHATWG applique le mappage UTS #46 (chiffres pleine chasse, chiffres cerclés, point idéographique) avant le parseur IPv4. Un client qui ne le fait pas traite la chaîne comme un nom.
- IPv6
- Entre crochets, comme dans une URL. Une socket IPv6 double pile (le défaut sous Linux) atteint l’IPv4 d’une adresse mappée ; 6to4 et NAT64 n’y mènent qu’à travers un relais ou une passerelle.
- Alias local
- Autres façons de joindre l’hôte local. Sous Linux, une connexion vers 0.0.0.0 aboutit sur la machine elle-même.
- DNS wildcard
- Noms publics qui résolvent vers l’IP qu’ils contiennent (nip.io, sslip.io). La cible doit pouvoir résoudre un nom externe. Présentés en texte, cette page ne les interroge pas.
02Contournements d’allowlist
Chaque gabarit est analysé par WHATWG URL. T désigne le domaine autorisé et A l’hôte de l’attaquant. Les trois contrôles naïfs testés : url.includes(T), url.startsWith("https://" + T), host.endsWith(T).
| Technique | URL | Hôte réel (WHATWG) | Contrôles naïfs |
|---|
Collez l’URL que votre filtre doit juger : voici ce qu’en fait WHATWG URL.
03Endpoints metadata cloud
Relevé dans la documentation officielle de chaque fournisseur en octobre 2026. La colonne En-têtes dit si une SSRF qui ne contrôle que l’URL d’un GET suffit.
| Plateforme | Requête | En-têtes | Source |
|---|---|---|---|
| AWS EC2 IMDSv1 |
Identifiants Actif tant que l’instance n’exige pas IMDSv2 (paramètre HttpTokens à optional). Adresse IPv6 sur les instances Nitro : [fd00:ec2::254]. | Aucun : un GET suffit | |
| AWS EC2 IMDSv2 |
Identifiants Il faut un PUT puis un en-tête personnalisé : une SSRF limitée au GET ne suffit pas. Aucun jeton n’est émis à une requête qui porte X-Forwarded-For, et la réponse au PUT a un TTL IP de 1 par défaut. | En-tête requis
| |
| AWS ECS Rôle de tâche |
Renvoie directement les identifiants du rôle de la tâche. Le chemin est propre à chaque tâche et vit dans une variable d’environnement du conteneur : il faut d’abord le lire (file:///proc/self/environ, fuite de logs). | Aucun : un GET suffit | |
| Google Cloud Compute Engine, GKE |
Identifiants Aussi joignable sur 169.254.169.254. Sans l’en-tête, le serveur refuse la requête ; toute requête qui porte X-Forwarded-For est rejetée. | En-tête requis
| |
| Microsoft Azure IMDS |
Identifiants Le paramètre api-version est obligatoire (la documentation en liste les valeurs). La requête doit porter Metadata: true et ne doit pas porter X-Forwarded-For. | En-tête requis
| |
| DigitalOcean Droplet |
Le service ne fournit aucun identifiant cloud. En revanche, user-data (/metadata/v1/user-data) contient souvent des scripts de démarrage et des secrets. | Aucun : un GET suffit | |
| Oracle Cloud IMDSv1 |
Points d’accès historiques /opc/v1 et /openstack, sans en-tête. Ils répondent 404 une fois IMDSv1 désactivé. | Aucun : un GET suffit | |
| Oracle Cloud IMDSv2 |
Toute requête v2 doit porter cet en-tête fixe : il suffit que la SSRF permette d’ajouter un en-tête. | En-tête requis
| |
| Alibaba Cloud ECS, mode normal |
Identifiants Mode accepté par défaut, que la documentation qualifie de non sécurisé. | Aucun : un GET suffit | |
| Alibaba Cloud ECS, mode renforcé |
Identifiants Même principe qu’IMDSv2 chez AWS : PUT pour obtenir un jeton (1 à 21 600 secondes), puis en-tête sur chaque requête. | En-tête requis
| |
| Kubernetes API server depuis un pod |
Identifiants Le jeton du compte de service est monté dans le conteneur : une SSRF qui lit file:// le récupère, une SSRF HTTP qui ajoute l’en-tête s’en sert. | En-tête requis
| |
| Kubernetes API du kubelet |
Par défaut, le binaire kubelet traite les requêtes sans authentification comme anonymes et son mode d’autorisation par défaut est AlwaysAllow. La plupart des distributions durcissent ces réglages (--anonymous-auth=false, Webhook) : vérifiez. | Aucun : un GET suffit |
04Schémas d’URL
Ce que chaque schéma permet quand le client de la cible l’accepte. libcurl en gère la plupart selon sa compilation (curl --version liste les protocoles disponibles).
| Schéma | Exemple | Usage en SSRF |
|---|---|---|
| http, https | http://127.0.0.1:8080/admin | Services web internes, consoles d’administration, API metadata. Le code et le temps de réponse servent aussi à scanner des ports. |
| file | file:///etc/passwd | Lecture de fichiers locaux quand le client le permet (libcurl, java.net.URL, fonctions de fichiers PHP). Sous Windows, file://hôte/partage ouvre une connexion SMB qui peut livrer un hash NetNTLM. |
| gopher | gopher://127.0.0.1:6379/_PING%0D%0A | Octets TCP arbitraires après le premier caractère du chemin, encodés en %XX : parler à Redis, Memcached, SMTP ou FastCGI. Pris en charge par libcurl. |
| dict | dict://127.0.0.1:6379/INFO | Envoie une ligne de commande à un port TCP et renvoie la réponse : bannières et commandes d’une ligne (Redis, Memcached). Pris en charge par libcurl. |
| ftp | ftp://10.0.0.5/ | Listage et lecture sur un FTP interne. Un serveur qui accepte une commande PORT vers un tiers se connecte à l’hôte choisi (FTP bounce). |
| ldap, ldaps | ldap://10.0.0.10:389/dc=corp,dc=local | Requêtes vers un annuaire interne (libcurl). Côté Java, une recherche JNDI vers ldap:// peut charger un objet distant. |
| tftp | tftp://10.0.0.5/config.txt | Lecture d’un fichier sur un serveur TFTP (UDP 69), fréquent sur les équipements réseau. Pris en charge par libcurl. |
Qu’est-ce qu’une SSRF ?
Une SSRF, ou Server-Side Request Forgery, est une vulnérabilité qui permet de faire émettre par un serveur une requête vers une destination choisie par l’attaquant. Elle peut exposer des services internes, des interfaces locales ou des métadonnées cloud accessibles depuis le serveur mais pas directement depuis Internet.
Ce qu’est une SSRF
Une Server-Side Request Forgery (CWE-918) survient quand une application récupère une ressource à partir d’une URL fournie par l’utilisateur : import d’image par lien, webhook, aperçu de lien, générateur de PDF, métadonnées SAML ou OpenID chargées à distance. L’attaquant fait alors émettre la requête par le serveur, depuis sa position réseau. Il atteint ce qui n’est pas exposé sur Internet : services en écoute sur 127.0.0.1, réseau interne, consoles d’administration et, dans le cloud, le service de métadonnées de l’instance, qui distribue des identifiants temporaires.
L’OWASP a classé la SSRF en catégorie propre, A10, dans le Top 10 de 2021. L’édition 2025 l’a intégrée à A01 (Broken Access Control) : le défaut tient au fait que le serveur accède en votre nom à des ressources qui devraient vous être fermées.
Pourquoi les listes noires échouent
Un filtre qui refuse 127.0.0.1 ou 169.254.169.254 compare une chaîne, alors que le client résout une adresse. Une même adresse s’écrit de dizaines de façons que la libc ou le parseur WHATWG acceptent : entier décimal, hexadécimal, octal, formes courtes, IPv6 mappée, Unicode. L’encodeur ci-dessus les génère et montre ce que lit un parseur conforme.
Les autres contournements ne touchent même pas l’écriture. Une redirection : le filtre valide https://votre-serveur/, qui répond 302 vers http://169.254.169.254/, et le client suit. Le DNS : un nom public comme 127.0.0.1.nip.io résout vers l’adresse interne, et le DNS rebinding sert une adresse publique au moment du contrôle puis une adresse interne au moment de la connexion, grâce à un TTL très court. Enfin, les écarts entre parseurs : Orange Tsai a montré à Black Hat USA 2017 que des bibliothèques courantes ne découpent pas une URL au même endroit (@, #, barre oblique inverse). Le contrôle et la requête lisent alors deux hôtes différents, ce que la section 02 rend visible.
Metadata cloud, Capital One et IMDSv2
Les services de métadonnées répondent sur une adresse link-local joignable depuis l’instance seule, et livrent les identifiants du rôle qui lui est attaché. En mars 2019, une intrusion chez Capital One est partie d’un pare-feu applicatif mal configuré sur EC2 : selon les analyses publiées, il a servi de relais vers le service de métadonnées, et les identifiants du rôle IAM obtenus ont permis de copier des données stockées dans S3. La banque a annoncé l’incident le 29 juillet 2019 ; il touchait environ 100 millions de personnes aux États-Unis et 6 millions au Canada. L’OCC lui a infligé une amende de 80 millions de dollars en août 2020.
AWS a publié IMDSv2 le 19 novembre 2019. Le client ouvre une session par un PUT sur /latest/api/token et présente ensuite le jeton dans l’en-tête X-aws-ec2-metadata-token. Une SSRF qui ne contrôle que l’URL d’un GET n’obtient rien. Le jeton n’est pas émis à une requête qui porte X-Forwarded-For, et la réponse au PUT part avec un TTL IP de 1, ce qui l’empêche de franchir un saut réseau supplémentaire. Google Cloud (Metadata-Flavor: Google), Azure (Metadata: true) et Oracle Cloud en version 2 (Authorization: Bearer Oracle) exigent aussi un en-tête. Le tableau de la section 03 indique pour chaque fournisseur si une SSRF simple suffit.
Méthode en mission
Repérez d’abord toutes les fonctions qui acceptent une URL ou un nom d’hôte, y compris dans les paramètres cachés, les en-têtes (Referer, Host derrière un proxy) et les documents traités côté serveur (SVG, XML avec entités externes, HTML converti en PDF). Confirmez la requête sortante avec un domaine que vous surveillez : Burp Collaborator dans Burp Suite Professional, ou interactsh de ProjectDiscovery, open source et auto-hébergeable. Une interaction DNS seule prouve la résolution, une requête HTTP prouve la connexion et donne souvent le User-Agent du client, donc son parseur.
Quand la réponse n’est pas renvoyée (SSRF aveugle), mesurez les écarts de temps et de code d’erreur entre ports ouverts et fermés. Visez ensuite 127.0.0.1 et les endpoints metadata ; si un filtre bloque, passez la liste de l’encodeur dans Burp Intruder, puis essayez une redirection depuis votre serveur et un nom nip.io. Un payload gopher vers Redis ou SMTP écrit réellement sur le service visé.
Se défendre
- Analysez l’URL une fois, avec le parseur du client qui fera la requête, et comparez l’hôte obtenu à une allowlist : égalité stricte, ou suffixe précédé d’un point.
- Résolvez le nom, refusez toute adresse loopback, privée (RFC 1918), link-local (169.254.0.0/16), CGNAT et leurs équivalents IPv6, après normalisation des adresses IPv4 mappées, puis connectez-vous à l’adresse vérifiée pour fermer la porte au DNS rebinding.
- Désactivez le suivi des redirections ou revalidez chaque saut, et limitez les schémas à http et https.
- Exigez IMDSv2 (HttpTokens=required) sur toutes les instances EC2, avec une limite de sauts à 1 quand aucun conteneur n’en a besoin.
- Filtrez la sortie réseau : un serveur applicatif n’a besoin que de quelques destinations, et les conteneurs n’ont généralement pas à joindre 169.254.169.254.
- Ne renvoyez jamais la réponse brute du serveur distant à l’utilisateur, ni ses messages d’erreur détaillés.
?Questions fréquentes
L’outil envoie-t-il des requêtes vers les adresses générées ?
Non. Les écritures sont produites par ip-address et analysées par le parseur URL de votre propre navigateur, sans connexion réseau. Les noms nip.io et sslip.io sont affichés en texte et ne sont jamais résolus, et les liens vers la documentation ne s’ouvrent que si vous cliquez dessus.
Pourquoi 0177.0.0.1 désigne-t-il 127.0.0.1 ?
Héritage d’inet_aton : un zéro de tête signifie octal, et 0177 vaut 127. Les navigateurs, Node et la libc suivent cette règle, alors que le module ipaddress de Python rejette les zéros de tête depuis la 3.9.5 (CVE-2021-29921), après avoir lu 0127 en décimal. Un filtre écrit en Python et un client libcurl peuvent donc lire deux adresses différentes dans la même chaîne.
Quelle écriture essayer en premier ?
Celle qui sort du motif que le filtre cherche. Un blocage par expression régulière sur 127. ou 169.254. tombe devant le décimal entier et les formes courtes ; une liste noire IPv4 seule tombe devant l’IPv6 mappée. Si aucune ne passe, la redirection depuis votre serveur et le DNS (nip.io, rebinding) contournent tout contrôle qui porte sur la chaîne.
IMDSv2 rend-il une SSRF inoffensive sur AWS ?
Il bloque la SSRF la plus courante, celle qui ne contrôle que l’URL d’un GET : il faut d’abord un PUT avec un en-tête, puis l’en-tête X-aws-ec2-metadata-token sur chaque requête. Une SSRF qui maîtrise la méthode et les en-têtes, ou du code exécuté sur l’instance, obtient toujours un jeton. Le TTL IP de 1 et le refus des requêtes portant X-Forwarded-For limitent les relais par proxy.
Comment confirmer une SSRF aveugle ?
Donnez à la fonctionnalité une URL que vous surveillez : un domaine Burp Collaborator ou un serveur interactsh. Une requête DNS seule prouve la résolution, une requête HTTP prouve la connexion sortante et révèle souvent le client (User-Agent). Ensuite, les différences de temps de réponse ou de code d’erreur entre un port ouvert et un port fermé permettent de cartographier le réseau interne sans voir la réponse.
Comment écrire une allowlist correcte ?
Analysez l’URL une seule fois, avec le parseur que le client utilisera, puis comparez l’hôte obtenu à la liste : égalité stricte, ou suffixe précédé d’un point pour les sous-domaines. Résolvez ensuite le nom, refusez toute adresse privée, loopback ou link-local, et connectez-vous à l’adresse vérifiée. Désactivez les redirections ou revalidez chaque saut.
+Autres outils
- /24Subnet Calculator
IPv4 et IPv6 : masques, plages et découpage CIDR.
- *-srcCSP Evaluator
Trouvez les contournements d’une Content Security Policy.
- >_Reverse Shell Generator
Payloads de reverse shell, listeners et upgrade TTY.
Audit technique
Faire vérifier une application ou une infrastructure
Pour une analyse par notre équipe, indiquez les systèmes concernés, les accès disponibles et les tests souhaités dans votre demande.