mConnect MV - SQL Injection
Olá!
Continuando os tópicos de exploração da descontinuada aplicação mConnect do desenvolvedor MV (www.mv.com.br), hoje iremos abordar uma falha por injeção parcial de comandos SQL, que serve de base para o CVE-2020-23282.
Aproveito para informar que a ação de coletar informações de serviços não é caracterizado crime, uma vez que foi utilizado um ambiente controlado de teste. Esta matéria tem como fins apresentar os métodos utilizados por hackers para encontrar informações de empresas e apresentar aos desenvolvedores as falhas de segurança que suas aplicações web (portais, sites de atendimento, etc) possuem. Corrigir ou não é uma decisão dos desenvolvedores e gestores/clientes destas aplicações.
Por Iran Macedo, especialista em proteção de dados e segurança ofensiva / Pentest. 14/05/2020.
A falha de SQLi
A aplicação que usarei para demonstrar a coleta de usuários válidos é o mConnect, testado na versão 02.001.00. Esta versão foi descontinuada pelo desenvolvedor e não é mais ofertadas aos seus clientes, cujas versões mais novas e livres destas falhas encontram-se disponíveis para atualização e uso.
O banco de dados utilizado pela aplicação é um Oracle. A aplicação não trata o campo 'usuário', retornando um erro do Oracle quando inserido um caractere inesperado, como pode ser visto abaixo.
ORA-01756: string entre aspas não finalizada adequadamente
Vemos acima o teste básico de um SQL Injection: Inserimos uma 'aspas simples' em um dos campos e analisamos o retorno da aplicação. Caso a aplicação retorne um código de erro do banco, significa que o que foi enviado pela janela, chegou até o banco de dados sem ser tratado e gerou um erro inesperado, uma vez que uma aspas simples finaliza o código SQL do banco, deixando uma aspas simples sem ser fechada corretamente (sem o par de aspas). Ou seja, o código foi injetado no banco com sucesso e o banco nos retorna ser vulnerável ao SQL Injection.
Boolean, Error e Time-Based
Para injetar um código que possa explorar esta falha, usaremos da lógica booleana do banco. Se uma condição é verdadeira, então o banco retorna 'TRUE' e a aplicação permite acesso. Ele faz isso quando compara se o usuário e se a senha que você digitou são iguais ao usuário e senha que estão no banco de dados.
Porém, caso você digite o valor de um dos campos errado, ele verifica com o valor armazenado no banco e retorna 'FALSE', sinalizando que você digitou algo errado.
Então a injeção de comandos SQL numa aplicação depende sempre da resposta do banco. Desta forma, vamos inserir um código que fecha a entrada do campo com uma aspas simples e inserimos uma lógica que retorna verdadeiro. O código injetado para exploração: ' OR '1' = '1'--.
Veja no código acima que primeiro vem uma aspas simples, fechando a variável que receberia o seu usuário ou senha, depois inserimos uma sentença verdadeira, pois 1 será igual a 1 sempre. E, por fim, finalizamos a sentença, fechando-a com uma aspas simples e dois traços. Estes dois traços significam que qualquer coisa digitada após este sinal deve ser ignorado, inclusive a validação da própria senha deve ser ignorada. Vamos ver se funciona:
Veja! O código injetado funcionou parcialmente, pois o usuário digitado (código) foi aceito pela aplicação, sem erros. Porém a aplicação fez uma segunda verificação em outra linha de verificação no banco (verificação em duas etapas), onde a senha foi inserida não corresponde a senha que está no banco (!que senha?) para este usuário (!que usuário?). Bugs.
E mesmo que eu insira no campo senha o código de injeção SQL e suas variações, nada funciona, pois para este campo, a aplicação trata/sanitiza o valor inserido, não permitindo o envio de caracteres especiais, como aspas simples, aspas duplas, barras e contra-barras, etc.
Desta forma, a injeção funciona apenas para um campo (usuário), enquanto a sua segunda validação (senha) não se mostra vulnerável ao ataque.
O que fazer agora?
Bem... já que a aplicação aceitou o código como um usuário válido, que tal dispararmos algumas senhas para a aplicação e vermos se o banco retorna TRUE (verdadeiro) para alguma destas senhas?
Vamos utilizar o programa de Brute Force THC-Hydra para realizar esta tarefa.
Segundo as tentativas de logon do Hydra, o banco retornou verdadeiro para o código SQL injetado e para a senha '123'. Vamos ver se é possível o acesso na aplicação.
Foi possível o acesso na aplicação com um usuário inexistente, pois a aplicação é falha ao tratar os dados inseridos no campo usuário. E, com a ajuda de um bot, conseguimos encontrar uma senha válida para este usuário inexistente.
Automatizando a invasão
Outro método é utilizar a ferramenta SQLMap para automatizar a invasão.
Ao final, você terá acesso à todos os dados existentes dentro do banco de dados da aplicação podendo, inclusive, utilizar os recursos do SQLMap para dar comandos no sistema operacional do servidor do banco de dados.
Correção da falha
Segundo informações passadas pelo desenvolvedor, o programa mConnect foi descontinuado e não recebe mais atualizações ou suporte. Para continuar a utilizar o serviço, o novo programa, que substituiu o mConnect é o Vivace Connect, disponível para aquisição através de contato com o desenvolvedor.
Conclusão
A injeção parcial de comandos SQL numa aplicação pode não funcionar 100%, jogando um atacante diretamente dentro da aplicação. Porém, permite que este atacante possua mais uma possibilidade para ataque e para invasão da aplicação e posse dos dados.
Desta forma, como já de ciência de todos, não utilizem softwares desatualizados ou descontinuados por seus desenvolvedores. E, caso seja extremamente necessário o seu uso, seja lá por quais motivos forem, não exponha esta aplicação, furada na sua segurança, na internet.
Até!
Documentação formal para o CVE na Mitre: MeuGithub
CVE ID: CVE-2020-23282