PHP – Funciones peligrosas

¿Peligrosas?… en realidad, depende de quien las use, como las use y con qué fin. Las funciones system(), exec(), passthru() y shell_exec() de PHP, sirven para ejecutar comandos sobre el sistema operativo que se esté utilizando. Por su parte, eval() ejecuta cualquier cadena de caracteres como código de éste lenguaje.  Para la mayoría de los programadores tales funciones son simplemente más código útil para su aplicación, lo cual es verdad, pero no todos lo ven de la misma manera.

 

 

La vulnerabilidad de Remote COMMAND Execution (RCE), hace referencia a la posibilidad de que un atacante logre ejecutar comandos sobre el sistema operativo que tenga por objetivo. Dentro del campo web, dicha vulnerabilidad apunta al mal uso de funciones PHP como system() programadas para realizar este tipo de acciones sobre el servidor. (Para tener en cuenta, existen funciones similares en otras tecnologías, por lo que RCE no se limita sólo a PHP).

Por otro lado, la vulnerabilidad de Remote CODE Execution (RCE), se aprovecha de fallos de programación en el uso de eval(). No hay que imaginar demasiado para saber lo que un atacante podría hacer si una aplicación utiliza esta función recibiendo como parámetro datos asignados por el usuario.

Comprendiendo el funcionamiento de eval(), es totalmente válido pasarle como parámetro  system(‘ls’);, de tal modo se podría interpretar como un ataque de ejecución remota de comandos. Pero la diferencia más grande entre Remote Code Execution y Remote Command Execution radica en la aplicación vulnerable.

Análisis de aplicaciones vulnerables a RCE

El siguiente código realiza un ping a la dirección IP que el usuario especifique y muestra la salida en pantalla:

<?php
$direccionIP = $_GET[ip];
$ejecutar = “ping “.$direccionIP;
$salida = shell_exec($ejecutar);
print $salida;
?>

Podemos observar que no se aplica ningún filtro a la variable “direccionIP” por lo que explotar esta falla es muy sencillo. Especificamos una IP de todas formas ya que el “ping” no lo podemos modificar pero basta con hacer uso de una pipe (|) seguido del comando que nosotros queramos para lograr nuestro objetivo. Ejemplo:  rce.php?ip=190.34.50.205 | ls

En cuanto a Remote Code Execution, el sitio oficial de PHP nos advierte del peligro que puede ser usar la función eval() con parámetros asignados por el usuario sin aplicar una previa validación, por ejemplo:

<?php
$sintaxcheck = $_GET[codigo];
$check = eval($sintaxcheck);
/*…*/
?>

En este caso, la forma de explotar la falla es: rce.php?codigo=echo “El limite es tu imaginacion”;

Bypass de filtros ¡atacantes por un rato!

En lo que respecta a seguridad web, siempre se habla  de “filtrar” los datos que envía el usuario a la aplicación. Al igual que un filtro de agua encargado de quitar la basura de la misma, un filtro PHP se encarga de eliminar los caracteres indeseables de la cadena de caracteres que recibamos.  En el caso de los filtros que buscan evitar un RCE, suelen centrarse en  los caracteres que utilizan las funciones anteriormente nombradas y se limitan a eliminar los paréntesis y las comillas. Aun así podríamos encontrarnos con uno mas complejo que filtre caracteres utilizados por codificaciones de modo que sea mas difícil de saltar, por ejemplo:

<?php
$ejecutar = $_GET[‘cmd’];
$ejecutar=preg_replace(“/[\(\)\’\%\&\$\|\”]/”,””,$ejecutar);
eval($ejecutar);
?>

Se eliminan los ()’”&%$[] de la variable cmd por lo que ejecutar un “system(‘ls’);” es imposible, sin embargo no se filtran las comillas invertidas () y esto es lo que pasa en la mayoría de los filtros anti-rce. El operador de comillas invertidas en PHP funciona como shell_exec(); por lo tanto bypasseamos el filtro anterior de la siguiente manera: rce.php?cmd=echo `ls`;  anteponemos un “echo” al comando para ver la salida en pantalla, de no hacerlo se ejecutara el comando pero sin mostrarnos nada. Finalmente obtenemos el mismo resultado que si hubiéramos ejecutado system(‘ls’);.

Protección

La realidad es que tal como lo advierte el sitio de PHP,  no es recomendable usar estas funciones con parámetros asignados por el usuario. Como vimos anteriormente, hasta el filtro mas complejo suele ser evadido, por lo tanto es mejor evitar el uso de tales funciones.

En el caso de ser necesario usarlas tendremos que validar los datos y utilizar las funciones  escapeshellcmd() para escapar una cadena de comandos completa o escapeshellarg() para escapar un argumento único, según corresponda.

Por ejemplo, la función escapeshellcmd() antepone una barra a los siguientes caracteres: #&;`|*?~<>^()[]{}$\, \x0A y \xFF.

La aplicamos de la siguiente forma:

<?php
$ejecutar = $_GET[‘cmd’];
$escape=escapeshellcmd($ejecutar);
system($escape);
?>

En conclusión, en el caso de utilizar estas funciones asegurémonos de validar los datos que asigne el usuario y por supuesto escapar y/o filtrar los caracteres que vimos a lo largo del artículo. Por otro lado es sumamente útil tener presente las buenas practicas descriptas en el desarrollo de código seguro de OWASP y emplear frameworks como ESAPI o similares.

#EOF

 

Curso Relacionado: Seguridad Web

Sheila Ayelen Berta.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *