💉Detectando e analisando SQL Injection

Olá! Nesse artigo, eu mostro brevemente como detectar alguns indicadores de um ataque SQL Injection.

O que é SQLi?

SQL Injection é um método crítico de ataque a aplicações web, onde a aplicação inclui diretamente conteúdo não higienizado fornecido pelo usuário em consultas SQL.

Os frameworks que são utilizados hoje em dia para desenvolver aplicações web possuem mecanismos preventivos contra ataques de SQL Injection. Porém, ainda existem vulnerabilidades de SQL devido ao uso de consultas brutas SQL, ou às vezes o framework também possui vulnerabilidades inatas de SQL Injection, ou o framework não é utilizado corretamente.

Tipos de SQLi

Existem 3 tipos de SQL Injection. São eles:

  1. In-band SQLi (Clássico) -> Se uma consulta SQL é enviada e respondida pelo mesmo canal, chamamos de In-band SQLi. É a metodologia mais fácil e mais utilizada por atacantes

  2. Inferential SQLi (Blind SQLi) -> Consultas SQL que recebem respostas que não podem ser lidas são chamadas de Inferential SQLi. São chamadas de consultas "chegas" porque sua resposta não pode ser vista

  3. Out-of-band SQLi -> Se a resposta da consulta SQL é enviada por um canal diferente, então essa injeção é chamada de Out-of-band SQLi. Por exemplo, se o atacante recebe múltiplas respostas de suas consultas SQL pelo DNS

Como o SQLi funciona?

Hoje em dia, as aplicações web padrão comumente recebem dados de um usuário e utilizam esses dados para mostrar determinado conteúdo. A maioria dos ataques SQLi são executados em páginas de login. Vamos examinar como injeções SQL funcionam.

Em uma página de login, espera-se que um usuário insira seu nome de usuário e sua senha. Do outro lado, a aplicação web utilizará as informações de nome de usuário e senha para criar uma consulta SQL semelhante à seguinte:

SELECT * FROM users WHERE username = 'USERNAME' AND password = 'USER_PASSWORD'

O significado dessa consulta é: "Quero saber todas as informações do usuário da tabela users cujo nome é USERNAME e cuja senha seja USER_PASSWORD". Se a aplicação encontrar um nome de usuário compatível com o que o usuário solicitou, ela autenticará o usuário. Se ela não encontrar um nome de usuário compatível, então o login não ocorre.

Vamos supor que nosso nome de usuário seja "john" e a senha seja "supersecretpassword". Quando você insere essa informação e clica no botão de login, a consulta SQL que vimos acima será executada e conseguiremos entrar na aplicação, pois as informações que passamos para a aplicação são compatíveis com as informações do banco de dados.

SELECT * FROM users WHERE username = 'john' AND passowrd = 'supersecretpassword'

E se utilizarmos esse mecanismo de uma maneira atípica e inserirmos um apóstrofo (ou aspas simples) ' no campo de nome de usuário? A consulta SQL provavelmente apresentará um erro e não validará o login.

SELECT * FROM users WHERE username = 'john'' AND password = 'supersecretpassword'

Se um atacante visualizar esse tipo de mensagem, ele certamente estará muito feliz. A partir dessas informações, podemos manipular essa consulta a nosso favor. E se utilizarmos um payload como esse a seguir?

‘ OR 1=1 -- -

Quando um atacante envia essa informação, a aplicação web executará a seguinte consulta SQL:

SELECT * FROM users WHERE username = '' OR 1=1 -- - AND password = 'supersecretpassword'

Na linguagem SQL, tudo que vier após os caracteres "-- -" será considerado como comentário. Então, analisando a consulta acima, a parte em que a senha é validada não será executada. Vamos remover essa parte para simplificar nosso entedimento:

SELECT * FROM users WHERE username = '' OR 1=1

Agora, nossa consulta executa o seguinte critério: "Se o nome de usuário estiver vazio ou 1 for igual a 1". Não é tão relevante se o campo "username" está preenchido ou não, pois 1 sempre será igual a 1. Por isso, essa consulta sempre será verdadeira e possivelmente chamará a primeira entrada no banco de dados. O atacante, então, será capaz de acessar a aplicação, pois ele executou uma consulta compatível.

