viernes, 20 de febrero de 2015

De Case-Insensitive a RCE

Este post ha sido escrito por The DarkRaver, un buen amigo y uno de los profesionales de la seguridad más capaces que he conocido jamás. También es conocido por haber publicado herramientas como dirb o sqlibf que recomiendo que probéis.

Vayamos con su post:

------------------------------------------------------

Hace algún tiempo estaba haciendo un test de intrusión a una webapp cuando encontré algo realmente interesante. La aplicación estaba programada en PHP pero contenía algunos componentes comerciales. Pronto encontré muchos formularios vulnerables a XSS y SQLi, pero no nos vamos a centrar en eso en este post.

De repente me di cuenta que solicitando la misma página en mayúsculas o en minúsculas la respuesta que obtenía era diferente. El servidor web estaba basado en Apache y Linux (case sensitive) mientras que los ficheros parecían estar en un sistema de ficheros case insensitive (¿quizá una carpeta compartida en una NAS?), así que cuando solicitaba page.php me respondía como es de esperar, pero cuando solicitaba page.PHP se mostraba el código fuente de la página.


Esta vulnerabilidad permitió revisar el código fuente de algunos de los componentes comerciales de la aplicación, donde encontré varias funciones potencialmente peligrosas como "include()" o "include_once()" que podrían ser vulnerables. No se encontraron otro tipo de funciones peligrosas como "system()", "open()" o "file_get_contents()".

Unos pocos minutos después pude confirmar que al menos uno de esos "include_once()" era vulnerable a LFI y completamente explotable. Sin embargo, solo podíamos cargar ficheros con extensión .js (JavasScript).


Intenté evadir esta protección empleando el caracter nulo, paths largos, etc, pero nada parecía funcionar. Así que... estamos atados a esta extensión ¿Cómo podríamos subir or crear un fichero .js local?

Los formularios para subir ficheros no permitían esta extensión, así que no era capaz de crear ficheros en el servidor ¿O quizá sí? ¿Qué hay de este trozo de código?


¡Era una funcionalidad que permitía cachear ficheros JavaScript en disco! Pero... ¿Cómo podríamos injectar contenido en esos ficheros?

Un vistazo más en profundidad mostró que algunos ficheros eran generados a partir de una plantilla, y una de ellas incluía algunos parámetros controlados por el usuario ¡Genial!


Aún mejor, el parámetro injectable era el mismo que era vulnerable a LFI, así que solo tuvimos que encontrar una manera de explotar ambas vulnerabilidades al mismo tiempo.

Los ficheros JavaScript estaban almacenados en un path del estilo "/cache/".$offv.$theme.$lang.$type.$name.".js" , donde $offv era el parámetro proporcionado por el usuario y el resto podían ser facilmente deducibles mirando el código fuente, con lo que el exploit quedaría de la siguiente manera:

http://www.app.com/plugin/minjs.php?
offending_var=../../cache/<?phpinfo();?>defaultes-lacoredefault

Sin embargo, me encontré con un "500 - Internal Server Error" ¿¿Qué demonios?? Algo estaba fallando de forma terrible ¿Cómo podríamos arreglarlo? Probé otras funciones PHP como "system()" "file_get_contents()" y "phpversion()" pero la mayoría de ellas fallaban de la misma forma.

Espera... quizá el exploit está funcionando pero la aplicación falla en algún otro punto posterior ¿Qué tal su probamos a incluir un "exit()"?

http://www.app.com/plugin/minjs.php?
offending_var=../../cache/<?system(“id”);exit();?>defaultes-lacoredefault


¡Bingo! Finalmente conseguí la ejecución remota de código en el servidor, y todo empetho con una pequeña vulnerabilidad que permitía visualizar el código fuente causado por un sistema de ficheros case-insensitive. Las cosas pequeñas a veces causan grandes problemas.

jueves, 5 de febrero de 2015

An IE Same Origin Policy Bypass story

Hace un par de días estaba leyendo mis feeds cuando de repente un titular llamó mi atención: "Seria vulnerabilidad en Internet Explorer totalmente parcheado expone las credenciales de los usuarios". Una técnica de evasión para el same-origin-policy de Internet Explorer había visto la luz. Este tipo de vulnerabilidades son muy críticas, ya que SOP proporciona la separación entre los diferentes sitios web dentro de nuestros navegadores, y evita que una web maliciosa pueda acceder o modificar contenido de otra web legítima.

Le he estado pegando un vistazo a la vulnerabilidad en las últimas horas y vaya si funciona. La PoC publicada funciona perfectamente pero quizá no es la proximación más práctica (real) que un atacante tomaría. Por lo que sé, no se han publicado más detalles sobre la vulnerabilidad aparte de la propia PoC, así que vamos a pegarle un vistazo al PoC. He preparado mi propia prueba de concepto simplemente para ver si era capaz de explotarla de una forma más "maléfica".


A primera vista la vulnerabilidad parece una condición de carrera o similar. Tenemos dos iframes, el primero de ellos carga una página dinámica, por ejemplo 1.php. No se ha publicado el código de esta página, pero básicamente espera durante unos pocos segundos y luego redirige a la misma URL que carga el segundo iframe.

Ambos iframes cargan una página en el website victima. Es importante encontrar una página que puede ser cargada dentro de un iframe, porque si no la vulnerabilidad no se puede explotar. Proveedores como Google, Facebook, etc, normalmente configuran sus sitios con la cabeceza "X-Frame-Options" para evitar ataques de ClickJacking, lo cual podría ser un problema.


Sin embargo, con encontrar una sola página en todo el dominio que no tenga la cabecera "X-Frame-Options" es suficiente, y eso no es tan dificil como parece. Hay dos recursos bien conocidos que no están protegidos en la mayoría de los sitios web: robots.txt (el que usa el autor original) y favicon.ico (el que uso yo para un ataque un poco más práctico).

Hay una función llamada "go()" que hace la verdadera explotación. Es dificil de leer así que permitidme que lo decodifique para vosotros.


Aquí es donde está la chicha. Hay algunas llamadas a "alert" y "eval" que parecen ser importantes. No he podido averiguar por qué pero si las cambias no funcionan. Esta parte es la más compleja de la vulnerabilidad.

Carga el segundo iframe del que hablabamos antes en la variable "x". Entonces espera unos pocos segundos (1 segundo en el código mostrado) y muestra un mensaje. Como comentaba antes, este "alert" parece ser importante así que no lo podemos borrar, pero podemos elegir un mensaje que no haga advertir al usuario que algo malo está pasando. Después de eso, cuando el primer iframe ha cambiado del atacante al sitio victima (debido a 1.php) el código Javascript y HTML es inyectado en ese segundo iframe. No deberíamos ser capaces, porque es un dominio diferente, pero lo somos. Nos hemos saltado la same-origin-policy.

Vamos a ver como lo vería una víctima:


Algunos paises tienen leyes específicas sobre cookies y los sitios web tienen que mostrar un mensaje como éste. Muchos usuarios se han acosutmbrado a ellos y simplemente pulsan aceptar.


Cuando injecté código en el iframe, utilicé un botón de google, de estos que se usan para autenticarte en sitios externos. Puede que no sea el blog más bonito del mundo, pero... parece un blog de verdad :)


Se abre la pantalla de autenticación de Google. Todo parece correcto pero el javascript debería haber cambiado al "action" del formulario de login, con lo que las credenciales deberían ir a un dominio diferente.


¡Hecho! Una vulnerabilidad realmente interesante. No puedo esperar a que salgan más detalles de la vulnerabilidad y ver porque los "alert", "eval" y "setTimeout" son tan importantes.