O que é SQL Injection? Para iniciantes
A injeção de SQL (ou SQL injection) é uma vulnerabilidade de segurança da web que permite que um invasor interfira nas consultas que um aplicativo faz ao seu banco de dados. Geralmente, permite que um invasor visualize dados que normalmente ele não é capaz de recuperar. Isso pode incluir dados pertencentes a outros usuários ou quaisquer outros dados que o próprio aplicativo é capaz de acessar. Em muitos casos, um invasor pode modificar ou excluir esses dados, causando alterações persistentes no conteúdo ou comportamento do aplicativo.
Em algumas situações, um invasor pode escalar um ataque de injection de SQL para comprometer o servidor subjacente ou outra infraestrutura de back-end, ou realizar um ataque de negação de serviço.
Qual é o impacto de um ataque de SQL Injection bem-sucedido?
Um ataque de SQL injection bem-sucedido pode resultar em acesso não autorizado a dados confidenciais, como senhas, detalhes de cartão de crédito ou informações pessoais do usuário. Muitas violações de dados de alto perfil nos últimos anos foram resultado de ataques de SQL injection, levando a danos à reputação e multas regulatórias. Em alguns casos, um invasor pode obter um backdoor persistente nos sistemas de uma organização, levando a um comprometimento de longo prazo que pode passar despercebido por um longo período.
Exemplos de SQL Injection
Há uma grande variedade de vulnerabilidades, ataques e técnicas de SQL Injection que surgem em diferentes situações. Alguns exemplos comuns de injeção de SQL incluem:
- Recuperando dados ocultos, onde você pode modificar uma consulta SQL para retornar resultados adicionais.
- Subvertendo a lógica do aplicativo, onde você pode alterar uma consulta para interferir com a lógica do aplicativo.
- Ataques UNION, onde você pode recuperar dados de diferentes tabelas de banco de dados.
- Examinando o banco de dados, onde você pode extrair informações sobre a versão e estrutura do banco de dados.
- Injeção cega de SQL, onde os resultados de uma consulta que você controla não são retornados nas respostas do aplicativo.
Recuperando dados ocultos
Considere um aplicativo de compras que exibe produtos em diferentes categorias. Quando o usuário clica na categoria Presentes, o navegador solicita o URL: https://insecure-website.com/products?category=Gifts
Isso faz com que o aplicativo faça uma consulta SQL para recuperar detalhes dos produtos relevantes do banco de dados:
SELECIONE * DE produtos ONDE categoria = ‘Presentes’ E lançados = 1
Esta consulta SQL pede ao banco de dados para retornar:
- todos os detalhes (*)
- da tabela de produtos
- onde a categoria é Presentes
e lançado é 1.
A restrição lançado = 1 está sendo usada para ocultar produtos que não foram lançados.
Para produtos não lançados, presumivelmente lançado = 0.
O aplicativo não implementa nenhuma defesa contra ataques de injeção de SQL, então um invasor pode construir um ataque como: https://insecure-website.com/products?category=Gifts’–
Isso resulta na consulta SQL:
SELECIONE * DE produtos ONDE categoria = ‘Presentes’ – ‘E lançado = 1
O principal aqui é que a sequência de dois traços - é um indicador de comentário em SQL e significa que o resto da consulta é interpretado como um comentário. Isso remove efetivamente o restante da consulta, de forma que não inclui mais E lançado = 1. Isso significa que todos os produtos são exibidos, incluindo os não lançados.
Indo além, um invasor pode fazer com que o aplicativo exiba todos os produtos em qualquer categoria, incluindo categorias que ele não conhece: https://insecure-website.com/products?category=Gifts’+OR+1=1– Isso resulta na consulta SQL:
SELECIONE * DE produtos ONDE categoria = ‘Presentes’ OU 1 = 1– ‘E lançado = 1
A consulta modificada retornará todos os itens em que a categoria seja Presentes ou 1 é igual a 1. Como 1 = 1 é sempre verdadeiro, a consulta retornará todos os itens.
Subvertendo a lógica do aplicativo
Considere um aplicativo que permite que os usuários façam login com um nome de usuário e senha. Se um usuário enviar o nome de usuário wiener e a senha bluecheese, o aplicativo verifica as credenciais executando a seguinte consulta SQL:
SELECIONE * DE usuários ONDE o usuário = ‘wiener’ E a senha = ‘bluecheese’
Se a consulta retornar os detalhes de um usuário, o login foi bem-sucedido. Caso contrário, é rejeitado.
Aqui, um invasor pode fazer login como qualquer usuário sem uma senha, simplesmente usando a sequência de comentário SQL -para remover a verificação de senha da cláusula de consulta ONDE. Por exemplo, enviar o nome de usuárioadministrador’–e uma senha em branco resulta na seguinte consulta:
SELECIONE * DE usuários ONDE o usuário = ‘administrador’ – ‘E senha =’ ‘
Esta consulta retorna o usuário cujo nome de usuário é administrador e loga com sucesso o invasor como esse usuário.
Recuperando dados de outras tabelas de banco de dados
Nos casos em que os resultados de uma consulta SQL são retornados nas respostas do aplicativo, um invasor pode aproveitar uma vulnerabilidade de injeção SQL para recuperar dados de outras tabelas no banco de dados. Isso é feito usando a palavra-chave UNION, que permite executar uma consulta SELECIONE adicional e acrescenta os resultados à consulta original.
Por exemplo, se um aplicativo executa a seguinte consulta contendo a entrada do usuário “Presentes”:
SELECIONE o nome, a descrição DOS produtos ONDE categoria = ‘Presentes’
então um invasor pode enviar a entrada:
‘UNION SELECIONE nome de usuário, senha DE usuários–
Isso fará com que o aplicativo retorne todos os nomes de usuário e senhas junto com os nomes e descrições dos produtos.
Examinando o banco de dados
Após a identificação inicial de uma vulnerabilidade de injeção de SQL, geralmente é útil obter algumas informações sobre o próprio banco de dados. Muitas vezes, essas informações podem abrir caminho para uma maior exploração.
Você pode consultar os detalhes da versão do banco de dados. A maneira como isso é feito depende do tipo de banco de dados, portanto, você pode inferir o tipo de banco de dados de qualquer técnica que funcione. Por exemplo, no Oracle você pode executar:
SELECT * FROM v$version
Você também pode determinar quais tabelas de banco de dados existem e quais colunas elas contêm. Por exemplo, na maioria dos bancos de dados, você pode executar a seguinte consulta para listar as tabelas:
SELECT * FROM information_schema.tables
Vulnerabilidades cegas de SQL Injection
Muitas instâncias de injeção de SQL são vulnerabilidades cegas. Isso significa que o aplicativo não retorna os resultados da consulta SQL ou os detalhes de quaisquer erros de banco de dados em suas respostas. Vulnerabilidades cegas ainda podem ser exploradas para acessar dados não autorizados, mas as técnicas envolvidas são geralmente mais complicadas e difíceis de executar.
Dependendo da natureza da vulnerabilidade e do banco de dados envolvido, as seguintes técnicas podem ser usadas para explorar vulnerabilidades cegas de injeção SQL:
- Você pode alterar a lógica da consulta para acionar uma diferença detectável na resposta do aplicativo, dependendo da verdade de uma única condição. Isso pode envolver a injeção de uma nova condição em alguma lógica booleana ou o disparo condicional de um erro, como divisão por zero.
- Você pode acionar condicionalmente um atraso de tempo no processamento da consulta, permitindo inferir a verdade da condição com base no tempo que o aplicativo leva para responder.
- Você pode acionar uma interação de rede fora de banda, usando técnicas OAST. Esta técnica é extremamente poderosa e funciona em situações onde as outras técnicas não funcionam. Frequentemente, você pode exfiltrar dados diretamente por meio do canal fora de banda, por exemplo, colocando os dados em uma pesquisa DNS de um domínio que você controla.
Como detectar vulnerabilidades de SQL Injection
A maioria das vulnerabilidades de injeção de SQL podem ser encontradas de forma rápida e confiável usando o Burp Suite scanner de vulnerabilidade da web.
A injeção de SQL pode ser detectada manualmente usando um conjunto sistemático de testes em cada ponto de entrada no aplicativo. Isso normalmente envolve:
- Enviar o caractere de aspas simples’e procurar por erros ou outras anomalias.
Enviar alguma sintaxe específica de SQL que avalia o valor base (original) do ponto de entrada e um valor diferente e procurar por diferenças sistemáticas nas respostas do aplicativo resultante.
- Enviar condições booleanas, como OR 1=1 e OR 1=2, e procurar diferenças nas respostas do aplicativo.
- Enviar cargas úteis projetadas para disparar atrasos quando executados em uma consulta SQL e procurar diferenças no tempo necessário para responder.
- Enviar cargas OAST projetadas para acionar uma interação de rede fora de banda quando executado em uma consulta SQL e monitorar todas as interações resultantes.
SQL Injection em diferentes partes da consulta
A maioria das vulnerabilidades de injeção de SQL surgem dentro da cláusula ONDE de uma consulta SELECIONE.
Esse tipo de injeção de SQL é geralmente bem conhecido por testadores experientes.
Mas as vulnerabilidades de injeção de SQL podem, em princípio, ocorrer em qualquer local dentro da consulta e em diferentes tipos de consulta. Os outros locais mais comuns onde a injeção de SQL surge são:
- Em declarações de ATUALIZAR, dentro dos valores atualizados ou na cláusula ONDE.
- Em declarações de INSERIR, dentro dos valores inseridos.
- Em declarações de SELECIONE, dentro da tabela ou nome da coluna.
- Em declarações de SELECIONE, dentro da cláusula ORDENAR POR.
SQL Injection de segunda ordem
A injeção SQL de primeira ordem surge quando o aplicativo obtém a entrada do usuário de uma solicitação HTTP e, no decorrer do processamento dessa solicitação, incorpora a entrada em uma consulta SQL de uma maneira insegura.
Na injeção SQL de segunda ordem (também conhecida como injeção SQL armazenada), o aplicativo obtém a entrada do usuário de uma solicitação HTTP e a armazena para uso futuro. Isso geralmente é feito colocando a entrada em um banco de dados, mas nenhuma vulnerabilidade surge no ponto onde os dados são armazenados. Posteriormente, ao lidar com uma solicitação HTTP diferente, o aplicativo recupera os dados armazenados e os incorpora a uma consulta SQL de maneira insegura.
A injeção SQL de segunda ordem geralmente surge em situações em que os desenvolvedores estão cientes das vulnerabilidades da injeção SQL e, portanto, lidam com segurança com o posicionamento inicial da entrada no banco de dados. Quando os dados são posteriormente processados, são considerados seguros, uma vez que foram previamente colocados na base de dados de forma segura. Nesse ponto, os dados são tratados de maneira insegura, porque o desenvolvedor erroneamente considera que eles são confiáveis.
Fatores específicos do banco de dados
Alguns recursos básicos da linguagem SQL são implementados da mesma maneira em plataformas de banco de dados populares, e muitas maneiras de detectar e explorar vulnerabilidades de injeção de SQL funcionam de forma idêntica em diferentes tipos de banco de dados.
No entanto, também existem muitas diferenças entre os bancos de dados comuns. Isso significa que algumas técnicas para detectar e explorar injeção de SQL funcionam de maneira diferente em plataformas diferentes. Por exemplo:
- Sintaxe para concatenação de strings.
- Comentários.
- Consultas em lote (ou empilhadas).
- APIs específicas da plataforma.
- Mensagens de erro.
Como evitar injeção de SQL
A maioria das instâncias de injeção de SQL pode ser evitada usando consultas parametrizadas (também conhecidas como instruções preparadas) em vez da concatenação de strings na consulta.
O código a seguir é vulnerável à injeção de SQL porque a entrada do usuário é concatenada diretamente na consulta:
Consulta string = “SELECIONE * DE produtos ONDE categoria = ‘” + input + “‘”;
Instrução de instrução = connection.createStatement ();
ResultSet resultSet = instrução.executeQuery (consulta);
Este código pode ser facilmente reescrito de forma a evitar que a entrada do usuário interfira na estrutura da consulta:
Instrução PreparedStatement =
connection.prepareStatement (“SELECIONE * DOS produtos ONDE
categoria =? “);
instrução.setString (1, input);
ResultSet resultSet = instrução.executeQuery ();
As consultas parametrizadas podem ser usadas para qualquer situação em que a entrada não confiável apareça como dados dentro da consulta, incluindo a cláusula ONDE e valores em uma declaração INSERIR ou ATUALIZAR. Elas não podem ser usadas para lidar com entradas não confiáveis em outras partes da consulta, como nomes de tabela ou coluna, ou a cláusula ORDENAR POR.
A funcionalidade do aplicativo que coloca dados não confiáveis nessas partes da consulta precisará adotar uma abordagem diferente, como valores de entrada permitidos na lista branca ou usando uma lógica diferente para fornecer o comportamento necessário.
Para que uma consulta parametrizada seja eficaz na prevenção da injeção de SQL, a string usada na consulta deve ser sempre uma constante embutida no código e nunca deve conter dados variáveis de qualquer origem. Não fique tentado a decidir caso a caso se um item de dados é confiável e continue usando a concatenação de string dentro da consulta para casos considerados seguros.
É muito fácil cometer erros sobre a possível origem dos dados ou que as alterações em outro código violem suposições sobre quais dados estão corrompidos.
Fonte: https://portswigger.net/web-security/sql-injection