摘要

本報告詳細描述了在 Google 使用者名稱恢復機制中發現的一個重大漏洞,在修補之前,該漏洞允許列舉並暴力破解與 Google 帳戶相關聯的電話號碼。該漏洞利用了無 JavaScript 版本的恢復表單的意外行為,結合了來自其他 Google 服務(如 Looker Studio 和密碼重置流程)的訊息洩漏。通過從標準啟用 JS 的表單中獲取有效的 BotGuard token,攻擊者可以繞過無 JS 端點的速率限制,實現高速探測電話號碼和顯示名稱的組合。本報告剖析了涉及的技術步驟,分析了被攻擊的端點,討論了 IPv6 和 BotGuard 繞過技術的使用,並概述了完整的攻擊鏈,包括獲取必要先決訊息(如國家代碼和顯示名稱)的方法。

Google 帳戶漏洞揭秘:你的電話號碼如何被輕易洩漏? | 資訊安全新聞

1. 簡介

調查始於測試 Google 服務在無 JavaScript 環境下的功能。令人意外的是,位於 accounts.google.com/signin/usernamerecovery 的使用者名稱恢復表單在無 JavaScript 的情況下仍能運作。這出乎意料,因為類似的帳戶恢復表單被認為自 2018 年以來需要 JavaScript 和高度混淆的工作量證明(Proof-of-work)程式碼來實施防濫用措施,如 BotGuard。這一觀察開啟了潛在的濫用途徑,特別是自動化探測或暴力破解的可能性,這通常會受到此類防濫用機制的阻礙。

2. 利用無 JavaScript 的使用者名稱恢復端點

核心漏洞存在於禁用 JavaScript 時,使用者名稱恢復表單的後端處理。該過程涉及兩個主要的 HTTP Request:

  • Request 1: 對 /signin/usernamerecovery 發送 POST Request,包含恢復電子郵件或電話號碼(例如,Email=+18085921029)。此Request將返回一個 302 Found 重新導向回覆,包含一個帶有 ess 參數的 Location 標頭。此 ess 值似乎與送出的聯繫訊息相關聯。

(Request 1 分析): 這個初始Request用於驗證聯繫方式(電話或電子郵件)的存在,並啟動與其相關聯的 session 狀態(ess)。gxf 參數的角色未明確詳述,僅知其來源於初始頁面 HTML,可能與 session 或 CSRF 保護有關,但似乎不是被繞過的主要防濫用控制點。

  • Request 2: 對 /signin/usernamerecovery/lookup 發送後續 POST Request。此Request包含從第一個Response中獲取的 ess 值、hardcoded 的 bgresponse=js_disabled 參數,以及顯示名稱欄位(GivenName, FamilyName)。

(Request 2 分析): 這是列舉的關鍵Request。它允許檢查是否存在與電話號碼(由 ess 值識別)相關聯並匹配提供的顯示名稱(例如 "John Smith")的 Google 帳戶。Response是一個 302 Found 重新導向,根據是否匹配條件,會導向 /signin/usernamerecovery/noaccountsfound(無匹配帳戶)或 /signin/usernamerecovery/challenge(找到匹配)。bgresponse=js_disabled 參數明確指示客戶端的 JavaScript 執行狀態。

3. 初始暴力破解嘗試與速率限制

使用這兩個Request序列對電話號碼和名稱組合進行暴力破解的初步嘗試,遇到了基於 IP 位址的速率限制,幾次Request後即出現 captcha。這表明雖然 JavaScript 防濫用未完全啟用,但仍存在某種基本的速率限制。

4. 嘗試使用 IPv6 繞過速率限制

繞過基於 IP 的速率限制的常見技術是使用大範圍的 IP 位址並為每個Request輪換。IPv6 提供了巨大的位址空間,例如 /64 範圍提供了超過 18 京(Quintillion)個位址,這在理論上是一種可行的方法。Google 帳戶伺服器已確認支持 IPv6。

作者使用 Rust 語言和 reqwest 庫實現了一個名為 gpb 的概念驗證(PoC)程式來測試這一點。提供的程式碼片段展示了生成指定子網內隨機 IPv6 位址的函數,以及創建設定為使用該特定本地位址的 reqwest 客戶端的函數。

