close up photo of mining rig

SQL Injection – Owasp Top 10

OWASP Top 10

Essa á listagem das 10 vulnerabilidades mais comuns em aplicações web como web sites. Vamos conhecer todas elas nessa série de vídeos. Mas não só como explorar essa vulnerabilidades mas também como implementar correções e proteções de segurança

Para começarmos os nossos estudos primeiro precisamos de algum serviço para direcionar os ataques, então inicie uma máquina virtual, eu vou utilizar Windows mas fica a seu critério qual você prefere. Vamos baixar o DVWA ou Danm Vulnerable Web App.

Xampp e DVWA

Primeiro precisamos do xampp, ele vai oferecer a nossa base com o Apache e o MySql
Eu vou fazer isso em uma máquina virtual, se você não sabe configurar uma assista o meu vídeo de instalação para o Kali Linux
Xampp Instalado

Agora vamos baixar o DVWA, eu vou utilizar o Git mas você pode baixar o zip também.

Agora que baixamos tudo que precisamos vamos fazer algumas configurações.
A primeira é colocar todo o conteúdo do DVWA para dentro da Pasta C:/Xampp/HtDocs

Entre na pasta CONFIG dentro dos arquivos do DVWA e altere o nome do arquivo para conter apenas a extensão .inc.php como a foto abaixo

Agora no Xampp na linha do MySQL clique em Admin

Isso vai abrir o PhpMyAdmin
Clique em Novo no lado esquerdo

Coloque o nome do Banco de dvwa e o tipo selecione agrupamento(A primeira opção)

Agora clique em Criar
Banco criado, vamos definir um usuário para o dvwa conectar clique em Privilégios na parte superior e coloque o usuário como dvwa e a senha p@ssw0rd
Se você ficar com alguma dúvida quanto ao usuário e a senha, volte no arquivo config que alteramos a extensão e abra ele com o bloco de notas

E de todas as permissões para facilitar a instalação

Depois é só ir até o final e clicar em Continuar, usuário criado podemos visitar o nosso localhost/dvwa para encontrar a aplicação

O que é SQL Injection

SQLi é um ataque onde executamos querys ao banco de dados utilizando algum tipo de input
Então imagine que vamos fazer um login, quando colocamos o nosso usuário e senha a aplicação deve enviar um query parecido com esse para o banco de dados

SELECT * FROM users WHERE name='mrseven' and password='senha123'

Onde a plataforma está pedindo para o banco de dados selecionar o usuário que tem o nome igual a mrseven e a senha igual a senha123. Quando ambos são verdadeiros ele realiza o login para você.
Ok, mas e o ataque?
A única coisa que temos controle nesse query é o nome do usuário e a senha certo?
Então o que aconteceria se eu adicionar uma aspas simples no usuário como mrseven’

SELECT * FROM users WHERE name='mrseven' ' and password='senha'

O query se altera, veja que agora o usuário fechou o conjunto de aspas dentro do próprio input que coloquei, isso deixa o banco confuso, pq tem uma sobrando e provavelmente vai gerar um erro, normalmente o erro 500
O que é interessante é que agora dentro do campo de usuário tudo que vier depois da aspas que colocamos está sob nosso controle, então eu posso alterar a query para buscar o que eu quiser nesse caso.

SQLi DVWA

Introdução

Vamos ver isso na prática, deve facilitar muito o entendimento
Dentro da aba de SQL Injection no DVWA a gente tem um campo de busca por ID, não é um login mas vale a mesma coisa, qualquer interação com o Banco de dados é válido para esse tipo de ataque, seja ela qual for.
Se entrarmos no htdocs do xampp e dar uma olhada em qual query o php está enviando

$query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";

Veja que agora o nosso input está no ultimo campo o ID
Vamos começar adicionando uma para ver como o banco se comporta

$query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id'';";

Quebramos o serviço, isso é bom sinal, lembra que a gente esperava isso, dado que uma aspas a mais gera um erro.
se você tentar colocar um ID que não existe, ele não vai retornar nada certo?
Mas e se manipularmos essa query para tornar ela sempre verdadeira?
mrseven’ OR 1=1– –

$query  = "SELECT first_name, last_name FROM users WHERE user_id = 'mrseven' OR 1=1-- -';";

Sempre Verdadeiro

O 1=1 é sempre verdadeiro então estamos falando para o banco de dados, retorne o primeiro nome e o sobrenome caso o id seja mrseven que não é o caso ou 1=1 como isso é verdadeiro ele vai retornar todos os nomes. Depois disso adicionamos o símbolo de comentário para nos livrarmos daquela aspas que estava sobrando.
Conseguimos injetar a nossa query dentro da existente.
Ok mas e para executar outros comandos, uma SQL injection não permite mudar a Query já definida então o começo é estático, podemos apenas adicionar informações no nosso ponto de input, nesse caso ID

