O que é injeção de SQL (SQLi)?
A injeção de SQL (SQLi) é uma vulnerabilidade de segurança da Web que permite que um invasor interfira nas consultas que um aplicativo faz em seu banco de dados. Geralmente permite que um invasor visualize dados que normalmente não consegue recuperar. Isso pode incluir dados pertencentes a outros usuários ou quaisquer outros dados que o próprio aplicativo possa acessar. Em muitos casos, um invasor pode modificar ou excluir esses dados, causando alterações persistentes no conteúdo ou no comportamento do aplicativo.

Em algumas situações, um invasor pode escalar um ataque de injeção de SQL para comprometer o servidor subjacente ou outra infraestrutura de back-end ou executar um ataque de negação de serviço.

Qual é o impacto de um ataque de injeção de SQL bem-sucedido?
Um ataque de injeção de SQL 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 injeção de SQL, 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 injeção de SQL
Há uma grande variedade de vulnerabilidades, ataques e técnicas de injeção de SQL, 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 na 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 (Blind SQL Injection), 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 a URL:

https://vulneravel.com.br/produtos?categorias=Presentes

Isso faz com que o aplicativo faça uma consulta SQL para recuperar detalhes dos produtos relevantes do banco de dados:

SELECT * FROM produtos WHERE categoria = ‘Presentes’ AND liberado = 1

Esta consulta SQL solicita que o banco de dados retorne:

– todos os detalhes (*)
– da tabela de produtos
– onde a categoria é Presentes
– e liberado é 1.

A restrição liberado = 1 está sendo utilizada para ocultar produtos que não estão liberados. Para produtos não lançados, presumivelmente liberado = 0.

O aplicativo não implementa nenhuma defesa contra ataques de injeção de SQL, portanto, um invasor pode construir um ataque como:

https://vulneravel.com.br/produtos?categoria=Presentes’–

Isso resulta na consulta SQL:

SELECT * FROM produtos WHERE categoria = ‘Presentes’–‘ AND liberado = 1

A chave aqui é que a sequência de dois traços é um indicador de comentário em SQL e significa que o restante da consulta é interpretado como um comentário. Isso remove efetivamente o restante da consulta, portanto, não inclui mais AND liberado = 1. Isso significa que todos os produtos são exibidos, incluindo produtos não liberados.

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://vulneravel.com.br/produtos?categoria=Presentes’+OR+1=1–

Isso resulta na consulta SQL:

SELECT * FROM produtos WHERE categoria = ‘Presentes’ OU 1=1–‘ E liberado = 1

A consulta modificada retornará todos os itens em que a categoria é 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 bob e a senha admin123, o aplicativo verificará as credenciais executando a seguinte consulta SQL:

SELECT * FROM users WHERE nome de usuário = ‘bob’ AND senha = ‘admin123’

Se a consulta retornar os detalhes de um usuário, o login foi bem-sucedido. Caso contrário, é rejeitado.

Aqui, um invasor pode efetuar 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 WHERE da consulta. Por exemplo, enviar o nome de usuário administrador’– e uma senha em branco resulta na seguinte consulta:

SELECT * FROM users WHERE nome de usuário = ‘administrador’–‘ AND senha = ”

Essa consulta retorna o usuário cujo nome de usuário é administrador e registra 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 SELECT adicional e anexar os resultados à consulta original.

Por exemplo, se um aplicativo executar a seguinte consulta contendo a entrada do usuário “Presentes”:

SELECT nome, descrição FROM produtos WHERE categoria = ‘Presentes’

então um invasor pode enviar a entrada:

