Introdução
Section titled “Introdução”Command Injection (ou OS Command Injection) é uma vulnerabilidade que ocorre quando uma aplicação passa dados fornecidos pelo usuário para um comando do sistema operacional sem a devida validação ou sanitização.
Um atacante pode manipular esses dados para injetar comandos adicionais, que serão executados com os mesmos privilégios do processo da aplicação.
Cenário Vulnerável
Section titled “Cenário Vulnerável”Imagine um endpoint que recebe um endereço IP e executa um ping para verificar conectividade:
String ip = request.getParameter("ip");Runtime runtime = Runtime.getRuntime();Process process = runtime.exec("ping -c 4 " + ip);string ip = Request.QueryString["ip"];var startInfo = new System.Diagnostics.ProcessStartInfo();startInfo.FileName = "cmd.exe";startInfo.Arguments = "/c ping " + ip;var process = new System.Diagnostics.Process();process.StartInfo = startInfo;process.Start();$ip = $_GET['ip'];system("ping -c 4 " . $ip);Um usuário normal enviaria algo como 192.168.0.1, gerando o comando:
ping -c 4 192.168.0.1Um atacante poderia enviar 192.168.0.1; cat /etc/passwd, gerando:
ping -c 4 192.168.0.1; cat /etc/passwdO caractere ; encerra o primeiro comando e inicia um novo, fazendo com que o servidor execute cat /etc/passwd e retorne seu conteúdo.
Riscos
Section titled “Riscos”Dependendo dos privilégios do processo da aplicação, um atacante pode:
- Ler arquivos sensíveis do sistema (
/etc/passwd, chaves privadas, arquivos de configuração com credenciais). - Executar comandos arbitrários no servidor, como instalar ferramentas maliciosas.
- Escalar privilégios e comprometer outros sistemas na rede interna.
- Deletar dados ou deixar a aplicação fora do ar.
- Estabelecer um shell reverso, obtendo acesso interativo ao servidor.
Como Corrigir
Section titled “Como Corrigir”A forma mais segura é não executar comandos de sistema. Utilize APIs nativas da linguagem ou do framework para a operação desejada — no caso de verificar conectividade, use bibliotecas de rede em vez de chamar ping.
Quando uma chamada ao sistema for inevitável, nunca concatene input do usuário ao comando. Passe os argumentos de forma separada e valide o input com uma allowlist antes de utilizá-lo.
String ip = request.getParameter("ip");Runtime runtime = Runtime.getRuntime();Process process = runtime.exec("ping -c 4 " + ip);if (!ip.matches("^[\\d.]+$")) { throw new IllegalArgumentException("IP inválido");}ProcessBuilder pb = new ProcessBuilder("ping", "-c", "4", ip);Process process = pb.start();string ip = Request.QueryString["ip"];var startInfo = new System.Diagnostics.ProcessStartInfo();startInfo.FileName = "cmd.exe";startInfo.Arguments = "/c ping " + ip;if (!System.Text.RegularExpressions.Regex.IsMatch(ip, @"^[\d.]+$")) { throw new ArgumentException("IP inválido");}startInfo.FileName = "ping";startInfo.Arguments = ip;var process = new System.Diagnostics.Process();process.StartInfo = startInfo;process.Start();$ip = $_GET['ip'];system("ping -c 4 " . $ip);if (!filter_var($ip, FILTER_VALIDATE_IP)) { throw new InvalidArgumentException("IP inválido");}$ip = escapeshellarg($ip);system("ping -c 4 " . $ip);