ORM Injection
Django ORM (Python)
Em este post é explicado como é possível tornar um Django ORM vulnerável usando, por exemplo, um código como:
Note como todos os request.data (que será um json) são passados diretamente para filtrar objetos do banco de dados. Um atacante poderia enviar filtros inesperados para vazar mais dados do que o esperado.
Exemplos:
Login: Em um login simples, tente vazar as senhas dos usuários registrados nele.
É possível forçar a senha até que ela seja vazada.
Filtragem relacional: É possível percorrer relações para vazar informações de colunas que nem eram esperadas para serem usadas na operação. Por exemplo, se for possível vazar artigos criados por um usuário com essas relações: Article(
created_by
) -[1..1]-> Author (user
) -[1..1]-> User(password
).
É possível encontrar a senha de todos os usuários que criaram um artigo
Filtragem relacional muitos-para-muitos: No exemplo anterior, não conseguimos encontrar senhas de usuários que não criaram um artigo. No entanto, seguindo outros relacionamentos, isso é possível. Por exemplo: Article(
created_by
) -[1..1]-> Author(departments
) -[0..*]-> Department(employees
) -[0..*]-> Author(user
) -[1..1]-> User(password
).
Neste caso, podemos encontrar todos os usuários nos departamentos de usuários que criaram artigos e, em seguida, vazar suas senhas (no json anterior, estamos apenas vazando os nomes de usuário, mas depois é possível vazar as senhas).
Abusando das relações muitos-para-muitos de Grupo e Permissão do Django com usuários: Além disso, o modelo AbstractUser é usado para gerar usuários no Django e, por padrão, esse modelo possui algumas relações muitos-para-muitos com as tabelas de Permissão e Grupo. O que basicamente é uma maneira padrão de acessar outros usuários a partir de um usuário se eles estiverem no mesmo grupo ou compartilharem a mesma permissão.
Contornar restrições de filtro: O mesmo post do blog propôs contornar o uso de alguns filtros como
articles = Article.objects.filter(is_secret=False, **request.data)
. É possível despejar artigos que têm is_secret=True porque podemos voltar de um relacionamento para a tabela Article e vazar artigos secretos a partir de artigos não secretos, pois os resultados são unidos e o campo is_secret é verificado no artigo não secreto enquanto os dados são vazados do artigo secreto.
Abusando de relacionamentos, é possível contornar até mesmo filtros destinados a proteger os dados exibidos.
Baseado em erro/tempo via ReDoS: Nos exemplos anteriores, esperava-se ter respostas diferentes se o filtro funcionasse ou não para usar isso como oráculo. Mas pode ser possível que alguma ação seja realizada no banco de dados e a resposta seja sempre a mesma. Nesse cenário, pode ser possível provocar um erro no banco de dados para obter um novo oráculo.
SQLite: Não possui um operador regexp por padrão (é necessário carregar uma extensão de terceiros)
PostgreSQL: Não possui um tempo limite de regex por padrão e é menos propenso a retrocessos
MariaDB: Não possui um tempo limite de regex
Prisma ORM (NodeJS)
Os seguintes são truques extraídos deste post.
Controle total de busca:
É possível ver que todo o corpo javascript é passado para o prisma para realizar consultas.
No exemplo do post original, isso verificaria todos os posts criados por alguém (cada post é criado por alguém) retornando também as informações do usuário dessa pessoa (nome de usuário, senha...)
O seguinte seleciona todas as postagens criadas por alguém com uma senha e retornará a senha:
Controle total da cláusula where:
Vamos dar uma olhada onde o ataque pode controlar a cláusula where
:
É possível filtrar a senha dos usuários diretamente como:
Usando operações como startsWith
, é possível vazar informações.
Contornando filtragem relacional muitos-para-muitos:
É possível vazar artigos não publicados ao retornar às relações muitos-para-muitos entre Category
-[*..*]-> Article
:
É também possível vazar todos os usuários abusando de alguns relacionamentos muitos-para-muitos de loopback:
Error/Timed queries: No post original você pode ler um conjunto muito extenso de testes realizados para encontrar a carga útil ideal para vazar informações com uma carga útil baseada em tempo. Isso é:
Onde o {CONTAINS_LIST}
é uma lista com 1000 strings para garantir que a resposta seja atrasada quando a vazamento correto for encontrado.
Ransack (Ruby)
Esses truques foram encontrados neste post.
Observe que o Ransack 4.0.0.0 agora exige o uso de uma lista de permissão explícita para atributos e associações pesquisáveis.
Exemplo vulnerável:
Note como a consulta será definida pelos parâmetros enviados pelo atacante. Foi possível, por exemplo, forçar o token de redefinição com:
Por meio de força bruta e potencialmente relacionamentos, foi possível vazar mais dados de um banco de dados.
Referências
Last updated