Union

Mas aqui entra a mágica do Union, um query com Union é basicamente juntar informações dentro de outra query preexistente.
Então nesse caso temos a query principal

SELECT 1, 2
SELECT first_name, last_name

`
Onde 1 é first_name e 2 é last_name
Se adicionarmos um UNION ele vai aproveitar a primeira query para adicionar mais valores

SELECT 1, 2 UNION SELECT 3,4

`
Para essa query o banco de dados vai retornar os valores da coluna 1 e 2 mas também da coluna 3 e 4.
Um detalhe muito importante aqui é o número de colunas, eles devem ser sempre iguais. Já vou explicar melhor…
Um banco de dados nada mais é que uma tabela contendo valores
Deixa eu mostrar um exemplo literalmente no Excel (Realmente é igual uma planilha)

Funcionamento do Banco de Dados

Digamos que essa seja a tabela do nosso banco de dados
Ele tem os dados que vimos anteriormente mas ele também tem dados a mais que nós não conseguimos ver como usuários e senha
O site nada mais é que uma consulta nesse tabela, ele procura o id e retorna os valores que estão na mesma linha

Com o uso do Union nós podemos colocar um valor a mais nessas respostas

Nesse caso utilizamos o Union para retornar as colunas Usuário e Senha também

SELECT nome, sobrenome FROM Usuários WHERE user_id = '2 ' UNION SELECT usuario, senha FROM Usuários-- -

Se olharmos o nosso PhpMyAdmin desse serviço a tabela é muito familiar com a do Excel que eu acabei de te mostrar, a ideia é que você pense em Bancos de Dados SQL como uma tabela mesmo. Mas veja que temos ainda mais valores que não estavam aparecendo.
Agora vamos de fato executar a Injection no nosso site. Em um caso real nós não teríamos o número de colunas, nesse caso nós temos pois o código fonte nos mostrou isso.
Mas para descobrir quantas colunas estamos carregando fazemos o seguinte:

Encontrando o Número de Colunas

Utilizamos o order by , isso é uma maneira boa de descobrir quantas colunas o sistema espera, se o input condizer com um número que faz sentido o sistema vai carregar, se não fizer sentido ele vai quebrar.
Então nesse caso estamos retornando 2 colunas então o “ORDER BY 1” vai funcionar e o “ORDER BY 2” também, porém qualquer número depois disso vai quebrar o sistema.

Se tentarmos utilizar o 3:

Lembrando de uma informação importante, não adianta contar os dados retornados ok? Nesse caso você poderia, mas normalmente o sistema retorna valores que não conseguimos ver na página, então pode ser que o php dessa página esteja esperando 3 valores mas só coloca em tela 2 deles, nesse caso utilizar 2 colunas não vai dar certo.
Agora já sabemos o número de colunas, perfeito! Mas e para descobrir o nome das colunas dentro do banco de dados? Podemos injetar uma query para isso dentro de uma das colunas.

Nome da Tabela e Nome das Colunas

Vamos utilizar um SELECT agora, lembrando que precisamos retornar o mesmo número de colunas, por isso descobrimos isso no passo anterior.
Podemos utilizar NULL para quando não queremos nada naquela coluna, nesse caso queremos só os nomes das tabelas;

1' UNION SELECT table_name,NULL FROM information_schema.tables-- -

Agora fazemos o mesmo para as colunas;

1' UNION SELECT column_name,NULL FROM information_schema.columns WHEERE table_name = 'users'-- -

Agora sim, sabemos o número de colunas e o nome das colunas então vamos criar um Payload para pegar as senhas e usuários;

1' UNION SELECT user,password FROM users-- -

Outros Ataques e Dicas

Blind SQL

Pronto! Conseguimos extrair informações do banco de dados.
Existem outros ataques utilizando SQL Injections como a Build SQL injection onde você não consegue ver nada que mostre os valores

Login Bypass

Ou por exemplo para passarmos uma tela de login, podemos passar aquele valor que é sempre verdadeiro e comentar a senha

Usuário: admin'-- -
Senha: Senha

Dessa forma o resto da query não é informada para o Banco de dados, então ele vai apenas procurar o usuário igual a ADMIN mesmo que a senha esteja errada.

Concat

Outra dica muito útil é usar o Concat quando você precisar passar dois ou mais valores em uma só coluna.
Digamos que nesse caso a gente só tivesse uma coluna em vez de 2, então mostrar o usuário e senha seria impossível certo? Você poderia fazer duas querys mas o que te garante que aquela senha de fato pertence ao usuário que você está procurando.
Podemos usar o Concat

1' UNION SELECT CONCAT(user,password),NULL FROM users-- -

Agora a senha e o usuário aparecem na mesma coluna.