IMDSv2 exige un jeton de session à courte durée de vie obtenu avec un PUT, puis renvoyé dans un en-tête à chaque lecture. C'est trivial depuis un shell sur l'instance, et toujours atteignable depuis un SSRF lorsque la primitive de requête peut émettre un PUT et définir l'en-tête du jeton.
Le flux de jeton#
TOKEN=$(curl -sX PUT "http://169.254.169.254/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
ROLE=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/iam/security-credentials/)
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE
Notes d'exploitation#
- L'exigence du
PUTet de l'en-tête personnalisé bloque les primitives SSRF les plus simples ; un SSRF avec request-smuggling complet ou en-tête contrôlable la satisfait tout de même. - Le TTL du jeton peut atteindre six heures, de sorte qu'un seul jeton couvre une longue session de lectures.
- Une hop-limit de 1 est courante ; un SSRF depuis un conteneur sur l'hôte peut échouer à la vérification de saut alors qu'un shell sur la machine réussit.
- Les credentials de rôle récupérés débloquent ensuite les API qui renvoient des credentials (
sts:AssumeRole,ecr:GetAuthorizationToken,sso:GetRoleCredentials, et les autres) pour élargir l'accès ; voir courtiers de credentials.
Outils#
- curl sur l'instance, ou une primitive SSRF avec contrôle de la méthode et des en-têtes.
- Pacu (
ec2__metadata) : gère automatiquement la danse du jeton.