O exemplo acima é um exemplo típico de SQL Injection. Os ataques SQLi não se limitam apenas a esse payload em específico, um atacante pode utilizar linguagem SQL para executar comandos remotamente em um sistema com a ajuda de comandos SQL, como por exemplo, o comando xp_cmdshell.

Finalidades do SQLi

Ataques de injeção SQL são comumente utilizados para os seguintes fins:

  • Burlar autenticação

  • Executar comandos

  • Exfiltração de dados sensíveis

  • Manipulação de entradas em bancos de dados

Como prevenir SQLi

  • Utilize um framework: Apenas utilizar um framework não é suficiente para prevenir um ataque SQLi. É de suma importância que o framework seja utilizado de acordo com a documentação

  • Mantenha seu framework atualizado: Para manter a aplicação web segura, é de grande importância que o framework também esteja atualizado

  • Sempre sanitize dados recebidos de usuários: Nunca confie nos dados recebidos por usuários. Não sanitize apenas os dados do formulário, mas também o faça em cabeçalhos, URLS etc.

  • Evite utilizar consultas SQL brutas: Muitas pessoas possuem o hábito de escrever consultas SQL brutas, mas se optarmos por utilizar um framework, podemos ter a segurança que ele nos fornece

Detectando ataques SQLi

Vimos acima o que atacantes podem fazer com um ataque de SQL Injection. Cada um dos resultados de uma injeção SQL mencionados acima podem causar grande impacto/perda para uma empresa, então devemos ser capazes de detectar tais tentativas de ataque e tomar ações para prevenir ataques desse tipo.

Mas como podemos detectar ataques de SQL Injection?

Na verdade, existe mais de uma resposta para essa pergunta. São elas:

  • Enquanto estiver analisando uma requisição web, cheque todas as informações advindas do usuário: Ataques SQLi não estão limitados apenas às áreas de formulário, você também pode checar os cabeçalhos das requisições HTTP, como o User-Agent, por exemplo

  • Procure por palavras-chave de linguagem SQL: Palavras como INSERT, SELECT ou WHERE dentro das informações recebidas do usuário

  • Familiarize-se com payloads frequentemente utilizados: Embora os payloads SQL possam mudar dependendo da aplicação web, atacantes utilizarão alguns payloads comuns para verificar se sua aplicação é vulnerável a SQLi. Alguns payloads mais frequentes podem ser encontrados nessa lista.

Detectando ferramentas automatizadas de SQL Injection

Atacantes também utilizam ferramentas que automatizam ataques de SQLi. Uma das mais conhecidas é o SQLMap. Porém, vamos olhar de forma mais abrangente, sem focar especificamente em uma ferramenta.

Podemos utilizar os seguintes métodos para detectar ativos de SQLi:

  • Analisar o User-Agent: Dispositivos automatizadores de SQLi geralmente possuem seus nomes e versões gravadas. Você pode olhar no cabeçalho "User-Agent" para tentar identificar esses dispositivos

  • Checar a frequência das requisições: Ferramentas automatizadas foram feitas para enviar uma determinada quantidades de requisições por segundo, para ser capaz de testar payloads o mais rápido possível. É comum que um usuário convencional envie uma requisição por segundo, então, se você verificar requisições com um intervalo de tempo mais curto, as requisições podem ter vindo de uma ferramenta automatizada

  • Analise o contexto dos payloads: Uma requisição forjada por uma ferramenta pode ter alguma característica específica em seu payload, como por exemplo sqlmap' OR 1=1

Exemplos de detecção

Temos como exemplo os logs de acesso de uma aplicação que sofreu um ataque de SQL Injection.

Caso você não saiba o que são logs de acesso: são registros de eventos de acesso, contendo informações do usuário, como endereço IP, método HTTP, User-Agent e código de resposta HTTP. Esses logs são muito úteis em investigações.

Agora nós temos logs de acesso em mãos. O que fazer?

