Aller au contenu
Categoria: Pentest9 min de lecture

SSRF Demystifie: Exploiter Cloud Metadata dans un Lab AWS Local

Por Lucas Andrade ·

Reproduction ethique de SSRF contre IMDS avec LocalStack, payloads reels, capture de credentials simules et blocage definitif via IMDSv2.

SSRF Demystifie: Exploiter Cloud Metadata dans un Lab AWS Local

L'endpoint 169.254.169.254 a brule plus de carrieres SRE que n'importe quelle autre IP de l'histoire du cloud. Capital One en 2019 a perdu environ 100 millions d'enregistrements parce qu'une WAF mal configuree a laisse un Server-Side Request Forgery atteindre l'Instance Metadata Service et extraire des credentials temporaires du role EC2. Des annees plus tard, nous recevons encore des rapports de bug bounty avec le pattern identique : une app recupere une image depuis une URL fournie par l'utilisateur, personne ne valide la destination, IMDSv1 reste actif, game over. Reconstruisons cette attaque depuis zero dans un lab AWS local avec LocalStack, comprenons exactement pourquoi IMDSv2 change le calcul, et terminons avec une checklist de durcissement deployable des aujourd'hui. Tout tourne sur votre propre machine, il n'y a donc d'autre cible que votre propre lab.

Qu'est-ce que le SSRF, et que fait le metadata service

Le Server-Side Request Forgery est une classe de bug ou un attaquant controle la destination d'une requete que le serveur fait en son nom. L'application est le deputy confus : elle a une position reseau et une identite que l'attaquant n'a pas, et elle se connecte volontiers la ou il pointe. Dans AWS, la destination interne de plus grande valeur est l'Instance Metadata Service (IMDS) a 169.254.169.254, une adresse link-local que chaque instance EC2 atteint. Il expose des donnees d'instance et, crucial, des credentials temporaires de role IAM sous /latest/meta-data/iam/security-credentials/. Un SSRF qui l'atteint transforme une innocente recuperation d'image en vol de credentials, ce qui en fait la cible la plus lourde de consequences en pentest cloud.

Contexte de menace : pourquoi cela continue

Le pattern se repete parce que le code vulnerable a l'air raisonnable. Un produit doit recuperer un avatar, rendre un apercu de lien ou proxifier un webhook, alors il accepte une URL et l'appelle cote serveur. Le developpeur pense a des images, pas a un endpoint de metadata link-local qui distribue des credentials cloud. Pendant ce temps, IMDSv1 est reste le defaut sur les anciennes instances pendant des annees, si bien que le coffre a credentials etait a une requete non validee de distance. La meme forme apparait dans Pentest APIs REST et GraphQL : Checklist Technique pour Bug Bounty Legal des que des endpoints de webhook ou d'image-proxy acceptent des URLs internes sans allowlist. Comprendre le pattern est ce qui permet de le trouver dans une cible et, surtout, de le tuer dans votre propre code.

Construire le lab avec LocalStack

L'environnement d'abord. Montez LocalStack Pro 4.x via docker-compose avec ec2, iam, sts et s3 actives, plus un conteneur Flask expose sur le port 5000 faisant tourner une API fetch-image deliberement vulnerable. Le code vulnerable fait environ dix-huit lignes : il recoit ?url=, appelle requests.get sans validation et renvoie le body. Pour simuler IMDS dans LocalStack, utilisez le mock de metadata ec2 ou un mock dedie lie a 169.254.169.254 via un network namespace. Qui veut une fidelite maximale utilise une vraie t3.micro a quelques centimes l'heure, mais LocalStack couvre environ 95% de l'apprentissage sans carte de credit. Le setup de conteneurs de base que vous reutilisez ici est couvert dans Pentest Web depuis Zero: Construire un Lab Sur avec DVWA, Juice Shop et Burp Suite.

Exploiter IMDSv1, etape par etape

