Algumas vulnerabilidades web levam diretamente ao comprometimento do servidor, e a command injection (injeção de comandos do sistema operacional) é a mais direta de todas. Ela ocorre quando uma aplicação web executa comandos do sistema operacional incorporando entrada do usuário sem tratamento — permitindo ao atacante executar seus próprios comandos no servidor. É a ponte mais curta entre uma falha web e um shell no sistema, conectando o Bloco XII ao Bloco VIII (exploração). Pratique no DVWA, que tem um módulo de command injection didático.

A mesma raiz, agora no sistema operacional

O mecanismo é a mesma raiz de toda injeção — misturar dados e comando —, agora no nível do sistema operacional. Imagine uma funcionalidade web que "pinga" um host para verificar conectividade: o usuário digita um endereço, e o servidor executa, por baixo, um comando de sistema como ping ENDERECO. Se a aplicação constrói esse comando colando a entrada do usuário diretamente, sem sanitizá-la, o atacante pode encadear seus próprios comandos. Os sistemas operacionais permitem executar múltiplos comandos numa linha usando separadores — o ; (executa o próximo comando em seguida), o | (encadeia via pipe), o && (executa se o anterior teve sucesso), e as crases ou $() (substituição de comando). Injetando esses separadores, o atacante quebra a estrutura do comando pretendido e adiciona o seu:

# a aplicação pretendia executar:  ping 8.8.8.8
# o atacante digita no campo:      8.8.8.8; whoami
# o servidor executa:              ping 8.8.8.8; whoami
#                                                ↑ o comando do atacante roda também

De whoami a reverse shell

Aquele ; whoami faz o servidor, além de pingar, executar o whoami — e a saída revela com que usuário a aplicação roda. A partir daí, o atacante pode executar qualquer comando que aquele usuário permita: listar arquivos, ler dados, e — o passo natural — obter um reverse shell (aula O que é um exploit: da vulnerabilidade ao acesso), transformando a command injection num acesso interativo completo ao servidor. É por isso que a command injection é tão crítica: ela pula direto da web para a execução de código no sistema, o objetivo máximo da exploração.

A variante cega

Como no XSS e na SQLi, há uma variante cega (blind command injection): às vezes o comando executa mas sua saída não aparece na resposta da página. Você confirma e explora a vulnerabilidade por canais indiretos — como fazer o servidor esperar (; sleep 10) e medir o tempo de resposta (a mesma lógica time-based da SQLi cega, aula SQL Injection na mão: conversando com o banco de dados), ou fazer o servidor te enviar dados por outro canal (uma requisição de rede para um servidor que você controla — a exfiltração out-of-band). O raciocínio é idêntico ao da injeção cega em outros contextos: quando você não vê o resultado, você o infere por diferenças de comportamento ou por canais laterais.

Code injection: executar a própria linguagem

Uma vulnerabilidade relacionada que vale mencionar é a code injection propriamente dita — quando a aplicação executa código da própria linguagem (PHP, Python) a partir de entrada do usuário, em vez de comandos do SO. Funções perigosas que avaliam strings como código (como eval em várias linguagens) são a causa clássica. O impacto é similar (execução de código no servidor), e a raiz é a mesma: entrada do usuário sendo interpretada como código executável. Command injection e code injection são primas próximas, distinguidas por o quê é injetado — comandos do SO vs. código da linguagem.

Toda injeção, uma raiz e uma defesa

O ponto conceitual, que fecha o padrão de injeção do bloco: toda injeção — SQL, XSS, comandos, código — compartilha a mesma raiz e a mesma defesa. A raiz é sempre entrada não confiável sendo interpretada como instrução (SQL no banco, JS no navegador, comando no SO, código na linguagem). A defesa é sempre manter a fronteira entre dado e instrução. Uma vez que você internaliza esse padrão único, você reconhece injeção em qualquer contexto novo que encontrar — e reconhece a defesa correta. É a beleza de entender o princípio em vez de decorar cada ataque isoladamente: a command injection é "a SQLi do sistema operacional", governada pela mesma lógica.

Não deixar a entrada virar comando

Do lado defensivo, a command injection tem defesas claras, todas visando não deixar a entrada virar comando. A melhor prática é evitar chamar o sistema operacional com entrada do usuário sempre que possível — usar funções seguras da linguagem que fazem a tarefa sem invocar um shell (por exemplo, resolver um endereço via biblioteca em vez de chamar o comando ping). Quando a chamada ao sistema é inevitável: usar APIs que separam comando e argumentos (passando os argumentos como uma lista, não como uma string concatenada, de modo que a entrada nunca seja interpretada como parte do comando — o equivalente às prepared statements da SQLi); validação rigorosa de entrada (allowlist — se o campo espera um endereço IP, aceitar apenas o formato de um IP, rejeitando qualquer caractere de shell); menor privilégio (a aplicação web não deve rodar como root, para limitar o dano de uma injeção bem-sucedida); e nunca usar funções de avaliação de código com entrada do usuário. A lição, unificada com todo o bloco: separe dado de instrução, valide no servidor, e limite privilégios para conter o impacto.

Fontes e leituras recomendadas

  • PortSwigger Web Security Academy — labs de OS command injection
  • OWASP — Command Injection e Code Injection (Testing Guide e prevenção)
  • DVWA — módulo de Command Injection em níveis de dificuldade
  • HackTricks — seção de command injection e exfiltração out-of-band

Exercícios

  1. Como a command injection permite ao atacante executar seus próprios comandos, e qual o papel de separadores como ; e &&?

    ✓ Resposta:

    A aplicação executa um comando do SO incorporando a entrada do usuário sem sanitizá-la; usando separadores como ;, | ou &&, o atacante encadeia comandos próprios ao comando pretendido. Assim, 8.8.8.8; whoami faz o servidor executar o whoami além do ping, rodando o comando do atacante.

  2. Por que a command injection é considerada uma das pontes mais diretas entre uma falha web e o comprometimento do servidor?

    ✓ Resposta:

    Porque leva diretamente à execução de comandos no sistema operacional do servidor, permitindo obter um reverse shell e acesso interativo completo — pulando da web para a execução de código, o objetivo máximo da exploração, sem etapas intermediárias.

  3. O que é a blind command injection, e como se confirma/explora a vulnerabilidade sem ver a saída?

    ✓ Resposta:

    É quando o comando executa mas sua saída não aparece na resposta. Confirma-se/explora-se por canais indiretos: fazendo o servidor esperar (; sleep 10) e medindo o tempo de resposta, ou provocando o servidor a enviar dados a um servidor controlado pelo atacante (exfiltração out-of-band).

  4. Qual a diferença entre command injection e code injection, e o que elas têm em comum?

    ✓ Resposta:

    Command injection injeta comandos do sistema operacional; code injection injeta código da própria linguagem da aplicação (ex.: via funções como eval). Em comum: ambas resultam em execução no servidor e têm a mesma raiz — entrada do usuário interpretada como instrução executável.

  5. Qual o padrão único que une SQLi, XSS e command injection, e qual a defesa correspondente para a command injection especificamente?

    ✓ Resposta:

    O padrão único é entrada não confiável sendo interpretada como instrução (SQL, JS, comando do SO, código). Para a command injection, a defesa é evitar chamar o SO com entrada do usuário; quando inevitável, usar APIs que separam comando e argumentos (argumentos como lista), validar por allowlist e aplicar menor privilégio — mantendo a fronteira entre dado e comando.