- 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/usernamerecoverye/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
bgresponsedo 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/usernamerecoverye obtinha, noLocationda resposta, o valoressvinculado àquele número- Os cookies e o valor
gxferam obtidos do HTML da página inicial
- Os cookies e o valor
- Em seguida, era enviado para
/signin/usernamerecovery/lookupoess, nome, sobrenome ebgresponse=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
- Sem conta:
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.000candidatos
- Como números móveis holandeses começam com
- Provedores como a Vultr oferecem uma faixa IPv6
/64, permitindo teoricamente usar18.446.744.073.709.551.616endereços - Foi criado um PoC que configurava um endereço IPv6 aleatório da sub-rede a cada requisição com
reqwesteClientBuilder.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
bgresponsedo 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 em03 - Nesse caso, se o primeiro nome fosse
Henry,usernamerecovery/challengeera 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 área61,62,63,64,65,68e quantidade de dígitos[7]
- O exemplo da Holanda inclui código do país
- 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
- Era possível obter o
bgTokencom uma chamada parahttp://localhost:7912/api/generate_bgtoken
- Era possível obter o
- 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
gpbpara 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
- EUA
- 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
- Exemplo:
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.