Le lab en marche, le payload classique IMDSv1 est litteralement un GET. Depuis Burp, interceptez la requete de l'app et remplacez le parametre url par http://169.254.169.254/latest/meta-data/iam/security-credentials/. La reponse fuit le nom du role attache, disons app-server-role. Ensuite demandez http://169.254.169.254/latest/meta-data/iam/security-credentials/app-server-role et vous obtenez du JSON avec AccessKeyId, SecretAccessKey et Token. Exportez-les en variables d'environnement, lancez aws sts get-caller-identity --endpoint-url http://localhost:4566, et vous etes authentifie en tant que l'application. C'est le moment ou les blue teams bondissent de leur chaise pendant la demo, car un seul parametre non valide vient de devenir une identite de role complete.

Escalade avec des credentials voles

L'escalade depend de ce que le role peut faire. Dans notre lab, nous attachons une politique deliberement permissive avec s3:* et iam:ListRoles. Avec les creds voles, aws s3 ls revele un bucket backups-prod-2026, aws s3 cp s3://backups-prod-2026/db.dump . recupere le dump, et aws iam list-attached-role-policies mappe le chemin vers l'escalade de privileges via PassRole. Des outils comme Pacu, ScoutSuite et cloudfox automatisent cette enumeration post-compromission pour voir vite le rayon d'explosion. Horodatez chaque commande, car un rapport de bug bounty sans PoC reproductible paie zero, et une chronologie propre est ce qui transforme une trouvaille en rapport trie et paye. Si vous voulez creuser le pivoting interne apres avoir pris des credentials, Pivoting avec Chisel et Ligolo-ng : Reseaux Segmentes en Lab de Pentest est l'etape suivante.

Pourquoi IMDSv2 casse l'attaque

IMDSv2 casse l'attaque classique en exigeant une session a token. Le flux correct est un PUT sur http://169.254.169.254/latest/api/token avec l'en-tete X-aws-ec2-metadata-token-ttl-seconds: 21600, puis un GET portant l'en-tete X-aws-ec2-metadata-token. Un SSRF qui ne fait qu'un GET, sans controle sur la methode ni les en-tetes, cale simplement : il ne peut obtenir de token, donc ne peut lire de credentials. Forcez IMDSv2 avec aws ec2 modify-instance-metadata-options --http-tokens required --http-put-response-hop-limit 1. Le hop-limit de 1 est crucial : il empeche les conteneurs en reseau bridge d'atteindre IMDS via le NAT de l'hote, fermant un chemin frequent conteneur-vers-metadata. Combinez cela avec un blocage d'egress de 169.254.0.0/16 dans le security group et l'app perd toute route vers l'endpoint magique.

Defense en profondeur au-dela d'IMDS

La defense ne s'arrete pas a IMDS. Validez les URLs dans l'application, rejetant 169.254.0.0/16, 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 et fd00::/8, et resolvez le hostname avant la requete pour vaincre le DNS rebinding, puis epinglez cette IP resolue pour la connexion reelle. Utilisez une bibliotheque auditee comme ssrf-protect ou implementez-le avec getaddrinfo plus des verifications d'IP par famille ; une blocklist de strings naive se contourne trivialement avec des IPs decimales, des adresses IPv6-mappees ou des redirects. Reduisez les permissions du role au minimum, preferez IRSA sur EKS pour que les pods recoivent des credentials scoped a courte duree, activez GuardDuty pour l'usage anormal de credentials, et lancez des scanners comme Prowler regulierement. Des techniques web liees vivent dans SQL Injection en Pratique: Exploiter, Detecter et Mitiger dans un Lab Controle et XSS Moderne: DOM, Stored et Reflected avec Exemples Reels en Environnement de Test, qui avec le SSRF forment le trio le plus commun en bug bounty d'entreprise.

Detection et monitoring

Supposez que la prevention echouera de temps en temps et instrumentez pour la detection. Le vol de credentials via IMDS a un signe : le meme role IAM s'authentifiant soudain depuis une IP hors de votre infrastructure. Le finding UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration de GuardDuty est fait exactement pour ca, alors activez-le et routez-le vers un canal d'astreinte. Au niveau applicatif, loggez chaque URL sortante que le fetcher resout et alertez sur toute requete dont la destination tombe dans une plage privee ou link-local, car une recuperation legitime d'avatar ne vise jamais 169.254.169.254. Alimentez ces logs dans le meme pipeline que vos autres detections pour qu'une tentative de SSRF devienne une alerte qui sonne plutot qu'une ligne que personne ne lit.

