lunes, 10 de septiembre de 2012

Bypassing .NET Request Validation

Hace un par de semana leía ESTE artículo de Zamir Paltiel en el que comentaba haber descubierto una nueva forma de evadir la seguridad proporcionada por el Request Validation de .NET para realizar ataques de Cross Site Scripting (XSS).

Como ya sabéis, las aplicaciones web desarrolladas en entornos .NET (típicamente ASP.NET) tienen una serie de medidas de seguridad que vienen aplicadas por el framework y por defecto, lo cual dificulta algunos tipos de ataques a pesar de que existan vulnerabilidades en el código.

Una de las protecciones que proporciona el framework es el Request Validation (ver documentación oficial AQUÍ o la publicada por owasp AQUÍ). Esta protección, que como comentamos viene activada por defecto, filtra determinados caracteres en las entradas de datos de los usuarios que podrían ser utilizados para realizar ataques de scripting. Veamos, sacado de la guía OWASP, que caracteres son esos:


La guía OWASP no mencionada nada de versiones posteriores de ASP.NET, como la 4.0, pero si buscamos un poco podemos encontrar AQUÍ como parece que no ha habido diferencias en cuanto a los caracteres filtrados, aunque sí se ha ampliado el "espectro" de entradas a las que se le aplica esta protección.

En resumidas cuentas, a pesar de que en el código fuente exista una vulnerabilidad de XSS, si el desarrollador o administrador no ha deshabilitado la protección de Request Validation vamos a tener que no vamos a poder explotarlo con ninguna cadena que contenta el símbolo de abrir tag seguido de cualquier letra, el símbolo de admiración o la barra del tag cerrado. Si lo hacemos, nos encontraremos con un bonito error como el siguiente:


¿Cómo podemos evadir esta protección? Pues... en general, podríamos hablar de que tenemos dos opciones. La primera es aprovecharnos de que no en todos los XSS es necesario abrir y cerrar tags, así que eso nos da una opción para explotarlo según donde se encuentre la vulnerabilidad dentro del código HTML. Esta no creo que la pudiéramos considerar como "saltarse la protección", sino más bien como darse la vuelta y buscar otra puerta por donde entrar.

La otra opción es encontrar una forma de abusar de la flexibilidad que tienen los lenguajes HTML y Javascript, y de la tolerancia a fallos que tienen los navegadores para encontrar alguna forma "extraña" de ejecutar el script que sea aceptada por los navegadores pero que no siga la forma típica. En general, al ser formas "enrevesadas", suele pasar que solamente funcionan en un tipo concreto de navegador, ya que están un poco "fuera del estandar".

En este caso, Zamir Paltiel ha encontrado una forma de evadir esta protección y explotar XSS's en navegadores Internet Explorer, de la siguiente forma:


El tag "tag", con el símbolo porcentaje delante, es interpretado como un tag HTML correcto por Internet Explorer, por lo que es posible emplear las técnicas habituales, como por ejemplo utilizar el parámetro "style" para introducir la ejecución de un Alert en Javascript:


Como siempre, quien dice alert dice robo de credenciales o cualquier otra cosa, siempre y cuando no empleemos alguno de los otros caracteres "prohibidos" que harán saltar las protecciones de Request Validation.

Para un Pentest, digamos que con esto hemos cumplido, hemos encontrado un fallo en la aplicación que podemos explotar a pesar de las protecciones del framework. En el mundo real, los navegadores (o módulos adicionales como NoScript) disponen de protecciones anti-XSS que pueden impedir esta ejecución, así que habría que encadenar este bypass que hemos comentado en este post con el bypass de estas protecciones anti-XSS. Si os interesa un ejemplo de como saltar protecciones anti-XSS, a mi me gustó mucho el Write-Up que escribió Pepelux al reto de Infiltrados de Informática64, cuya primera fase trataba 100% sobre este tema.

12 comentarios :

Adrián dijo...

La verdad es que el filtro es relativamente inútil en la mayoría de los casos (debido a que suelen aparecer este tipo de ténicas), pero sobretodo debido a que los desarrolladores confían en el filtro y no implementan otras medidas, con lo que encontrar otros puntos donde no haga falta abrir tags.

Jose Selvi dijo...

@Adrián: Completamente de acuerdo!

Con estas protecciones, en ocasiones, ocurre como en el experimento de los taxistas de Munich.

