Ataques
Como burlar manualmente os filtros de SQLi

Analista de segurança
Updated
8 min
Entre as vulnerabilidades mais recorrentes estão as falhas de injeção, não à toa elas ocupam o primeiro lugar na lista OWASP Top Ten. Esse tipo de vulnerabilidade pode comprometer toda a sua segurança e infraestrutura; praticamente qualquer entrada pode ser um vetor de injeção, e todas precisam ser controladas. Aqui, a SQL injection desempenha um papel importante, não só pelo risco de vazamento de informações, mas também porque pode levar à execução remota de comandos ou ao acesso à rede interna.
Essa vulnerabilidade ocorre quando um atacante injeta código nas consultas que a aplicação faz ao banco de dados, interferindo em seu funcionamento normal. Isso acontece porque os desenvolvedores não validaram corretamente a entrada de dados nem aplicaram as boas práticas para recuperar dados do banco de dados. Vou te dar um exemplo; imagine este trecho de código:
Código comum vulnerável a SQLi
Aqui criei o código típico de uma página de login que verifica o usuário e a senha. As variáveis são recebidas por uma requisição POST, e não há validação de entrada. Um atacante poderia simplesmente usar o conhecido payload de SQLi 1' or '1'='1 e burlar o formulário de login. Mas, se eu filtrar alguns caracteres como a OR keyword ou single quote de aspas simples, estaria tudo bem? Não muito.
Laboratório de bypass de SQLi
Para configurar nosso laboratório, vamos usar o Vagrant da Hashicorp’s; os arquivos-fonte estão abaixo. Crie uma pasta chamada SQLie salve o Vagrantfilenela.
Configurando o laboratório
Vagrantfile
Em seguida, execute o ambiente usando
Vagrant up
Isso criará uma máquina Linux com LAMP instalado e configurado. Neste ponto, já temos tudo o que precisamos e estamos prontos para lançar um ataque.
Agora podemos configurar nossa máquina atacante. Aqui também estamos usando Kali Linux com Vagrant, mas você pode usar o sistema operacional que preferir.
Estas são as ferramentas que vamos usar:
Se você estiver usando o Kali, tudo isso já vem instalado por padrão.
Estamos prontos para começar.
Enumerando nosso servidor
Primeiro, precisamos verificar as portas do servidor. Podemos usar o nmap ou o ncat para isso.
Escaneamento de portas
Saída do nmap
NC
Our server runs Apache on port 80. Then using Dirbuster, we can search for directories on the web server.
Dirbuster
Como podemos ver, há um site de administração ao qual não temos acesso e um site comum onde estão nossos casos de teste.
Ataques de bypass de SQLi
Existem três casos de teste; o primeiro é o mais simples. Ele filtra as palavras-chave OR|AND e também o caractere de espaço.
Primeiro filtro de SQLi
O nome de usuário não é injetável porque usa uma instrução preparada (isso foi feito assim para mostrar a forma correta de fazer consultas). Se colocarmos qualquer um desses caracteres na consulta, ela deve responder com um alerta Wrong.
Para burlar isso, precisamos substituir essas palavras-chave: a palavra-chave OR pelo caractere de barra vertical dupla ||, e a palavra-chave AND pelo caractere de e comercial duplo &&. Neste caso, precisamos codificar isso em URL por causa do tipo de conteúdo da aplicação web, resultando em %26%26. Por fim, o caractere de espaço pode ser burlado usando várias substituições, como as seguintes:
O comentário de bloco
/**/O caractere ascii %09 de tabulação horizontal
O caractere ascii %0a de nova linha
O caractere ascii %0b de tabulação vertical
O caractere ascii %0c de nova página
O caractere ascii %0d de retorno de carro
Assim, nosso conhecido payload de SQLi mudará para algo como '/**/||/**/1=1#
Primeiro bypass
O próximo caso de teste é um pouco mais complicado: ele filtra os mesmos caracteres de antes, além do caractere de aspas simples. Além disso, remove o uso da instrução preparada na variável de usuário, mas também valida o caractere de aspas simples.
Segundo filtro de SQLi
Então, o que podemos fazer para burlar isso? O caractere de barra invertida \ é um caractere de escape especial usado para indicar outros caracteres especiais dentro de strings. Isso é útil no nosso caso porque, se injetarmos esse caractere no campo de usuário, o caractere de aspas simples ao lado dele vai agir como um caractere literal, e a string do nome de usuário terminará logo ao lado do campo de senha:
Exemplo de barra invertida
É apenas uma questão de injetar nosso código ali; o payload no usuário será \, e no campo de senha será /**/||/**/1=1/**/--
Segundo bypass
O último exemplo combina tudo isso e adiciona mais filtros ao código; é um tipo diferente de vulnerabilidade, porque vamos burlar o filtro dentro de uma palavra-chave ORDER BY.
Terceiro filtro de SQLi
Aqui quase não podemos usar palavras-chave ou funções, e o union select também não vai funcionar. Para coletar dados do banco de dados a partir de uma palavra-chave ORDER BY , precisamos usar uma SQLi baseada em erro ou uma baseada em tempo.
Então, a primeira injeção servirá para testar a vulnerabilidade; vamos injetar uma SQLi simples baseada em erro em que, se for verdadeira, ela ordenará os itens usando o id, e se for falsa, vai ordená-los usando o name:
?by=if(false,id,name)?by=if(true,id,name)
Agora, vamos adicionar outra camada. Queremos extrair informações a partir disso, e para conseguir isso precisamos fazer algumas consultas. Neste exemplo, vamos obter a senha do usuário guest (se você quiser obter a senha do admin, deve tentar por conta própria). Como os caracteres =, aspas simples e aspas duplas estão filtrados, precisamos de outra forma de obter a informação do usuário que queremos. Aqui temos o operador IN e a função CHAR. O operador IN nos permite especificar múltiplos valores em uma cláusula WHERE, mas também podemos usar apenas um se quisermos, e a função CHAR retorna o caractere ASCII correspondente a um número. Usando os dois elementos, uma consulta para a senha de guest ficaria mais ou menos assim:
Consulta da senha de guest
Aqui, a string guest é a combinação dos caracteres ASCII 103,117,101,115,116. Agora, a função MIDvai nos ajudar a extrair caracteres dessa consulta e obter a senha caractere por caractere. Esta consulta vai obter o primeiro caractere da senha:
Caractere da senha de guest
Em seguida, precisamos compará-lo com outro caractere; aqui vamos usar IN e CHAR novamente:
Comparação da senha de guest
Finally, we put our query into the previous IF function and replace the spaces with the block comment:
Com isso, conseguimos obter a senha de guestusando a função ORDER BY. Fazer isso manualmente levaria bastante tempo, então vamos automatizar com Python. A primeira coisa de que precisamos é uma função que faça nossas consultas e retorne a resposta:
Função para fazer a requisição
Em seguida, precisamos percorrer cada elemento da senha e cada caractere ASCII:
Consulta iterativa
E, por fim, verificamos se a lista está ordenada por id:
É isso: crie o exploit, execute-o e espere pelo resultado. Isso também poderia ser feito com qualquer outra consulta, por exemplo, para obter o hash da senha de um usuário do MySQL.
Solução
A primeira coisa que quem tem esse problema precisa fazer é implementar instruções preparadas; não há como fugir disso. Injeções podem ocorrer em praticamente qualquer provedor de banco de dados (senão em todos). Com essas instruções, o software terá consultas de dados mais robustas, e o uso de consultas dinâmicas será descartado.
O próximo passo é aplicar listas brancas para validar a entrada do usuário. Quando os desenvolvedores usam filtragem por lista negra, como nos exemplos acima, existe o risco de deixar passar algum parâmetro que permita a injeção. Listas brancas são uma abordagem melhor porque permitem apenas o que está nelas, e mais nada.
Por fim, há a implementação do princípio do menor privilégio. Já encontrei vários bancos de dados executando consultas com o usuário root; é melhor usar usuários limitados em nossas aplicações, porque isso reduz o raio de ação dos atacantes que, no pior cenário, conseguem acesso ao banco de dados.
Se você quiser mais informações sobre proteções contra SQLi, pode consultar a OWASP ou nossa base de dados.
Comece a usar a solução de ASPM da Fluid Attacks agora mesmo
Assine nossa newsletter
Mantenha-se atualizado sobre nossos próximos eventos e os últimos posts do blog, advisories e outros recursos interessantes.
Outros posts























