Ghost AcademyGhostOffensive · Ghost Academy
GhostOffensiveMódulo 08Con laboratorio

Ataques del lado cliente

Hasta ahora casi todo ocurría en el servidor. Este módulo se traslada al otro extremo: el navegador de la víctima. Muchas vulnerabilidades no viven en la base de datos ni en el sistema de ficheros, sino en cómo una página trata el contenido que muestra, las peticiones que acepta o los mensajes que recibe.

Objetivos de la unidad

1. Cross-Site Scripting (XSS): ejecutar tu código en la víctima

Un XSS consiste en lograr que el navegador de otra persona ejecute JavaScript que tú controlas, en el contexto (y con los permisos) de la web vulnerable. La causa de fondo es siempre la misma que en las inyecciones del módulo 6: contenido no confiable acaba interpretándose como código (HTML/JS) en lugar de como texto. Se clasifica por dónde vive el dato:

TipoDónde vive el dato maliciosoA quién afecta
ReflejadoViaja en la propia petición (un parámetro de URL) y se devuelve sin escapar en la respuesta.Solo a quien abre un enlace manipulado que le envías.
AlmacenadoSe guarda en el servidor (un comentario, una biografía) y se sirve después.A todos los que visiten esa página. El más grave.
Basado en DOMNunca llega al servidor: JavaScript del cliente lee algo de la URL (location.hash) y lo inserta en la página.A quien abre el enlace, sin que el servidor lo vea siquiera.
kali@lab
$ http://objetivo/buscar?q=<script>alert(1)</script>   # prueba de concepto

Qué se hace realmente con un XSS. El alert(1) solo demuestra que ejecuta; el impacto real es otro. Como el script corre en el contexto de la víctima, puede: robar su cookie de sesión (document.cookie, si no es HttpOnly) y enviársela al atacante para suplantarla sin su contraseña; actuar en su nombre haciendo peticiones autenticadas (lo que además elude el CSRF, porque el script ya está dentro del origen); leer lo que ve en pantalla; o registrar sus pulsaciones. Por eso un XSS almacenado en una página que ve un administrador puede ser el principio de un compromiso total.

Filtrar es difícil, escapar es lo correcto. Intentar bloquear <script> es un juego perdido: hay decenas de vectores (<img src=x onerror=...>, atributos de evento, javascript:...). La defensa real es escapar según el contexto donde se inserta el dato (HTML, atributo, JavaScript, URL tienen reglas distintas) y usar CSP como red de seguridad (ver sección 6).

2. CSRF: el navegador confía de más

CSRF se apoya en una consecuencia del diseño del navegador que viste en el módulo 5: el navegador adjunta automáticamente las cookies del dominio destino en cada petición, sin importar qué página la originó. Así, si estás logueado en tu banco y visitas una web maliciosa, el JavaScript (o incluso un simple <img> o un formulario auto-enviado) de esa web puede lanzar una petición a tu banco y tu cookie de sesión viajará con ella. Si la acción (transferir, cambiar el correo) solo exige esa cookie, se ejecuta en tu nombre sin que tú lo sepas.

Defensa: un token anti-CSRF único e impredecible por sesión, exigido en cada acción que cambie estado; la web atacante no puede conocerlo (la SOP le impide leer la respuesta que lo contiene). El atributo de cookie SameSite (sección 5) ataca la misma raíz desde el otro lado. Nota clave: si la web tiene un XSS, el CSRF token no salva nada, porque el script atacante ya está dentro y puede leerlo.

3. Clickjacking

Consiste en incrustar la página legítima en un <iframe> transparente encima de un señuelo, de modo que la víctima cree pulsar un botón inocente cuando en realidad pulsa sobre la página real (confirmar un pago, dar un permiso). No roba datos: secuestra clics. Se evita diciendo quién puede enmarcar la página:

Cabecera de respuestaEfecto
X-Frame-Options: DENYNadie puede enmarcar la página (cabecera antigua, aún válida).
Content-Security-Policy: frame-ancestors 'self'Solo el propio sitio puede enmarcarla. Es la forma moderna y más flexible.

