Básicos de Inyección de Comandos


Ejecutar un ataque de Inyección de Comandos significa básicamente ejecutar un comando del sistema en un servidor determinado a través de una aplicación web. La ejecución del comando es, por supuesto, la parte fácil. La parte difícil es encontrar y explotar la grieta vulnerable en el sistema que podría ser cualquier cosa, desde un campo de un formulario inseguro en una página web hasta un puerto abierto en la interfaz de red.

De hecho, esta es la primera razón por la que siempre debes configurar tu servidor con múltiples cuentas de usuario, de modo que los diferentes procesos que no necesitan acceso a los demás archivos e incluso si tu aplicación es vulnerable, ningún exploit pueda causar daños graves. Especialmente, una aplicación web, nunca debería tener permisos de root.

Encontrar una vulnerabilidad

Primero debes pensar en todas las formas en que tu servidor y el mundo exterior pueden comunicarse entre sí. Un Examen de penetración probablemente comenzaría con la ubicación de todas las direcciones IP y los puertos disponibles para averiguar qué servicios se están ejecutando en un servidor. Sin embargo, nos vamos a concentrar en el enfoque más simple: vamos a tratar de atacar a un servidor a través de un sitio web, porque al completar un formulario, este envía información al servidor y la probabilidad de que el servidor responda con algo a través del sitio web es alta.

Para encontrar un formulario vulnerable, todo lo que necesitas hacer es probar un comando bash en todas las entradas (al igual que XSS). Por ejemplo, ls; debería enumerar todos los archivos en cualquier directorio en el que se encuentre la aplicación web (los servidores de Windows tienen comandos diferentes, como dir &). Dependiendo de qué comando se ejecute en el servidor, es posible que debas ajustar el comando de prueba a ; ls;. A veces, incluso cuando la entrada es vulnerable, no lo sabrás, porque a pesar de que el comando se ejecuta, el servidor no revela los resultados. En este caso, puedes intentar hacer ping a tu servidor (; ping -c 4 172.521.43.11;) y verificar tus registros para ver si el ping alcanza a tu servidor.

Ejemplo de Vulnerabilidad

La forma más obvia que puede ser vulnerable es aquella que claramente ejecuta algún comando del sistema en el servidor. Toma por ejemplo este servicio de ping. Ingresa una IP y la misma hará ping 4 veces y te dará los resultados.

entrada vulnerable

El formato del texto devuelto (rojo) parecerá algo de un terminal de Linux. Si estás familiarizado con Unix Bash, lo reconocerás como el comando ping que funciona solo con proporcionar la IP: ping 104.244.42.1. De hecho, eso es exactamente lo que hace el servidor en este caso.

Sin embargo, no todas las vulnerabilidades son tan obvias. Por lo general, la entrada no se ve para nada extraña.

actualizar imagen de perfil

Aquí puedes cargar un archivo o agregar una URL que redirija a un archivo para actualizar tu imagen de perfil. Lo que no ves es que en el fondo se usa un comando llamado convert para ajustar tu imagen de un rectángulo a un círculo. Para encontrar este tipo de vulnerabilidad, puedes insertar un comando separado por punto y coma:

error de actualización de perfil

Puedes ver que el pwd muestra el directorio actual de las aplicaciones web en el campo de errores. ¿Por qué funciona esto? Porque hay una línea PHP en el servidor que se ve así: exec("convert {$_GET['filename']} -crop 200x200 {$newname}");. Y cuando insertamos a; pwd; como la URL entonces lo que se ejecuta en bash es convert a; pwd; -crop 200x200 {$newname} que detiene el archivo de conversión y ejecuta el nuestro.

Importancia en el mundo real

Ser capaz de ejecutar comandos como un determinado usuario en un sistema significa tener acceso casi completo a esa cuenta. Por lo tanto, todo, desde tu código hasta las credenciales de la base de datos, puede estar disponible para el hacker. O, si el delincuente cibernético así lo elige, puede reemplazar silenciosamente el contenido de tu sitio para que se ajuste a sus preferencias.