(程式碼片段分析):

* get_rand_ipv6: 此函數接受 IPv6 CIDR 子網字符串(例如,"2001:db8::/64"),並在該子網內生成隨機的 IpAddr::V6。首先解析 CIDR 以獲取網路前綴和長度,然後取子網中第一個位址的網路部分,與隨機生成的值結合,移位形成主機部分。此處的 random() 函數是一個佔位符;實際使用需要加密安全的或至少標準的隨機數生成器。
* create_client: 此函數利用 get_rand_ipv6 函數從指定子網域獲取隨機 IP,然後構建一個 reqwest::Client 實例。關鍵設定包括禁用重新導向(redirect::Policy::none())和設置 local_address 為隨機生成的 IPv6 位址。danger_accept_invalid_certs(true) 值得注意,表明 PoC 可能遇到憑證問題,儘管這在生產程式碼中是危險的。
    

儘管使用了 IPv6 輪換,採用資料中心 IP 位址和無 JS 表單的 PoC 仍持續遇到 captcha。這表明 Google 的防濫用系統可能標記了資料中心 IP 或與此特定端點路徑上的自動化存取相關的其他Request特性。

5. BotGuard Token 繞過突破

審查 /signin/usernamerecovery/lookup Request時,bgresponse=js_disabled 參數尤為突出。作者回憶起標準啟用 JS 的表單通過 bgRequest 參數傳遞了一個 BotGuard token。假設是用從啟用 JS 流程中獲取的有效 BotGuard token 替換 js_disabled。

測試此假設證明是成功的。通過從合法的、啟用 JS 的 Google 帳戶恢復互動中獲取 bgRequest token(可能是手動執行步驟或使用 chromedp 等自動化工具),該 token 可以插入到無 JS 流程中 /signin/usernamerecovery/lookup Request的 bgresponse 參數中。這完全繞過了Request限制。使用此技術的 gpb 程式顯示快速的 "HIT" 結果。

(輸出分析): 輸出顯示 gpb 程式成功識別出符合提供標準(--prefix +316, --suffix 03, --digits 6, -f Henry, -l Chancellor)的電話號碼,並在 lookup 端點上產生 "HIT"。初步觀察是,這些命中發生在名為 "Henry" 且未設置姓氏的帳戶上,電話號碼以 "03" 結尾,無論在 lookup Request中提供何種姓氏。這意味著只要全名匹配或僅名字匹配且帳戶未設置姓氏,lookup 端點就會返回命中。

為解決此問題,作者改進了流程,對任何初始命中進行二次驗證檢查,使用隨機、不太可能的姓氏(例如,0fasfk1AFko1wf)。如果端點對隨機姓氏仍報告命中,則初始結果被過濾為誤報(僅表示名字匹配)。只有全名和電話號碼完全匹配時才算真命中。通過這一改進,對於同一全名和電話後綴/國家代碼獲得多個命中的可能性變得很低。

6. 訊息收集:顯示名稱與國家代碼

要執行目標暴力破解,攻擊者需要受害者的 Google 帳戶顯示名稱和國家代碼。

  • 國家代碼: 忘記密碼流程提供了一個遮罩的電話號碼提示(例如,荷蘭的 •• ••••••03),根據 libphonenumber 的國家格式進行格式化。通過將這些遮罩格式映射到國家,可以確定受害者的國家代碼。作者創建了一個腳本來收集此映射,存於 mask.json。

(mask.json 摘錄分析): 這展示了遮罩電話號碼的格式(•• ••••••••)如何直接揭示國家("nl" 表示荷蘭),因為 Google 使用 libphonenumber 的標準國家格式。

  • 顯示名稱: 由於 Google 在 2023 年和 2024 年更改了政策,除非有直接互動,否則大多數端點不再顯示名稱。然而,作者發現了一種無需受害者互動即可洩漏顯示名稱的方法:創建一個 Looker Studio 文件並將所有權轉移到受害者的電子郵件位址。受害者的顯示名稱隨後會出現在攻擊者的 Looker Studio 首頁上。