Para el que no se conozca la historia: A principios de los 80 se hizo un experimento instalando un nuevo sistema de frenada (el ABS) a la mitad de los taxistas de Munich para comprobar su efectividad. El resultado fue, sorprendentemente, que los taxistas a los que se les instaló el ABS tenían MÁS accidentes que los que no lo llevaban ¿Por qué? Porque se dieron cuenta de que sus coches frenaban más y redujeron la distancia de seguridad con respecto al coche de delante, con lo que al final...

Algo muy similar ocurre en la seguridad con estas protecciones, y también con los IPS/WAF, y eso que el propio Microsoft dice bien claro en la documentación en la que explica las protecciones que estas no substituyen a un buen filtrado de caracteres de entrada.

n3k dijo...

Hola, tu has probado con la versión del framework 4?.
He intentado reproducir el ataque levantando un asp webform con .net 4, pero no he tenido éxito.

Esto es lo que tiene mi webform:

http://imageshack.us/photo/my-images/855/xsstest.png/

Desde IE, coloco esto en el textbox:
<%tag style="foo:expression(alert('ASD'))" >

Si bien no se refresca el Label1, tampoco aparece el dialog de alert().

Jose Selvi dijo...

@n3k: Con la v4.0 no lo he probado, pero a priori debería funcionar igual. Igual el filtro anti-XSS te lo está parando ¿Puedes mandarnos qué código HTML te devuelve la página?

Si no funcionara como tal debería saltarte un error como el que he puesto en el post, sino es que igual no te funciona por el filtro anti-XSS o la versión del navegador ¿Qué versión usas?

n3k dijo...

Probé con una version de IE 9.0.8112.

No me da ningun error, es como que no salta el alert() nada más.
No se setea la propiedad Text de Label1 (o bien no se muestra en el navegador).
Es decir, si pongo el string "Hola" aparece "Hola". Le pongo el string de prueba, y no hace nada.
No estoy usando nada arriba del framework, es decir, no estoy usando anti-xss de ningun tipo.

n3k dijo...

Este es el codigo fuente generado:

http://imageshack.us/photo/my-images/31/codigofuentexsstest.png/

Gracias por responder,
Saludos!!

Jose Selvi dijo...

@n3k: He estado pegando un vistazo a las capturas que me has pasado y tengo dos comentarios que hacerte:

1) ¿Estás seguro que el código que has escrito está protegido por Request Validation? Estás cambiando el contenido de un parámetro por otro, no sé si así aplica esta protección, prueba esta cadena a ver: < script>alert(1234) (pongo espacios dentro del tag, que sino Google no me deja) Si esto te salta es que la protección no funciona si cambias el contenido así a saco.

2) He probado a coger el código que te devuelve, meterlo en un fichero HTML local y acceder a él, y a mi SÍ que me salta el alert. También podría ser porque esté dentro del tag SPAN, que hay tags que impiden que el navegador interprete nada dentro de ellos, pero yo antes descartaría que sea por el navegador (sus filtros anti-XSS o lo que sea, que como ponía en el post eso ya es otra batalla).

n3k dijo...

Jose: si intento escribir un xss normal sucede esto
http://imageshack.us/photo/my-images/707/requestvalidation.png/

Se puede ver que es la misma validación.
Por otro lado, si dices filtros del mismo navegador, he probado crear un html con el código siguiente:

http://imageshack.us/photo/my-images/253/htmlxss.png/

Y con eso, abriendo con el mismo navegador, SI salta el alert().

De todos modos, voy a probar con otra versión de IE y posteo lo que sucedió :).

Saludos!!

Jose Selvi dijo...

@n3k: Entonces casi seguro que es el filtro anti-XSS de tu IE9. La evasión de estos filtros... da para otro post, pero tienes una buena referencia en el enlace que he puesto al Write-Up de pepelux.

n3k dijo...

@Jose: Gracias por responder, seguramente sea eso; voy a ver ese artículo que mencionas.

Saludos!!

Anónimo dijo...

Si quitas el DOCTYPE si que funciona, asi que supongo que al no ser una etiqueta estandar no la interpreta.

Anónimo dijo...

Aqui está explicado el porqué no te funciona.

http://www.securitysift.com/xss-and-cross-site-scripting-with-a-little-help-from-asp-net-and-ie9/