Skip to main content

Injeção de comandos: como funciona, quais são os riscos e como evitá-la

Escrito por

25 de novembro de 2020

0 minutos de leitura

Ataques de injeção de comandos — também conhecidos como ataques de injeção de comandos do sistema operacional — exploram uma falha de programação para executar comandos no sistema sem validar, escapar ou sanitizar corretamente as entradas, o que pode permitir que um invasor execute comandos arbitrários.

Quais são os riscos da injeção de comandos?

Dependendo da configuração do aplicativo e do processo que o executa, uma vulnerabilidade de injeção de comandos pode elevar os privilégios do processo ou abrir um shell reverso remoto, permitindo que um agente malicioso interaja com o sistema sem restrições.

Como funcionam os ataques de injeção de comandos?

Para entender as falhas de programação relacionadas a ataques de injeção de comandos do sistema operacional, vamos explorar algumas vulnerabilidades desse tipo encontradas em aplicativos baseados em Node.js.

systeminformation é uma biblioteca de informações do sistema operacional (SO) com mais de 500 mil downloads por semana, manutenção regular (commits) e uma comunidade ativa, como podemos ver na página de integridade de dependências do Snyk Advisor:

Página do pacote npm systeminformation mostrando uma pontuação de integridade de 75/100, a tendência de downloads semanais e um gráfico da frequência de commits de manutenção

No entanto, todas as versões do systeminformation anteriores à versão 4.27.11 são vulneráveis à injeção de comandos do sistema operacional, devido a vários métodos vulneráveis expostos aos usuários pela biblioteca.

