📝 Description
On se retrouve face à un challenge où il faut exfiltré un code OTP (One Time Password) uniquement avec du CSS, car malgré une injection d’HTML les CSP (Content Security Policy) nous bloquent. Le code OTP change à chaque requête et seul le bot (grâce a ses cookies) peut enregistrer un user associé au code OTP.
🔎 RECON
HTML INJECTION
A l’arrivé sur le site web du challenge je regarde les CSP :
|
|
on remarque aussi qu’un script est chargé sur la page, le voici :
|
|
Ok on peut observer que le script regarde si l’URL contient un param page. Si oui il fetch le contenu du param et mets la réponse dans la div avec la class .message. Juste après le script enlève toute les balises style.
Je test avec une URL que je controle et on a bien notre HTML Injection.

BYPASS LE REMOVE DES <STYLE>
Après de longues recherches le ✨DOM Clobbering✨ me permet enfin de pouvoir mettre mes balises styles ! Grâce au ✨DOM Clobbering✨ il est possible de générer des variables globales dans le contexte JS avec les attributs id et name dans les balises HTML. On peut en quelque sorte écraser la valeur précédente.
|
|
Une image vaut mille mots :

Maintenant je peux mettre des balises style 🙂
BYPASS DU OTP QUI CHANGE
La valeur du OTP se trouve dans un input :
|
|
Souvent pour exfiltrer des données avec du CSS on s’y prend comme ça :
|
|
Cette technique est bien mais dans notre cas elle ne fonctionne pas car à chaque requête la valeur du OTP change.
✨bfache✨ (Back/forward cache)
Quand on fais un retour en arrière sur un navigateur le cache est utilisé pour ne pas avoir a re fetch la page web. On va pouvoir utiliser ce cache pour bypass le changement de valeur.

Maintenant il reste plus qu’à créer un exploit.

💥 Proof of Concept
Résumons :
- Un serveur pour send le CSS et recevoir les valeurs.
- Une page HTML qui open le site avec l’injection HTML et qui l’envoie sur une page qui fera un history.go(-1).
Pour exfiltrer les données avec le CSS on crée un endpoint /test qui enregistre les caractères reçus dans un fichier.
On crée aussi un endpoint /exfil qui envoie le nouveau CSS avec les précédent caratères + chaque caractère de l’alphabet.
On oublie pas le header Cache-Control: no cache qui empéchera notre CSS d’être mis en cache.
|
|
Voici le code permettant d’ouvrir une nouvelle fenetre qu’on pourra par la suite manipuler :
|
|
Le code de la page sur laquelle on envoie le bot tous les 500ms qui fera un history.go(-1) afin d’utiliser le bfcache :
|
|
On envoi notre index.html au bot et voilà on reçoit les caractères du OTP à chaque fois que le browser fais un backward et use le cache ! lactf{masterfu3_para7737_css_exf1l7ration}
PS: apparement cette manière de solve le chall était unintended. J’ai aussi eu de la chance que le bot accepte les open (activé par default sur les bots puppeteer) et qu’il reste suffisament de temps pour que je puisse exfil les données.
La façon attendue était d’exfiltrer des trigrammes à l’aide du CSS. Plus de détails ici.