jueves, 27 de diciembre de 2012

Bypass de filtros XSS con más de una variable. Caso práctico con Chrome

Como sabéis, tanto Chrome como Internet Explorer incluyen filtros para detectar y bloquear ataques de Cross Site Scripting reflejado (los que llevan el script de regalo incluido en la URL). Firefox, por el contrario, no incluye ningún filtro para estos casos y se hace necesario instalar alguna extensión como "NoScript" para respirar más tranquilos. Siempre he pensado que Chrome es un navegador estupendo para NAVEGAR, y que Firefox es un navegador estupendo para PENTESTING. Esto se debe a que si haces un pentest centrándote en Chrome, quizá te esté vendando los ojos bloqueando la ejecución de ciertos ataques que en otro navegador sí que tendrían éxito, aunque lo ideal, lógicamente, sea probar los ataques en todos los navegadores posibles.

A lo que vamos...

Los filtros basados en expresiones regulares para detectar un conjunto de elementos peligrosos siempre dan y darán mala espina. Por un lado, si al programador se le escapa un solo caso entre la gran cantidad de combinaciones posibles, estamos jodidos. Por otro lado, tenemos una dificultad añadida si ese conjunto de elementos peligrosos es variable en el tiempo (véase XSS cheatsheet para HTML5).
Si os fijáis, muchos filtros AntiXSS están enfocados a elementos aislados. Trabajan a grandes rasgos así:

Sin embargo, una página web completa conforma su comportamiento en base a su CONJUNTO de etiquetas y variables. Puede que una variable por sí sola no sea peligrosa, pero sí cuando se junta con sus colegas (como le pasa a más de uno en la vida real):


Al señor Nick Nikiforakis se le ocurrió que con esta idea podría llegar a saltarse el filtro para XSS reflejado de Chrome y, de hecho, lo consigue. A pesar de que Chrome se curó de sus primeros balazos basados en esta idea, Nick Nikiforakis siguió actualizando sus ataques y, a día de hoy, aún funciona el método que se muestra a continuación.




Esto es debido a que, por un lado, la variable 'a' se encarga de introducir simplemente <script>void('. Chrome no la considera peligrosa por sí sola y la deja pasar. Todo lo que venga después en la página quedará dentro de la función void y será "ignorado". Ahora necesitamos cerrar la función, ejecutar nuestra sentencia javascript y finalmente introducir al amigo </script>. De esto se encarga la segunda variable 'b', que toma el valor ');alert('XSS');</script>. Chrome tampoco la considera peligrosa por sí sola. Lógicamente, cuando las variables se encuentran finalmente juntas en la página renderizada, provocan la ejecución del script, habiendo explotado con éxito un XSS reflejado saltándonos el filtro correspondiente de Chrome.

Esta idea no sólo me parece interesante para saltarse este filtro. Me parece interesante tenerla en cuenta para cualquier sistema de filtros cuyas variables estén siendo revisadas de forma aislada y vayan a parar, finalmente, a un sistema donde interactúen como un conjunto.
Imaginaos cualquier formulario web con varios campos para rellenar, los cuales van a ser revisados uno a uno por un filtro contra XSS persistente y que, finalmente, van a ir a parar a la misma página para ser mostrados. Quizá, nuestro primer intento de introducir un XSS en cada una de las variables aisladas haya fracasado, pero siempre nos queda intentar construirlo jugando con más de una, procurando evitar escribir en un solo campo lo que el filtro considera peligroso.

¿Soy el único al que le parece interesante introducir estos métodos en los scanners automáticos de XSS?

Saludos!

2 comentarios: