1 pontos por GN⁺ 2025-06-10 | Ainda não há comentários. | Compartilhar no WhatsApp
  • O formulário de recuperação de nome de usuário sem JS do Google permitia verificar combinações de número de telefone e nome de exibição, criando uma cadeia de ataque capaz de descobrir o número de telefone completo de um usuário específico do Google
  • O ponto central era a diferença de redirecionamento entre /signin/usernamerecovery e /signin/usernamerecovery/lookup, que permitia distinguir entre os estados de conta inexistente e conta existente
  • Havia limitação de requisições por IP e CAPTCHA, mas ao inserir o token BotGuard do formulário com JS no bgresponse do formulário sem JS, tudo passou a funcionar sem restrições, combinado ainda com rotação de IPv6
  • O atacante podia obter o nome de exibição da conta Google via Looker Studio e reduzir bastante os candidatos combinando o número de telefone mascarado do fluxo de recuperação de senha com formatos de numeração por país
  • Em um servidor de 16 vCPU custando US$ 0,30 por hora, era possível fazer cerca de 40 mil verificações por segundo; o Google desativou completamente o formulário de recuperação de nome de usuário sem JS em 6 de junho de 2025 e pagou um total de US$ 5.000

Vulnerabilidade iniciada no formulário de recuperação de nome de usuário sem JS

  • Ao verificar o funcionamento dos serviços do Google com JavaScript desativado no navegador, foi descoberto que o formulário de recuperação de nome de usuário ainda funcionava
  • Considerava-se que o formulário de recuperação de conta exigia JavaScript por depender, desde antes, das defesas da família BotGuard, geradas por código JavaScript ofuscado com proof-of-work
  • Porém, o formulário sem JS oferecia um fluxo capaz de verificar se um e-mail de recuperação ou número de telefone estava vinculado a um determinado nome de exibição

Verificação da existência da conta com duas requisições

  • A primeira requisição enviava o número de telefone para /signin/usernamerecovery e obtinha, no Location da resposta, o valor ess vinculado àquele número
    • Os cookies e o valor gxf eram obtidos do HTML da página inicial
  • Em seguida, era enviado para /signin/usernamerecovery/lookup o ess, nome, sobrenome e bgresponse=js_disabled
  • Como o redirecionamento da resposta mudava, era possível determinar se existia uma conta Google com aquele número de telefone e nome de exibição
    • Sem conta: usernamerecovery/noaccountsfound
    • Com conta: usernamerecovery/challenge

Limite por IP, IPv6 e bypass do BotGuard

  • Nas tentativas iniciais, após algumas requisições, o endereço IP era submetido a limitação de requisições e um CAPTCHA era exibido
  • No exemplo de número móvel holandês, o fluxo de recuperação de senha fornecia uma dica como •• ••••••03
    • Como números móveis holandeses começam com 06, era necessário testar as 6 posições restantes, ou seja, 10^6 = 1.000.000 candidatos
  • Provedores como a Vultr oferecem uma faixa IPv6 /64, permitindo teoricamente usar 18.446.744.073.709.551.616 endereços
  • Foi criado um PoC que configurava um endereço IPv6 aleatório da sub-rede a cada requisição com reqwest e ClientBuilder.local_address
  • Ao usar o formulário com JS desativado a partir de IPs de datacenter, o CAPTCHA continuava aparecendo, mas ao inserir o token BotGuard do formulário de recuperação de conta com JS no bgresponse do formulário sem JS, as requisições passavam
    • No formulário sem JS, esse token BotGuard aparentemente não tinha limitação de requisições

Filtrando acertos incorretos

  • Os resultados iniciais incluíam várias contas com nome Henry, sobrenome vazio e número de telefone terminado em 03
  • Nesse caso, se o primeiro nome fosse Henry, usernamerecovery/challenge era retornado independentemente do sobrenome
  • Para validar possíveis acertos, foi feita nova verificação usando o mesmo primeiro nome, mas com um sobrenome aleatório como 0fasfk1AFko1wf
    • Se ainda assim aparecesse como acerto, era filtrado como falso positivo
  • Considerou-se baixa a probabilidade de existirem outros usuários do Google com exatamente o mesmo nome de exibição completo, o mesmo código de país e os mesmos dois dígitos finais

