Uma vulnerabilidade perigosa na popular biblioteca Sequelize





Olá, Habr! Este artigo será de interesse para aqueles que já estão usando a biblioteca Sequelize ou apenas vão trabalhar com ela. Abaixo, vamos dizer a você como a funcionalidade operatorAliases embutida pode ser prejudicial e como evitar um vazamento de seu próprio banco de dados.



O que é Sequelize, onde é usado e para quê?



Sequelize é uma biblioteca Node.js ORM para Postgres, MySQL, MariaDB, SQLite e Microsoft SQL Server que mapeia tabelas em bancos de dados e seus relacionamentos com classes. Ao usar o Sequelize, não precisamos escrever consultas SQL, mas devemos trabalhar com dados como com objetos comuns. Ele tem suporte transacional robusto, relacionamentos, carregamento ativo e lento, replicação de leitura e muito mais.



O que são operatorAliases e qual é o perigo?



Sequelize usa operadores de caracteres por padrão. Usar o Sequelize sem apelidos simbólicos, é claro, melhora a segurança. Embora a falta de aliases de string torne a injeção de operador extremamente improvável, devemos sempre validar e limpar a entrada do usuário corretamente.



E a própria opção operatorAliases permite que você defina se os operadores de alias estarão disponíveis. Aqui está a aparência de um exemplo de ativação no código:







Quando tudo funciona bem



Vejamos o código do aplicativo de demonstração. O arquivo de modelo user.model.js contém: Você







pode ver que existem três campos na tabela de usuários e todos eles têm um tipo de dados de string.



O arquivo do controlador auth.controller.js contém:







O código usa o método findOne no modelo de usuário. E o método findOne retorna a primeira linha do banco de dados de acordo com a condição de consulta passada. Nesse caso, o aplicativo recebe os dados de nome de usuário e senha do usuário e os aplica a uma consulta na tabela de usuários.



A solicitação gerada neste caso será semelhante a esta:

SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` = :username AND `users`.`password` = :password LIMIT 1;







Como o ORM é usado para formar consultas, a injeção SQL trivial não funcionará. Se nenhuma correspondência de usuário for encontrada no banco de dados, o aplicativo retornará o erro Usuário não encontrado. Se os dados de entrada corresponderem ao nível do banco de dados, o aplicativo comparará a senha inserida com a senha armazenada no banco de dados e retornará a mensagem "Senha inválida!" se não corresponder, ou um token de autorização se for bem-sucedido. O algoritmo de validação de dados de entrada foi escolhido especificamente para testar a vulnerabilidade.



A tabela conterá os seguintes dados: A











autorização está funcionando corretamente.



E quanto a operadores e aliases?









Aliases são denotados pelo símbolo “$”, a sintaxe para aliases é semelhante ao MongoDB. Operadores de pesquisa, comparações e muitos outros estão disponíveis para nós. Apesar da forte digitação dos dados no modelo, a transferência de dados do usuário para o ORM no formato JSON acarreta normalização. E aqui começa a diversão!



Quando o problema bate no DOM



Ataque em lote







Este tipo de solicitação ao aplicativo inicia uma solicitação ao banco de dados:

Executando (padrão): Com este ataque, você pode verificar muitos logins para uma senha específica para validade em uma solicitação ao servidor e vice-versa. O ataque funciona na versão mais recente da biblioteca para dezembro de 2020 (6.3.5) e com a opção OperadoresAliases desabilitada. SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` IN ('admin', 'more', 'much more') AND `users`.`password` = 'wrong pass' LIMIT 1;











Ataque de conversão de tipo de dados



Se você passar dados como ...







... para o aplicativo , nada acontecerá no nosso caso. Embora a condição lógica no banco de dados seja correta, verificar a senha no aplicativo em estudo no nível do aplicativo e comparar diferentes tipos de dados não pode retornar verdadeiro.



Ataque do operador de comparação







De acordo com os dados da captura de tela, será gerada uma consulta ao banco de dados do formulário: O banco de dados retorna os dados, pois há uma correspondência entre nome de usuário = admin e uma senha que não é igual a “aaa”. Para passar por todo o processo de autorização, precisamos obter uma senha.

SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` = 'admin' AND `users`.`password` != 'aaa' LIMIT 1;











Regex e ataque de pesquisa de string



Você pode obter os dados brutos usando os aliases para os operadores de pesquisa $ like ou os operadores $ regexp para trabalhar com expressões regulares.







Quando o símbolo não convergir, será gerado um erro informando que o usuário não foi encontrado.







Se o símbolo corresponder, haverá um erro sobre a senha errada. Uma consulta do formulário é executada no banco de dados: Assim, caractere por caractere, você pode restaurar os dados da tabela.

SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` = 'admin' AND `users`.`password` LIKE 'E%' LIMIT 1;











Ataque de comparação de coluna em uma tabela



Existe um apelido interessante $ col que permite comparar um campo a um campo.







A consulta ao banco de dados irá: Executar a seguinte consulta ao banco de dados: Assim, ela cumprirá a condição lógica no nível do banco de dados.

SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` = 'admin' AND `users`.`password` = `aaaaa` LIMIT 1;













SELECT `id`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` = 'admin' AND `users`.`password` = `password` LIMIT 1;









Livrando-se de vulnerabilidades



  • Você precisa instalar a versão mais recente da biblioteca Sequalize, onde o suporte para aliases foi removido.



    ( Fonte )

  • Desative o uso de aliases definindo operatorAliases: false.
  • Valide completamente os tipos de dados e seus valores do usuário antes de usá-los no ORM.


Obrigado pelo seu interesse!



All Articles