lunes, 21 de marzo de 2016

Bypassing disable_functions y open_basedir en PHP

¡Saludos!

      A raíz de un CTF descubrí esta pequeña triquiñuela para bypassear estas protecciones. Si alguien quiere leer el write up completo que hizo nuestro compañero @cgvwzq de ka0labs lo teneis en  https://blog.ka0labs.net/post/33/ , es bastante interesante.


      Por ponernos en contexto, open_basedir va limitar las rutas a las que vamos a poder acceder desde nuestro PHP, lo que se traduce de forma efectiva en que estamos "enjaulados" en cuanto a sitios donde poder tocar: no podríamos, por ejemplo, leer un archivo que está en un nivel superior a la cota marcada por esta directiva.

     En el otro lado tenemos disable_functions que es utilizada para evitar el abuso de las funciones system(), exec(), proc_open(), etc. En el momento en el que se meten en la lista negra TODAS las funciones que permiten ejecución de comandos / programas nuestra webshell está extremadamente limitada, puesto que únicamente vamos a poder crear archivos dentro de lo que permita open_basedir pero no ejecutarlos. Necesitamos bypassear estas protecciones de alguna forma para saltar de un eval() a un system().

     El concepto es bastante viejo, al aparecer, y viene reflejado en este ticket abierto en el bugtracker de PHP en 2008 (https://bugs.php.net/bug.php?id=46741). La idea es utilizar LD_PRELOAD para cargar una librería que haga el bypass. Seguro que estás pensando algo tipo "WTF???? LD_PRELOAD EN UN PHP??????". Vayamos por partes.

    En primer lugar setear la variable de entorno LD_PRELOAD nos va a permitir hookear cualquier función que proceda de una librería linkada dinámicamente. Al setear LD_PRELOAD con putenv cualquier programa que ejecutemos desde este PHP va a tener ya esta variable de entorno y podremos hookealo. Ahora bien, ¿si el problema que teníamos era que no podíamos ejecutar nada, cómo diablos arregla esto el problema? La magia de PHP y la función mail().

  Si consultamos la documentación de PHP nos encontramos con este bonito párrafo:

Nota:
La implementación en Windows de mail() difiere bastante de la implementación en Unix. Primero, no usa un binario local para componer mensajes ya que sólo opera en sockets directos, lo que significa que es necesario un MTA escuchando en un socket de red (que puede estar tanto en localhost como en una máquina remota). 


        O sea, que mail() en realidad llama a un binario para mandar el e-mail en el caso de Linux, concretamente ejecuta (por defecto, esto se puede cambiar en php.ini) el enlace simbólico /usr/sbin/sendmail. Oh la lá! ¡Ya estamos ejecutando un programa externo desde nuestro PHP, y cuando ejecute /usr/sbin/sendmail podremos hookear sus fuciones con LD_PRELOAD y nuestra librería molona! Localicemos alguna función golosa con strace:

   
       Ese geteuid() parece bastante goloso. Nos picamos una cutre librería que levante una shell inversa al llamar a esta función, y en el PHP con putenv y mail hacemos la magia.


He picado un pequeño PoC ( https://github.com/0verl0ad/sifilis-PoC ) para que se vea fácilmente como chutaría (editad al gusto).

      Espero que os sea de utilidad en vuestros test de intrusión ;)


Byt3z!
5 0verl0ad Labs: Bypassing disable_functions y open_basedir en PHP ¡Saludos!       A raíz de un CTF descubrí esta pequeña triquiñuela para bypassear estas proteccion...
< >