‘ UNION SELECT usuario, senha FROM usuarios–

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 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 de injeção cega de SQL (Blind 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 de injeção cega de SQL:

– Você pode alterar a lógica da consulta para acionar uma diferença detectável na resposta do aplicativo, dependendo da veracidade de uma única condição. Isso pode envolver a injeção de uma nova condição em alguma lógica booleana ou o acionamento condicional de um erro, como uma divisão por zero.
– Você pode acionar condicionalmente um atraso no processamento da consulta, permitindo inferir a veracidade 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. Freqüentemente, você pode exfiltrar dados diretamente por meio do canal fora de banda, por exemplo, colocando os dados em uma pesquisa de DNS para um domínio que você controla.




Como detectar vulnerabilidades de injeção SQL
A maioria das vulnerabilidades de injeção de SQL pode ser encontrada de forma rápida e confiável usando o scanner de vulnerabilidades da Web do Burp Suite.

A injeção de SQL pode ser detectada manualmente usando um conjunto sistemático de testes em cada ponto de entrada do aplicativo. Isso normalmente envolve:

Enviando o caractere de aspas simples ‘ e procurando por erros ou outras anomalias.
Submeter alguma sintaxe específica de SQL avaliada para o valor base (original) do ponto de entrada e para um valor diferente e procurar diferenças sistemáticas nas respostas resultantes do aplicativo.
Submeter condições booleanas como OR 1=1 e OR 1=2 e procurar diferenças nas respostas do aplicativo.
Enviando cargas úteis projetadas para acionar atrasos de tempo quando executadas em uma consulta SQL e procurando diferenças no tempo necessário para responder.
Envio de cargas OAST projetadas para acionar uma interação de rede fora de banda quando executada em uma consulta SQL e monitoramento de quaisquer interações resultantes.




Injeção de SQL em diferentes partes da consulta
A maioria das vulnerabilidades de injeção SQL surgem dentro da cláusula WHERE de uma consulta SELECT. Esse tipo de injeção de SQL geralmente é bem compreendido por testadores experientes.

Mas as vulnerabilidades de injeção de SQL podem, em princípio, ocorrer em qualquer local da consulta e em diferentes tipos de consulta. Os outros locais mais comuns onde ocorre a injeção de SQL são:

Nas instruções UPDATE, dentro dos valores atualizados ou na cláusula WHERE.
Nas instruções INSERT, dentro dos valores inseridos.
Em instruções SELECT, dentro do nome da tabela ou coluna.
Em instruções SELECT, dentro da cláusula ORDER BY.




Injeção de SQL em diferentes contextos
Em muitas pesquisas por sql injection, você usou a string de consulta para injetar sua carga SQL maliciosa. No entanto, é importante observar que você pode realizar ataques de injeção SQL usando qualquer entrada controlável que seja processada como uma consulta SQL pelo aplicativo. Por exemplo, alguns sites recebem entrada no formato JSON ou XML e usam isso para consultar o banco de dados.

Esses formatos diferentes podem até fornecer maneiras alternativas para ofuscar ataques que seriam bloqueados devido a WAFs e outros mecanismos de defesa. As implementações fracas geralmente procuram apenas palavras-chave comuns de injeção de SQL na solicitação, portanto, você pode ignorar esses filtros simplesmente codificando ou escapando caracteres nas palavras-chave proibidas. Por exemplo, a seguinte injeção SQL baseada em XML usa uma sequência de escape XML para codificar o caractere S em SELECT:

<verificaEstoque>
<IdProduto>
123
</IdProduto>
<IdLoja>
999 &#x53;ELECT * FROM information_schema.tables
</IdLoja>
</verificaEstoque>


Isso será decodificado no lado do servidor antes de ser passado para o interpretador SQL.




Fatores específicos do banco de dados
Alguns recursos principais 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 bancos de dados comuns. Isso significa que algumas técnicas para detectar e explorar a injeção de SQL funcionam de maneira diferente em diferentes plataformas. Por exemplo:

– Sintaxe para concatenação de strings.
– Comentários.
– Consultas em lote (ou empilhadas).
– APIs específicas da plataforma.
– Mensagens de erro.


Injeção de SQL de segunda ordem
A injeção de SQL de primeira ordem surge quando o aplicativo recebe a entrada do usuário de uma solicitação HTTP e, durante o processamento dessa solicitação, incorpora a entrada em uma consulta SQL de maneira insegura.

Na injeção SQL de segunda ordem (também conhecida como injeção SQL armazenada), o aplicativo recebe 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 em que 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 de SQL de segunda ordem geralmente surge em situações em que os desenvolvedores estão cientes das vulnerabilidades de injeção de SQL e, portanto, manipulam com segurança o posicionamento inicial da entrada no banco de dados. Quando os dados são processados posteriormente, eles são considerados seguros, pois foram previamente colocados no banco de dados com segurança. Nesse ponto, os dados são tratados de maneira insegura, porque o desenvolvedor erroneamente os considera confiáveis.




Como evitar a 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 de 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:

String query = “SELECT * FROM produtos WHERE categoria = ‘”+ input + “‘”;
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(consulta);



Esse código pode ser facilmente reescrito de forma a impedir que a entrada do usuário interfira na estrutura da consulta:


PreparedStatement statemenbt = connection.prepareStatement(“SELECT * FROM products WHERE category = ?”);
statement.setString(1, entrada);
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 na consulta, incluindo a cláusula WHERE e valores em uma instrução INSERT ou UPDATE. Eles não podem ser usados para lidar com entradas não confiáveis em outras partes da consulta, como nomes de tabelas ou colunas ou a cláusula ORDER BY. A funcionalidade do aplicativo que coloca dados não confiáveis nessas partes da consulta precisará adotar uma abordagem diferente, como lista branca de valores de entrada permitidos ou usar 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 cadeia de caracteres usada na consulta deve sempre ser uma constante embutida em código e nunca deve conter nenhum dado variável 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 strings na consulta para casos considerados seguros. É muito fácil cometer erros sobre a possível origem dos dados ou que alterações em outro código violem suposições sobre quais dados estão corrompidos.




One thought on “SQL Injection”

Leave a Reply

Your email address will not be published. Required fields are marked *

× Fale conosco