0

Como é feito um ataque SQLi

criado por Jefrey em 28/08/2011 3:22pm
Ataque completo
Este tipo de ataque pode ocorrer não só em sistemas de login, mas em qualquer lugar desprotegido que possua acesso ao banco de dados.
Caso queira ver na prática como ocorre, baixe o aplicativo Damn Vulnerable (www.dvwa.co.uk), aponte a proteção para "Low" e clique em SQL Injection.
Você deve saber que comentários em consultas SQL são feitos com dois hífens seguidos de um espaço ("-- "). Isto é muito utilizado em um ataque de SQLi, pois permite ao atacante cancelar a execução de partes da consulta que não são interessantes para ele.
Vamos agora obter a quantidade de colunas existentes na tabela atual que podemos utilizar. Para isso, mandamos o servidor ordenar os resultados por uma determinada coluna, definida por um número. Ou seja, se ultrapassarmos este número, ultrapassaremos a quantidade de colunas, e o servidor nos retornará um erro. Vamos digitar o seguinte no campo:
1' ORDER BY 1-- 
Deu certo? Claro! Agora, vamos tentar:
1' ORDER BY 2-- 
1' ORDER BY 3-- 
É interessante saber que também podemos injetar via GET, os valores que são enviados via URL, injetando nossas instruções diretamente na mesma.
Note que quando tentamos ordenar pela terceira coluna, ele nos retorna um erro. Então, temos duas colunas utilizáveis. Vale ressaltar que mesmo com este resultado, faz bem saber que não é equivalente a real quantidade de colunas na tabela, mas sim a quantidade de colunas acessada pela instrução. Ou seja, pode ser que haja na tabela a coluna 'nome', 'sobrenome', 'login', 'senha' e 'id', além de outras, como 'endereco', 'email', não sabemos. Mas já sabemos que apenas duas destas colunas são requisitadas pelo sistema. Para nos certificarmos disto, vamos fazer:
1' UNION ALL SELECT 1-- 
Não obtivemos sucesso aqui.
1' UNION ALL SELECT 1,2-- 
Aqui obtivemos sucesso, pois não foi exibido erro do MySQL. Então, realmente apenas 2 colunas são acessadas pelo sistema.
Agora é bom saber que nós só acessaremos duas informações por vez, pois apenas duas informações são requisitadas pelo sistema. Se tentarmos obter mais de uma informação, teremos erros. Vamos então obter o nome de usuário logado no sistema, o nome do banco de dados atual e a versão do MySQL rodando ali. Como são duas por vez, vamos primeiramente obter o usuário e o banco de dados. E, em seguida, a primeira coluna (já que não há dados mais importantes) e a versão. Façamos os dois requests:
Código:
1' UNION ALL SELECT user(),database()--
Código:
1' UNION ALL SELECT 1,@@version--
Caso o banco de dados selecionasse 3 dados por vez (por exemplo, título, descrição e texto) poderíamos obter as 3 informações em apenas um request, fazendo user(),database(),@@version.
Agora, saibamos o seguinte: o servidor mantém um banco de dados chamado 'information_schema' com vários dados importantes, inclusive, os nomes de todas as tabelas acessíveis pelo usuário atual. Vamos listar todas as tabelas que podemos acessar:
Código:
1' UNION ALL SELECT 1,table_name FROM information_schema.tables--
E se o sistema requisitasse 3 informações por vez? Faríamos assim:
Código:
1' UNION ALL SELECT 1,2,table_name FROM information_schema.tables--
Notou o '2' ali no meio? Simplesmente requisitaríamos mais uma informação que seria inútil para nosso ataque.
Agora, note que o sistema nos retornou muitos nomes de tabela. Poderíamos fazer como o Havij, listar tabela por tabela, mas isso é perda de tempo. Procure apenas a tabela que lhe interessa, a julgar pelo nome. Pode ser algo como ''clientes'', ''login'', ''admin''... Use o bom senso, coisa que o Havij não possui. Não tente pegar a senha do PHPMyAdmin por ali, pois ela não é guardada no banco de dados, mas sim no arquivo config.inc.php.
No caso do DVWA, encontramos uma tabela chamada ''users''. Vamos verificá-la, listando suas colunas. Se não for a que queremos, apenas voltamos e tentamos com outra.
Código:
1' UNION ALL SELECT 1,column_name from information_schema.columns WHERE table_name=('users')--
Vemos aqui alguns nomes de colunas como user_id, first_name, last_name e password. Realmente há fortes indícios de que seja essa a tabela que procuramos. Vamos listar seu conteúdo. Se não for esta, voltamos e procuramos outra.
Mas, peraí! Você não falou que só podemos requisitar duas informações por vez? Sim. Mas, é para burlar isso que existe a gracinha do concat. Sua função é simples, apenas inclui mais de uma informação em apenas um dos resultados, fazendo o sistema acreditar que aquele valor trata-se realmente do valor requisitado, por estar tudo em apenas uma string. O separador que utilizaremos aqui é <=>, representado pelo hash 0x3c3d3e. Escolhi este pois é algo mais difícil de se colocar em um login, e assim é mais complicado que você se confunda. Mas isto não é nada de mais. Se quiser outro, utilize outro sem problemas, como o :, que é representado pelo hash 0x3a. Vamos pedir algumas informações:
Código:
1' UNION ALL SELECT 1,concat(user_id,0x3c3d3e,password,0x3c3d3e,user,0x3c3d3e,first_name,0x3c3d3e,last_name) from users--
Lembre-se que a ordem dos dados que você colocar no concat será a ordem retornada. Veja que obtemos vários resultados. As senhas estão criptografadas em MD5, ao que parece. Mas há vários sites que descriptografam o MD5 por brute-force e por um banco de dados. Duvida? Vá no Google e pesquise por "MD5 decrypter". Nessa altura, o website já era!

Comentários:

Nenhum comentário foi enviado ainda.

Novo Comentário:

(Você pode usar tags como <b>, <i> ou <code>. URLs serão convertidas para links automaticamente.)