Obtenção do código do país e do nome de exibição

  • A máscara do número de telefone no fluxo de recuperação de senha podia ser usada para inferir o código do país
  • O Google usa o formato nacional de cada número com libphonenumber
  • Foram coletados formatos nacionais mascarados por país para criar o mask.json
    • Rússia, Holanda, Reino Unido e Estados Unidos têm padrões de máscara diferentes entre si
  • Em 2023, o Google mudou a política para mostrar nomes apenas quando houvesse interação direta com o alvo, e em abril de 2024 a Internal People API deixou totalmente de retornar nomes de exibição para contas não autenticadas
  • Porém, ao criar um documento no Looker Studio e transferir sua propriedade para a vítima, o nome de exibição da vítima era exposto na tela inicial sem qualquer interação da vítima

Otimização do espaço de candidatos e ferramentas

  • Usando a validação de números da libphonenumber, foi gerado o format.json com prefixos móveis por país, códigos de área conhecidos e quantidades de dígitos
    • O exemplo da Holanda inclui código do país 31, códigos de área 61, 62, 63, 64, 65, 68 e quantidade de dígitos [7]
  • A validação em tempo real com libphonenumber reduzia consultas à API do Google para números inválidos
  • Para gerar tokens BotGuard, foi criado um script em Go usando chromedp
  • O fluxo completo do ataque seguia três etapas
    • Vazamento do nome de exibição da conta Google via Looker Studio
    • Obtenção do número de telefone mascarado no fluxo de recuperação de senha
    • Uso de nome de exibição e telefone mascarado no gpb para força bruta do número completo

Desempenho da força bruta e tempo estimado

  • Em um servidor de US$ 0,30 por hora com 16 vCPU de especificações de consumidor, era possível realizar cerca de 40 mil verificações por segundo
  • Tempo estimado quando o fluxo de recuperação de senha fornecia apenas os dois últimos dígitos:
    • EUA +1: 20 minutos
    • Reino Unido +44: 4 minutos
    • Holanda +31: 15 segundos
    • Singapura +65: 5 segundos
  • Se o fluxo de redefinição de senha de outros serviços, como o PayPal, fornecesse mais dicas numéricas, o tempo poderia cair drasticamente
    • Exemplo: +14•••••1779

Cronologia do reporte ao Google e das medidas adotadas

  • 2025-04-14: relatório enviado ao fornecedor
  • 2025-04-15: o fornecedor recebeu e classificou o relatório
  • 2025-04-25: resposta “Nice catch!”
  • 2025-05-15: o painel definiu uma recompensa de US$ 1.337 + swag
    • A justificativa foi a avaliação de baixa probabilidade de exploração, e o problema foi reconhecido como metodologia de abuso de alto impacto
  • 2025-05-15: foi apresentada contestação da justificativa da recompensa
    • Segundo a tabela do Abuse VRP, probability/exploitability é determinada pelos pré-requisitos do ataque e pela possibilidade de a vítima perceber a exploração
    • Foi argumentado que esse ataque não tinha pré-requisitos e que a vítima não conseguiria perceber a exploração
  • 2025-05-22: o painel pagou mais US$ 3.663, ajustando a recompensa total para US$ 5.000
    • A likelihood foi elevada para medium
  • 2025-05-22: o fornecedor confirmou a implantação de medidas de mitigação em andamento até a desativação global do endpoint
  • 2025-05-22: coordenação da divulgação pública para 2025-06-09
  • 2025-06-06: o fornecedor confirmou a desativação completa do formulário de recuperação de nome de usuário sem JS
  • 2025-06-09: relatório publicado

Ainda não há comentários.

Ainda não há comentários.