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.

3 comentarios :

Unknown dijo...

Muy buen amigo, por favor, nunca deja de presentar con su inteligencia ... gracias

Unknown dijo...

me parece muy interesante este articulo

Anónimo dijo...

muchas gracias por compartir