Vamos analisar o código da função vulnerável inetChecksite(). Você consegue identificar a vulnerabilidade de segurança neste exemplo de injeção de comandos?

      let urlSanitized = util.sanitizeShellString(url).toLowerCase();
      if (urlSanitized) {
        let t = Date.now();
        if (_linux || _freebsd || _openbsd || _netbsd || _darwin || _sunos) {
          let args = ' -I --connect-timeout 5 -m 5 ' + urlSanitized + ' 2>/dev/null | head -n 1 | cut -d " " -f2';
          let cmd = 'curl';
          exec(cmd + args, function (error, stdout) {
          …

Posso tirar várias conclusões deste trecho de código:

  • Um parâmetro de url está sendo sanitizado. Será que consigo contornar as funções de sanitização com algo que o autor não levou em conta?

  • Está sendo usada uma API insegura para iniciar processos do sistema operacional: exec(), que concatena os comandos e seus argumentos em um único comando de shell para execução. Esse também é o motivo pelo qual o autor precisou recorrer à própria sanitização dos argumentos da linha de comando.

A variável urlSanitized é concatenada aos argumentos fornecidos à CLI.

É nesse último ponto, sobre urlSanitized, que está a vulnerabilidade de segurança. O comando em si, referenciado pela variável cmd, é o utilitário de rede curl. E se pudéssemos simplesmente passar um argumento de comando ao curl como URL?

É possível tentar uma injeção de comandos com a seguinte prova de conceito, fornecendo a URL à função vulnerável, como mostrado no primeiro argumento passado para a função inetChecksite(). Veja este exemplo de injeção de comandos:

 const si = require('systeminformation');
si.inetChecksite("https://snyk.io; touch /tmp/abc", (result) => console.log(result));

No entanto, isso não funciona neste caso porque esse pacote npm sanitiza entradas perigosas do usuário, como o ponto e vírgula (;).

No entanto, os argumentos de linha de comando normalmente não precisam de caracteres especiais. Poderíamos fornecer como entrada do usuário uma URL como https://snyk.io -o hihi, que inclui um espaço e concatena o argumento posicional -o do curl, gravando o resultado do site em um arquivo que controlamos.

Veja outro exemplo de injeção de comandos que mostra como essa exploração pode ocorrer — e de fato funciona como esperado — em uma versão vulnerável do systeminformation@4.27.10:

const si = require('systeminformation');
si.inetChecksite("https://snyk.io -o hihi", (result) => console.log(result));

Este commit aprimorou a sanitização com o objetivo de limitar ainda mais vulnerabilidades desse tipo de injeção de comandos:

Comparação lado a lado de trechos de código em lib/internet.js, mostrando a sanitização ampliada de URLs com substituições adicionais de caracteres.

Guia rápido de injeção de comandos

Podemos aprender muito com outros exemplos de injeção de comandos, nos quais identificamos vulnerabilidades de segurança em pacotes de código aberto e como elas foram mitigadas, como nestas vulnerabilidades: aqui e aqui.

Para evitar ataques de injeção de comandos, considere as seguintes práticas:

  1. Não permita que entradas do usuário sejam usadas nos comandos executados pelo seu aplicativo.

  2. Use apenas APIs seguras para executar comandos, como execFile(). Diferentemente de outras APIs, ela aceita o comando como primeiro parâmetro e um array de argumentos de linha de comando como segundo parâmetro da função. Assim, o comando precisa ser um programa válido e fica separado de entradas potencialmente perigosas.

  3. Ao usar execFile(), garanta que o usuário não tenha controle sobre o nome do programa. Além disso, mapeie as entradas do usuário para argumentos de comando, em vez de passá-las diretamente para a execução do programa.

  4. Como precaução adicional, valide se as entradas do usuário correspondem ao formato esperado. Por exemplo, se um parâmetro de função espera uma URL, valide se a entrada recebida é uma URL válida. Isso teria evitado a vulnerabilidade de injeção de comandos mencionada acima no pacote npm systeminformation.

Ataques de injeção de comandos no OWASP Top 10

Para mostrar como os ataques de injeção de comandos do sistema operacional são comuns, consultei todas as vulnerabilidades de segurança conhecidas publicamente que a equipe de segurança do Snyk publicou em outubro de 2020 e filtrei pelo ecossistema JavaScript no npm. Como você pode ver, só na última semana de outubro foram identificadas várias vulnerabilidades de segurança de Command injection em pacotes npm.

Página do Snyk Vulnerability Database com busca por vulnerabilidades, filtros de pacotes e uma lista de vulnerabilidades do npm com níveis de gravidade e datas de publicação.

Em resumo, as vulnerabilidades de injeção de comandos são mais comuns do que você imagina. Não é à toa que esses ataques aparecem com destaque entre os 10 principais riscos de segurança para aplicações web da OWASP: são comuns e assumem muitas formas, como os ataques de injeção de SQL.Recomendo conectar seus repositórios Git ao Snyk para testar e corrigir vulnerabilidades de injeção de comandos. Quem sabe o Snyk também encontra outras? O Snyk é gratuito e leva pouco tempo para configurar o monitoramento dos seus projetos!

Comece a participar de desafios de Capture the Flag

Aprenda a resolver desafios de Capture the Flag assistindo sob demanda ao nosso workshop virtual introdutório.

Leia mais

Blog

Modelos de ponta encontraram as vulnerabilidades. Só o atacante encontrou as cadeias.

A análise estática encontrou as falhas, mas só os testes de ataque em aplicações ativas provaram como elas poderiam ser encadeadas para causar invasões. Uma comparação entre Evo COS, Claude Security e Claude Code Security.

feature insights context
Blog

Os ataques autônomos já chegaram. A defesa precisa acompanhar o ritmo.

Os atacantes autônomos estão reduzindo o tempo disponível para a defesa. Saiba como a descoberta, a correção, a validação e a prevenção contínuas ajudam as equipes de segurança a acompanhar esse ritmo.

Blog

Por que agentes de programação com IA continuam criando falhas de controle de acesso

Agentes de programação com IA podem gerar uma lógica de autorização que compila e passa pela revisão, mas permite que um tenant acesse os dados de outro. Saiba por que é difícil detectar falhas de controle de acesso e como evitá-las.