7. 優化與 BotGuard Token 生成

實施了進一步的優化以提高暴力破解的效率:

  • Libphonenumber 驗證: 使用 libphonenumber,程式可以根據每個國家的已知前綴、區碼和數字數量,使用 format.json 文件驗證生成的電話號碼。這減少了對 Google API 的無效號碼格式的無必要Request。

(format.json 摘錄分析): 這顯示了每個國家的結構化資料,包括國家代碼("31" 表示 "nl")、常用區碼或手機號碼前綴列表("61" 到 "68"),以及國家代碼後的預期總數字數(荷蘭手機號碼為 7 位)。這些資料支持客戶端驗證。

  • BotGuard Token 生成服務: 為了自動化獲取新鮮 BotGuard token 的過程,開發了一個使用 chromedp(可能是無頭瀏覽器自動化庫)的 Go 腳本,與啟用 JS 的表單互動並提取 token。此腳本提供了一個簡單的 API 端點(例如,http://localhost:7912/api/generate_bgtoken),返回有效的 token。

(Token 服務分析): 該服務將執行Headless瀏覽器並執行 Google 的 BotGuard JavaScript 的複雜過程抽象為一個簡單的 HTTP API 呼叫,使暴力破解程式(gpb)能夠按需求獲取 token,而無需直接管理Headless瀏覽器的複雜性。

8. 完整攻擊鏈

結合這些技術形成了完整的攻擊鏈:

  1. 使用 Looker Studio 轉移方法洩漏受害者的 Google 帳戶顯示名稱。
  2. 在忘記密碼流程中使用受害者的電子郵件(可能與顯示名稱一起獲得)以獲取遮罩的電話號碼提示。
  3. 從遮罩格式確定受害者的國家代碼。
  4. 使用 gpb 程式,結合洩漏的顯示名稱、國家代碼前綴和遮罩電話提示(提供最後 2 位數字),暴力破解電話號碼的其餘數字。gpb 程式將使用 BotGuard token 生成服務來繞過速率限制。

9. 性能與時間分析

暴力破解的效率取決於未知數字的數量。通過忘記密碼流程提示顯示的最後 2 位數字,大多數國家的可能性顯著減少。作者報告在一台消費級伺服器上實現了每秒約 40,000 次檢查。

暴力破解其餘數字所需的估計時間(假設未知數字數量為 N,可能性為 10^N):

  • 美國 (+1):20 分鐘
  • 英國 (+44):4 分鐘
  • 荷蘭 (+31):15 秒
  • 新加坡 (+65):5 秒

如果其他服務(如 PayPal 的 +14•••••1779 格式)提供了更多已知數字,這些時間還可以進一步縮短。

10. 時間線與修補

該漏洞於 2025-04-14 報告給 Google,於 2025-04-15 進行分級,並於 2025-05-15 初步授予 1,337 美元加贈品的獎勵。對初始低可能性評估提出上訴。Google 將可能性修訂為中等,並於 2025-05-22 將總獎勵提高至 5,000 美元。Google 確認於 2025-05-22 推出「Inflight Mitigations」,並於 2025-06-06 全球完全棄用無 JS 使用者名稱恢復表單。披露於 2025-06-09 進行協調。

11. 結論

本研究揭露了 Google 帳戶恢復流程中的一個關鍵漏洞鏈,源於對遺留無 JavaScript 端點的不完整防濫用措施應用。通過結合訊息洩漏技術(Looker Studio 用於顯示名稱,忘記密碼流程用於電話號碼國家代碼和提示)與繞過漏洞端點上 BotGuard 速率限制的新方法,攻擊者僅需目標的電子郵件位址即可有效列舉與特定 Google 帳戶相關聯的完整電話號碼。雖然 Google 現已完全棄用易受攻擊的無 JS 表單,但此案例突顯了在所有介面變體中保持一致安全控制的重要性,以及跨服務訊息洩漏增強攻擊能力的潛在風險。

Copyright © 2025 版權所有 翊天科技有限公司