Inyección de comandos
Veamos la Inyección de Comandos por sí misma por ahora. Vamos a centrarnos principalmente en algunos ejemplos diferentes para que sea más fácil ver cómo se ve en acción. Así que, como repaso rápido, las vulnerabilidades de inyección de comandos se producen cuando la entrada del usuario utiliza parte de un comando del sistema operativo, como la siguiente función:
let ip = request.params.ipAddress;
system("ping " + ip);
Si un usuario proporciona la dirección IP, usaremos `8.8.8.8` como ejemplo, el comando que se ejecutará será `ping 8.8.8.8`, que hace exactamente lo que uno esperaría. Sin embargo, si el usuario proporciona `8.8.8.8 && ls /etc/` este comando no sólo hará ping a la IP 8.8.8.8, sino que también ejecutará `ls` en la carpeta `/etc/.
Mitigación
Dada la gravedad de un ataque de inyección de comandos, hay algunas preguntas importantes que debe plantearse en primer lugar cuando trabaje con comandos del sistema:
- ¿Es realmente necesario invocar ese comando? La mejor defensa es no invocar nunca comandos del sistema
- ¿Existen bibliotecas/vinculaciones que permitan conseguir el mismo efecto sin utilizar un comando del sistema?
- ¿Puede pasar datos al proceso a través de Standard In, en lugar del propio comando?
Si estas cosas no son posibles, la parametrización es importante.
Ejemplos
He aquí algunos ejemplos en varios idiomas para mostrar cómo se ve esto en la práctica.
Sin el uso de la parametrización, esto es vulnerable a la inyección de comandos.
string folder = "/tmp/ && ifconfig";
string cmd = "\"ls " + folder +"\"";
// INSECURE: Ejecuta tanto el comando `ls` como `ifconfig`
System.Diagnostics.Process.Start("bash", "-c " + cmd);
C# - seguro
Al proporcionar el comando como una lista de parámetros, el comando está parametrizado y protegido contra la inyección de comandos.
string folder = "/tmp/ && ifconfig";
List<string> arguments = new List<string>() {"-c", "ls", folder};
// SECURE: Does not execute ifconfig command
System.Diagnostics.Process.Start("bash", arguments);
Java - Inseguro
Sin el uso de la parametrización, esto es vulnerable a la inyección de comandos.
String folder = "/tmp/ && ifconfig";
// INSECURE: Ejecuta tanto el comando `ls` como `ifconfig`
ProcessBuilder b = new ProcessBuilder("bash -c ls " + carpeta);
Process p = pb.start();
Java - Seguro
Al proporcionar el comando como una lista de parámetros, el comando está parametrizado y protegido contra la inyección de comandos.
String folder = "/tmp/ && ifconfig";
// SEGURO: No ejecuta el comando ifconfig
ProcessBuilder b = new ProcessBuilder("bash", "-c", "ls", folder);
Process p = pb.start();
Javascript - Inseguro
Sin el uso de la parametrización, esto es vulnerable a la inyección de comandos.
const { exec } = require("child_process");
const folder = "/tmp/ && ifconfig";
// INSECURE: Executes both the `ls` and `ifconfig` command
const ls = exec("bash -c ls " + folder, (error, stdout, stderr) => {
console.log(`stdout: ${stdout}`);
});
Javascript - Seguro
const { spawn } = require("child_process");
const folder = "/tmp/ && ifconfig";
// SECURE: Does not execute ifconfig command
const ls = spawn("bash", ["-c", "ls", folder]);
ls.stdout.on("data", data => {
console.log(`stdout: ${data}`);
});
Python - Inseguro
Sin el uso de la parametrización, esto es vulnerable a la inyección de comandos.
import subprocess
folder = "/tmp/ && ifconfig"
# INSECURE: Ejecuta tanto el comando `ls` como `ifconfig`
subprocess.run("bash -c ls " + folder, shell=True)
Python - Seguro
Al proporcionar el comando como una lista de parámetros, el comando está parametrizado y protegido contra la inyección de comandos.
import subprocess
folder = "/tmp/ && ifconfig"
# SEGURO: No ejecuta el comando ifconfig
subprocess.run(["bash", "-c", "ls", folder])