Hay ataques a gran escala que explotan vulnerabilidades específicas. Por ejemplo, en 2016 se encontró un exploit en un enrutador que utilizaba la capacidad de los servidores NTP para ejecutar comandos de forma remota y así construir una botnet. Millones de enrutadores fueron vulnerables a esto y hay muchos más ataques como este contra enrutadores y otras cosas conectadas a Internet.

Básicamente, estoy hablando de que la Inyección de Comandos sigue siendo algo importante y tu aplicación web podría escanearse en busca de vulnerabilidades en cualquier momento, así que asegúrate de protegerte.

¡OMG salva mi servidor!

Hay muchas formas de protegerse contra esto.

No ejecutar comandos del sistema

Obviamente, esta es la protección perfecta, pero no exactamente la más recomendada en cada situación. Solo asegúrate de que realmente necesitas ejecutar comandos del sistema antes de implementarlos. Una buena práctica es utilizar métodos diseñados específicamente para casos de uso como este: pcntl_fork y pcntl_exec. A muchos desarrolladores no les gusta usarlos, ya que la implementación no siempre es sencilla. Además, en lugar de wget, los desarrolladores deberían usar Biblioteca de URL para Cliente PHP para extraer archivos de recursos externos.

Validar entrada del usuario

Si no hay forma de ejecutar los comandos del sistema, debes asegurarte de que el usuario no haya escrito ningún código malicioso en un campo de formulario. La forma más fácil es verificar si hay símbolos sospechosos como ; y #. A esto se le llama poner en lista negra. Sin embargo, para estar realmente seguro, deberás asegurarte de qué tipo de cadenas están permitidas y poner en lista blanca los símbolos. Por ejemplo, si tu comando acepta un nombre de archivo, entonces debes incluir en la lista blanca letras, números y el punto ..

Aquí hay un ejemplo de PHP con Regex donde un usuario puede eliminar un archivo:

if (preg_match('/^[a-zA-Z0-9]+\.[a-z]{1,5}$/g', $filename)) {
	exec('rm {$filename}'); // is filename so execute command
} else {
	throw new Exception('Not a filename');
}

Poner en lista blanca los nombres de archivos y las URL puede resultar casi imposible con una simple expresión regular. Los nombres de archivo y las URL pueden contener caracteres válidos con los que la expresión regular coincidirá y bloqueará.

El siguiente ejemplo es vulnerable, ya que no sanitiza los datos aportados por los usuarios. El usuario puede insertar cualquier código malicioso que pueda encontrar y PHP lo ejecutará en el servidor.

if (!empty($_POST['uri'])){
	$newfile = 'uploads/users/'.end(explode('/', $_POST['uri']));
	exec("wget -O {$newfile} {$_POST['uri']}", $o, $r);
	$errors = array_merge($errors, $o);
}

Una solución rápida para esto puede ser el uso del método escapeshellarg(), que agregará comillas simples alrededor de todos los datos de entrada del usuario. Este enfoque es aceptable pero no siempre el mejor.

Como precaución adicional, el desarrollador debe tener en cuenta que a veces necesita obtener parámetros adicionales del sitio web de forma dinámica. Un buen ejemplo de esto es ImageMagick, que realiza la manipulación de imágenes. El siguiente ejemplo es la ruta que se muestra al usuario final después de encontrar algo inesperado. Además del nombre de archivo, la dirección indica la aceptación de argumentos adicionales: x e y, que el usuario puede cambiar.

../?page=profile_image&id=6&filename=uploads%2Fusers%2F
image_1_520x347.JPG&x=0&y=0

En este caso, el código debe sanitizar también los argumentos para permitir que solo se pasen valores enteros y rescatar cualquier otra cosa.

Revisión de código

El Regex puede complicarse, así que asegúrate de que un compañero de equipo o compañero de trabajo revise tu código y, si es posible, haz que un Tester también pruebe sus trucos en el código.

Mantener los permisos de usuario separados

Como precaución adicional, esto ayuda al administrador del servidor a mantener las cuentas de usuario separadas cuando sea posible. Lo más importante es que la aplicación web no debería tener más permisos de los absolutamente necesarios. Sobre todo, no le dé permisos de root, eso sería un peligro inminente.

Krister Viirsaar