Nuevos labs cada semana — Accede a todos desde 5€/mes

Nivel AvanzadoGratis

Reflected XSS en página 429 vía Google Analytics — el snippet de tracking como vector

El snippet de Google Analytics tomaba parte de la URL como input sin sanitizar. Un breakout de string literal dentro del propio script: la inyección estaba ya en contexto JavaScript.

Gorka El Bochi9 de mayo de 20269 min

Respuesta rápida

La página de error 429 (Too Many Requests) de un subdominio de una red social Q&A reflejaba parte de la URL dentro del bloque <script> de Google Analytics, sin sanitizar. Como el input ya estaba en contexto JavaScript, no hacía falta romper HTML: bastaba romper el string literal con '-alert(document.domain)-'. Reflected XSS clásico, pero el vector — el snippet de GA — es interesante.


1. Contexto — la página de error 429

Cuando un usuario realiza demasiadas peticiones a un subdominio de la plataforma, el servidor devuelve una página de error 429. Esta página incluye un snippet de Google Analytics que toma parte de la URL como input para construir sus llamadas de tracking.

El problema es que ese valor de la URL se inserta directamente dentro del bloque <script> de Google Analytics sin ningún tipo de sanitización, convirtiéndose en un punto de inyección de JavaScript.


2. El payload y la URL vulnerable

bash
https://subdomain.target.tld/'-alert(document.domain)-'

La parte de la URL después de la barra ('-alert(document.domain)-') se refleja directamente dentro del script de Google Analytics en la respuesta HTTP.


3. El código vulnerable en la respuesta

html
<script type="text/javascript">
  ...
  ga('set', 'dimension1', 'board-'-alert(document.domain)-'');
  ga('set', 'dimension2', 'False');
  ga('set', 'dimension3', 'False');
  });
});
</script>

El valor de la URL se concatena dentro de un string literal JavaScript entre comillas simples. El payload cierra la comilla de apertura con ', inyecta la llamada a alert(document.domain) con concatenación de strings (-alert(document.domain)-), y reabre la comilla para que el resto del código sea sintácticamente válido.

Desglose del payload

lua
dimension1', 'board-   ← string original hasta donde llega el input
'-alert(document.domain)-'input del atacante

La secuencia resultante en el script es:

javascript
ga('set', 'dimension1', 'board-' - alert(document.domain) - '');

JavaScript evalúa -alert(document.domain)- como una operación aritmética, lo que fuerza la evaluación de alert(document.domain) como parte de la expresión. El resultado aritmético no importa — lo que importa es que alert(document.domain) se ejecuta.


4. Condición para triggear el XSS

La página de error 429 solo se muestra cuando el servidor detecta demasiadas peticiones desde el mismo cliente. Para que la víctima cargue la página vulnerable, primero tiene que estar en rate limit. En la práctica esto se consigue de varias formas:

  • El atacante envía muchas peticiones previas desde la IP de la víctima (no trivial).
  • La víctima ya está en rate limit de forma natural por su propio uso.
  • Se envía directamente el link cuando ya está en estado 429.

5. Clasificación técnica

CampoValor
Tipo de vulnerabilidadReflected XSS — Input reflejado en bloque <script>
CWECWE-79 — Improper Neutralization of Input
VectorSegmento de URL reflejado en snippet de Google Analytics
PersistenciaReflected — se activa solo al cargar la URL maliciosa
Condición previaEstado 429 (rate limit) activo en el cliente

6. Notas técnicas

  • El XSS está dentro de un bloque <script> existente, no en un atributo HTML. Esto lo hace especialmente directo: no hace falta salir de un contexto HTML, el input ya está dentro de un contexto JavaScript donde cualquier código es ejecutable directamente.
  • El vector es el snippet de Google Analytics, un bloque de código de terceros que la plataforma incluía en sus páginas de error. La superficie de ataque está en cómo la app construía los parámetros pasados a ga() usando datos de la URL sin escapar.
  • La condición del 429 limita ligeramente la explotabilidad respecto a un Reflected XSS sin condiciones previas, pero no la elimina — la URL maliciosa sigue siendo crafteada por el atacante y compartible.

Lección general

Cuando un valor del cliente acaba dentro de un bloque <script>, el vector ya está medio cocinado: solo necesitas romper el contexto del string literal que lo contiene. No mires solo HTML cuando audites páginas de error o snippets de tracking — el contexto JavaScript es donde menos sanitización suele haber.


Labs relacionados

Practica reflected XSS en script blocks y bypasses con concatenación aritmética: labs de XSS.

Practica esto en un lab

Xss

Resolver

Sigue aprendiendo · cuenta gratis

Guarda tu progreso, desbloquea payloads avanzados y rankea tus flags.

Crear cuenta

Artículos relacionados