Pieges frequents

Les erreurs recurrentes meritent d'etre nommees. Les equipes bloquent le string litteral 169.254.169.254 et ratent 2852039166, sa forme decimale, ou un hostname controle par l'attaquant qui s'y resout. Elles valident l'URL une fois, puis suivent des redirects qui pointent droit vers le metadata service. Elles forcent IMDSv2 sur les nouvelles instances mais laissent une longue traine d'anciennes en optional. Elles mettent le hop-limit mais oublient la regle d'egress, ou l'inverse. Et elles accordent au role d'instance bien plus que necessaire, si bien qu'une breve fuite de credentials devient une compromission totale du compte. La defense en profondeur existe precisement parce que chacun de ces points echouera un jour.

Checklist de durcissement

Deployez ceci aujourd'hui : lancez aws ec2 describe-instances --query 'Reservations[].Instances[].[InstanceId,MetadataOptions.HttpTokens]' sur votre inventaire maintenant, et toute instance renvoyant optional est exposee au SSRF classique ; forcez required en masse via un SSM Automation Document ; mettez le hop-limit a 1 ; ajoutez un blocage d'egress pour 169.254.0.0/16 ou c'est faisable ; auditez les roles avec des politiques *:* et reduisez-les ; validez et epinglez les URLs sortantes dans l'app avec une bibliotheque auditee ; activez GuardDuty et routez le finding d'exfiltration vers l'astreinte ; et ajoutez un test E2E en CI qui tente d'atteindre 169.254.169.254 depuis le conteneur de l'app et fait echouer le build sur une reponse 200.

FAQ : IMDSv2 seul suffit-il a arreter le SSRF ?

IMDSv2 defait le chemin specifique SSRF-vers-vol-de-credentials quand le SSRF se limite a de simples GET, ce qui couvre la grande majorite des cas reels. Ce n'est pas un correctif SSRF complet. Un attaquant capable de controler methodes et en-tetes, ou qui pivote vers d'autres services internes qu'IMDS, garde de la marge. Traitez IMDSv2 comme un controle obligatoire et de grande valeur, puis ajoutez validation d'URL, roles au moindre privilege et restrictions d'egress pour que le metadata service ne soit pas votre seule ligne de defense.

FAQ : Puis-je m'entrainer sans facture AWS ?

Oui. LocalStack Pro vous donne EC2, IAM, STS et S3 plus un mock de metadata, qui reproduit environ 95% de l'apprentissage sans depense cloud et sans risque de toucher quoi que ce soit qui ne vous appartient pas. Gardez l'app Flask vulnerable et le mock de metadata strictement sur un reseau docker local. Quand vous voudrez finalement une fidelite maximale pour un cas limite precis, une vraie t3.micro coute quelques centimes l'heure, mais ne pointez jamais cet outillage vers une infrastructure que vous n'etes pas autorise a tester.

Conclusion

A retenir concretement : il faut environ dix-sept minutes pour reproduire le pattern Capital One dans le lab, et il faut les memes dix-sept minutes pour fermer le trou en production. Lancez la requete d'inventaire maintenant, forcez IMDSv2 partout, reduisez les roles trop permissifs, validez les URLs sortantes dans vos apps, et ajoutez le test CI qui fait echouer le build si le conteneur de l'app atteint 169.254.169.254. Le SSRF contre les metadata cloud n'est pas exotique ; c'est un probleme de configuration par defaut avec un correctif bien compris. Les equipes qui subissent une breche ne sont pas celles qui manquaient de connaissances, mais celles qui n'ont jamais lance la requete.

Related posts

Nenhum comentário ainda

Seja o primeiro a comentar.

Deixe seu comentário

Entre com sua conta Canverly para comentar. Você pode usar a mesma conta em qualquer site da rede.

Entrar com Canverly