4. Redirección abierta

Ocurre cuando un parámetro decide a dónde redirige la aplicación sin comprobar que el destino sea de confianza. Su gracia no es técnica sino de engaño: el enlace empieza con el dominio legítimo (banco.com/ir?next=...), la víctima lo reconoce y confía, pero acaba en la web del atacante. Es un multiplicador del phishing, y a veces un peldaño para robar tokens de OAuth. La defensa: no redirigir a URLs arbitrarias del usuario; usar una lista blanca o rutas relativas internas.

kali@lab
$ curl -I 'http://objetivo/ir?next=https://sitio-falso.test'   # mira la cabecera Location

5. Cookies bien configuradas

Tres atributos, cada uno contra un ataque concreto de este módulo:

AtributoQué evita
HttpOnlyQue JavaScript lea la cookie con document.cookie. Corta el robo de sesión vía XSS (sección 1).
SecureQue la cookie viaje por HTTP sin cifrar, donde podría interceptarse.
SameSite (Lax/Strict)Que la cookie se envíe en peticiones originadas por otro sitio. Ataca la raíz del CSRF (sección 2).

No son opcionales ni intercambiables: una cookie de sesión debería llevar HttpOnly; Secure; SameSite=Lax como mínimo.

6. Content-Security-Policy: la red de seguridad contra XSS

La CSP es una cabecera que le dice al navegador de qué orígenes puede cargar y ejecutar recursos (scripts, estilos, imágenes). Una política que solo permita scripts del propio dominio hace que, aunque un atacante consiga inyectar un <script>, el navegador se niegue a ejecutarlo. No sustituye a escapar la salida —es defensa en profundidad—, pero convierte muchos XSS explotables en intentos fallidos. Entender que existe te ayuda tanto a atacar (ver qué permite una CSP mal hecha) como a recomendar la defensa correcta en el informe.

7. Comunicación entre ventanas: postMessage

postMessage es la vía legítima para que dos ventanas o iframes de orígenes distintos se comuniquen, saltándose la SOP de forma controlada. El fallo aparece cuando quien recibe el mensaje no comprueba event.origin: entonces acepta mensajes de cualquier página, incluida una maliciosa. Y si además inserta ese mensaje en el DOM sin escaparlo (innerHTML), se convierte en un XSS de origen cruzado. La regla al recibir es doble: validar siempre event.origin contra una lista de orígenes esperados, y tratar el contenido del mensaje como dato no confiable.

Para profundizar
🧰 Herramientas relacionadas (Ghost Academy)

Guías y laboratorios ya publicados en Ghost Academy sobre las herramientas de este módulo:

XSS educativo · Client Side Security

Laboratorio: Pulsar Social

⬇ Descargar laboratorio (ZIP)

Descomprime, lee el LEEME.md y lanza startlab.sh. Encontrarás 8 flags GO{...}: XSS reflejado, almacenado y por DOM, CSRF, clickjacking, redirección abierta, cookie mal configurada y postMessage sin validar. Verifícalas en http://localhost:8585/verificador.

¿Atascado o ya terminado? La solución paso a paso revela todas las flags. Úsala cuando lo hayas intentado.

Autoevaluación

  1. Más allá del alert(1), ¿qué tres cosas puede hacer de verdad un atacante con un XSS?
  2. ¿Por qué un XSS basado en DOM puede existir aunque el servidor haga todo correctamente?
  3. ¿Por qué un token anti-CSRF no protege nada si la web también tiene un XSS?
  4. ¿Qué atributo de cookie ataca la raíz del CSRF y cuál corta el robo de sesión vía XSS?
  5. ¿Qué cabecera evitaría que tu banco se pudiera incrustar en un iframe ajeno?
  6. ¿Cómo ayuda una CSP a contener un XSS aunque el atacante logre inyectar un <script>?
  7. ¿Por qué event.origin es imprescindible al recibir un postMessage?