Primeiro, devemos olhar para as páginas que foram solicitadas e verificar que, além de páginas como "info.php" que são facilmente legíveis, também existem requisições feitas para páginas de nomenclatura complexa, com símbolos como "%". Não podemos afirmar que requisições como essas são maliciosas, mas o fato de elas estarem registradas em grandes quantidades é minimamente suspeito.

Mas o que o símbolo % significa, afinal? Quando solicitamos uma página que contém caracteres especiais, essas requisições não são diretamente enviadas ao servidor. Ao invés disso, nosso navegador executa uma codificação de URL (por porcentagem) dos caracteres especiais e os substitui por uma string que se começa com o caracter % seguida de 2 caracteres hexadecimais. Então, as páginas que possuem o símbolo % no exemplo acima são páginas que contém caracteres especiais.

Agora que sabemos o que os símbolos % significam, vamos revisitar os logs de acesso. Olhando para as requisições, podemos facilmente ver que, além dos símbolos %, existem palavras como UNION, SELECT, AND e CHR. Devido a essas serem palavras específicas da linguagem SQL, podemos assumir agora que trata-se de um ataque de SQL Injection.

Para economizar nossos olhos, vamos fazer essa análise ficar um pouco mais fácil. Você pode pesquisar por "Online URL Decoder" na Internet para encontrar aplicações web que decodificam automaticamente o texto. Para facilitar a leitura dos logs de acesso, iremos aproveitar a praticidade dessas aplicações.

CONSELHO: Não é recomendado subir logs de acesso contendo informações críticas em aplicações de terceiros como essa.

Agora, com o conteúdo decodificado, podemos ver com mais clareza que se trata realmente de um ataque de SQL Injection. Mas o que fazemos agora? Sim, nos confirmamos que houve um ataque, mas simplesmente deixaremos ele aqui?

Claro que não. Agora procuraremos outros pedaços de informações que podemos coletar com esses logs.

Primeiramente, vamos olhar para as datas das requisições. Todos os payloads foram enviados em "19/Feb/2022 11:09:24". Podemos ver mais de 50 requisições enviadas em apenas 1 minuto. O fato é que muitas requisições foram feitas em um curtíssimo período de tempo, o que nos evidencia um ataque automatizado. Ainda, como mencionamos anteriormente, quando atacantes executam testes manuais, eles escolhem os payloads mais fáceis primeiro.

Confirmamos que um ataque de SQL Injection foi executado através de uma ferramenta automatizada. Podemos finalizar nossa análise, certo?

Errado. Ainda precisamos determinar se o ataque foi bem-sucedido ou não. Podemos determinar se um ataque SQLi foi bem-sucedido olhando a resposta das requisições, mas durante nossa execução, praticamente nunca teremos acesso à resposta. Podemos presumir que todas as respostas terão o mesmo tamanho, pois o ataque foi executado na mesma página e utilizando a variável "id". Podemos estimar o sucesso do ataque analisando o tamanho da resposta.

Infelizmente, o servidor web básico que foi desenvolvido para servir de exemplo não possui um tamanho de resposta confiável. Portanto, não podemos estimar se o ataque foi bem-sucedido analisando essa informação. Mas com servidores web configurados corretamente, podemos encontrar o tamanho da resposta dentro dos logs de acesso. Você pode examinar essa parte para identificar alguma diferença notável entre o tamanho das respostas. Se existir alguma diferença considerável, podemos estimar que o ataque foi bem-sucedido. Porém, nessa situação, o mais adequado seria escalar o alerta para um analista de maior alçada.

Informações obtidas com a análise de exemplo

  1. Um ataque de SQL Injection ocorreu no parâmetro "id" na página principal da aplicação

  2. As requisições vieram do seguinte endereço de IP: 192.168.31.174

  3. Devido a ocorrência de mais de 50 requisições por segundo, detectamos que o ataque executado veio de uma ferramenta automatizada

  4. A natureza complexa dos payloads reforçam a afirmação anterior

  5. Não podemos determinar se a resposta foi bem-sucedida ou não, pois não temos nenhuma informação sobre o tamanho da resposta.

Last updated