針對 Fomo 用戶的惡意書籤釣魚攻擊分析
金色財經
作者:Yao & Lisa
編輯:77
一、背景
近期慢霧安全團隊收到一位 Fomo 用戶的求助。用戶反饋,他在 Fomo 網頁端查看 MOONLET 代幣詳情時,點擊了頁面展示的項目官網入口,進入 voltage.family,並按提示完成「人機驗證」,隨後發現帳戶內約 4.8 萬美元資產被轉走。整個過程中,他沒有連接錢包、進行鏈上授權,也沒有輸入助記詞或私鑰。該用戶通過 Google 登錄 Fomo,稱賬號未開啟二次驗證。
接到反饋後,慢霧安全團隊對相關頁面及腳本展開分析,發現所謂的「人機驗證」會引導用戶添加並點擊惡意書籤。書籤內嵌 JavaScript 代碼,目標是在 Fomo 頁面中讀取瀏覽器儲存、提取登錄令牌,並將數據發送至外部地址。
本文圍繞釣魚頁面和腳本還原攻擊過程,重點分析惡意書籤如何竊取嵌入式錢包的訪問憑證。
(釣魚站點首頁偽裝成交易產品頁面,並設置訪問入口)
MistEye 響應
MistEye 是由 SlowMist 自主研發的 Web3 威脅情報與動態安全監控系統,集成了安全監控與情報聚合能力,為用戶提供實時的風險預警與資產守護。
MistEye 已第一時間通過情報推送與客戶告警通道同步風險。
二、釣魚分析
釣魚入口來源
根據用戶補充的截圖,當時他正在查看 Fomo 上的 MOONLET 代幣詳情頁。紅箭頭標出了代幣名稱旁的官網入口,右側項目介紹區域也有「官網」按鈕。結合用戶反饋,本次訪問釣魚站點的入口來自該代幣詳情頁展示的外部鏈接。
(Fomo 的 MOONLET 代幣詳情頁及項目官網入口)
偽造人機驗證
用戶訪問的站點為 voltage.family。進入 /app 頁面後,頁面展示九個圖標,要求用戶找到「四條腿的動物」,將其拖到瀏覽器書籤欄,再連續點擊該書籤三次。拖拽時,頁面還會顯示操作引導,讓用戶誤以為這是正常驗證步驟。
(偽造的人機驗證頁面)
(頁面引導用戶將圖標拖入瀏覽器書籤欄)
最終添加的書籤名為 Triple click to verify。它保存的並非普通網頁地址,而是一段以 javascript: 開頭的代碼,即 bookmarklet。用戶點擊這種書籤時,代碼會在當前頁面中執行;攻擊者正是藉此誘導用戶在已登錄的 Fomo 頁面運行惡意腳本。
這種通過惡意書籤在目標頁面執行 JavaScript 的攻擊方式並不陌生。此前,慢霧安全團隊也曾分析過一起 Discord Token 竊取案例,詳見《慢霧:揭露瀏覽器惡意書籤如何盜取你的 Discord Token》。
惡意書籤投遞
頁面上的動物圖標會隨機出現,但用戶選哪個圖標並不影響最終添加的惡意書籤內容。fomo-track.js 讀取頁面內嵌的 BMCODE,替換訪客標識後,將所有 a.mini-bookmark 元素的 href 設置為同一段書籤代碼(以下為樣本原文,已省略外層取值與判空邏輯):
替換動作會在頁面 DOM 變化、定時器觸發、鼠標按下和拖拽開始時反覆執行,以覆蓋頁面原本的書籤鏈接。正常加載頁面時,九個圖標均指向這段代碼。所謂「識別動物」,實際是在為惡意書籤的投遞提供藉口。
(書籤實際內容為 javascript 代碼)
驗證後的 /app/live 頁面繼續模仿交易終端。界面註明市場數據為模擬數據,連接錢包按鈕僅彈出提示。結合前面的引導過程,這些頁面主要是為了把釣魚站點偽裝得更可信。
(驗證後展示的模擬交易終端)
本地數據採集
書籤代碼壓縮後有八千多字符。最外層使用 location.hostname.includes("fomo.family") 判斷當前頁面主機名,符合條件才繼續執行。這裡用的是字符串包含判斷,而不是嚴格域名匹配,因此凡主機名中包含 fomo.family 的頁面都可能滿足條件,不能理解為只會在 fomo.family 及其合法子域下執行。
這也說明,單純打開釣魚網站並不等於已經執行了後續採集邏輯。腳本需要在符合條件的頁面上下文中運行,才能讀取該頁面可訪問的儲存。
採集函數 v() 首先遍歷 localStorage 和 sessionStorage。它按鍵名匹配 privy、wallet、share、secret、seed、mnemon、turnkey、dynamic、fomo、mfa 等關鍵詞;鍵名未命中時,再檢查值的前 300 個字符。命中的數據最多保留 4000 個字符,存入對象 o。
隨後,腳本調用 indexedDB.databases() 獲取當前上下文可訪問的數據庫,逐一遍歷 object store,通過 getAll() 讀取記錄,並按「庫名/表名」保存。該流程設置了 4 秒超時,避免單個採集步驟長時間阻塞。
採集範圍同時覆蓋登錄憑證和錢包相關數據。在嵌入式錢包場景下,這些數據可能涉及錢包訪問、恢復和密鑰材料;一旦泄露,攻擊者可能進一步控制錢包。
登錄憑證提取
腳本優先查找 privy:token 和 privy:refresh_token,並通過 y() 處理可能包裹在 JSON 中的 token 或 accessToken 字段。如果沒有找到固定鍵名,則逐步放寬匹配範圍,查找其他 token 字段,同時排除 id_token、identity 等不屬於目標令牌的字段。最後,腳本還會嘗試從值中提取以 eyJ 開頭的 JWT 片段。該兜底方式只能選出疑似令牌,並不保證結果有效。
TOTP 註冊
取得訪問令牌後,腳本攜帶 Bearer 令牌、Privy 應用 ID 和客戶端 ID,請求 https://auth.privy.io/api/v1/users/me,並讀取響應中的 mfa_methods(或 mfaMethods)字段,以判斷賬號已綁定的二次驗證方式;該數組是否為空,直接決定後續 MFA 分支是否執行。腳本同時包含返回 401 時藉助刷新令牌重試請求的處理。
腳本還包含收到 401 後向 /sessions 提交刷新令牌的邏輯:以 refresh_token 為請求體,代碼先對響應調用 .json() 解析,再取其中的 token 字段作為新的訪問令牌,取得後重新請求 /users/me(在 MFA 事件通道中捕獲到 unauthorized/401 時,也走同一條刷新路徑重試)。
與 MFA 相關的代碼會創建一個 4×4 像素、透明度為 0.01 的 iframe,加載 Privy 的 embedded-wallets 頁面,再通過 postMessage 發送事件請求。消息按隨機請求 ID 對應,默認等待 6 秒;就緒檢查以 100 毫秒為間隔,最多等待 8 秒。
腳本嘗試以 TOTP 為方法初始化註冊,並從響應中提取 secret 或 totpSecret。若取得密鑰,它會在本地按 30 秒時間步長、HMAC-SHA1 和動態截斷計算六位驗證碼,再提交註冊請求。該邏輯的意圖是將攻擊者掌握的 TOTP 密鑰用於帳戶驗證。
這裡需要區分「發起註冊」與「註冊成功」。初始化返回密鑰,不代表服務端已經完成綁定;腳本將包含 already、exist、enrolled、duplicate 等字樣的錯誤視為可繼續處理,也不能證明新密鑰已生效。
代碼中,這段 MFA 邏輯的觸發條件很明確:只有當 /users/me 返回的 mfa_methods 非空,也就是賬號已綁定至少一種二次驗證方式時,腳本才會創建 iframe、調用 privy:mfa:init-enrollment 獲取 TOTP 密鑰並提交註冊;如果該數組為空,整段 MFA 邏輯都不會執行。用戶稱其賬號原先未開啟二次驗證,因此這部分很可能沒有觸發。但這不影響本地數據和憑證的採集、外傳,因為 ls 與 idb 是獨立通道。另需注意,發起註冊不等於註冊成功,是否真正綁定仍需服務端記錄確認。
登錄憑證泄露如何危及錢包資產
本次攻擊針對的是用戶已登錄的 Fomo 頁面及其嵌入式錢包訪問憑證。惡意書籤執行後,會採集 Privy 訪問令牌、刷新令牌及錢包相關本地數據,並發送至攻擊者控制的地址。這些憑證涉及錢包的訪問與恢複流程,泄露後可能被用於接管錢包,進一步導出私鑰或發起交易。因此,即使用戶沒有主動連接錢包、簽署鏈上授權或輸入助記詞,也可能面臨資產被盜的風險。當前展示的腳本主要負責採集和外傳,後續具體採用哪條路徑完成資產轉移,還需結合進一步的調查結果確認。
數據外傳
發送前,腳本把採集結果組織為 ls、idb 和 mfa 三部分,分別對應 localStorage、IndexedDB 記錄以及 MFA 方法和處理結果。再進行 base64url 編碼。編碼後超過 11000 個字符時,腳本先刪減 IndexedDB 記錄,保留與 privy、share、wallet、key、secret 相關的內容;若仍超限,則將本地儲存部分縮減為 privy:token、privy:refresh_token 和 mfa-session-storage 三個關鍵字段。流程另設 20 秒兜底發送,避免一直等待採集結束。
外傳目標為 noisy-heart-5856.zmfkc29.workers.dev。腳本採用兩種方式發送:一是在取得 TOTP 初始化密鑰後,通過 fetch 提前發送,密鑰放在 initsecret 參數中;二是通過 location.href 跳轉,把令牌、採集數據以及腳本保留的 TOTP 密鑰放入 URL 參數。
t:訪問令牌;
r:刷新令牌;
vid:訪客標識;
site:站點標識;
Is:經 base64url 編碼的採集數據;
initsecret:初始化階段取得的 TOTP 密鑰;
totp:腳本最終保留的 TOTP 密鑰。
對該地址進行非破壞性測試時,根目錄、未知路徑以及攜帶憑證參數的請求都返回 302,並跳轉回 voltage.family;POST /visit 返回 204。該響應符合「接收數據後把用戶送回釣魚站點」的設計,但僅憑響應本身無法確認服務端是否保存了數據。
fomo-track.js 開頭還保留了一段注釋,描述 tracker → Cloudflare Worker → panel → Telegram 的數據鏈路,並稱復用了舊驗證頁的中繼。這屬於樣本作者留下的線索,尚未獲得後台面板或 Telegram 側證據支持。
/* voltage tracker -> cloudflare worker -> panel -> telegram
(same relay the old captcha page uses; no keys in this file) */
綜合頁面和代碼,可以還原出誘導添加書籤、在目標頁面執行腳本、採集儲存、提取令牌、嘗試 MFA 操作及外傳數據的鏈路。憑證是否被實際重放、後續交易由誰發起,仍需結合服務端日誌和鏈上記錄核實。
三、MistTrack 資金分析
根據受害者提供的資訊,共 45,106.85 USDC 被駭客分三次提現到駭客地址 D783JqupQ2FYhkxUfGEd1gaFEoAJDXRX1NEb4aVH2hZ6,我們使用慢霧旗下鏈上追蹤 & 反洗錢工具 MistTrack 對該地址進行反洗錢分析。
駭客地址(D783Jq…hZ6) 從 9 月 17 日開始活躍,在受害者資金進入前,該地址已經存在較為頻繁的 USDC ↔ SOL 資金交互,推測存在其他受害者。
鏈上可以觀察到多筆金額相近的 USDC 兌換為 SOL,也存在反向兌換 SOL → USDC,兌換多數通過 Jupiter Aggregator 完成。兌換後的 SOL 並未長期留存在該地址,而是被進一步發送至大量不同的中間地址,例如 HGSe...Ucim、3XyKap...gXVj 等地址。同時,也可以觀察到部分 USDC 被直接拆分發送至多個地址,例如向 HGSe...、2th9... 等地址連續轉出多筆 USDC 和 SOL。
該地址還通過 Relay.link 將 SOL 轉換為其他鏈上的資產,例如:
0.6 SOL → 0.024 ETH,目標 Ethereum 地址 0x77bd56dfef9530ba61962a420e34a0dbd55de51c;0.59 SOL → 0.025 ETH,目標同一 Ethereum 地址;
0.29 SOL → 0.012 ETH,目標同一 Ethereum 地址;
0.29 SOL → 0.00039 BTC,進入 Bitcoin 地址 bc1q6j54xfvlgqjw6mq2ja3pym3qrezp8k39aeftxh
除向外跨鏈外,該地址還接收了通過 deBridge 跨鏈轉入的資金。其中,一筆由 Robinhood 鏈上的 USDG 兌換為 Solana上的 USDC,另一筆由 BNB Chain 上的 USDC 跨鏈轉入。
該地址向 Privacy Cash Pool 共轉入 1568.33 SOL,也是該地址最主要的洗錢出口:
此外,部分資金最終流向博彩平台相關地址。例如,該地址曾將部分 USDC 兌換為 SOL 後轉入 Stake 平台,也有部分 SOL 直接轉入 Stake 平台。
再如,後續資金還多次進入 Winna 相關地址,包括向 Winna deposit 地址轉入 11.34 SOL 和 1,500 USDC,以及從 Winna hot wallet 接收 7,199.81 USDC。
從 D783Jq…hZ6 的整體資金行為來看,該地址呈現出較為明顯的多層拆分、資產兌換、跨鏈轉移和平台充值特徵。我們將持續關注相關地址的後續資金轉移。
四、IOC
釣魚頁面與數據外傳
hxxps://voltage[.]family/app
hxxps://voltage[.]family/app/live
noisy-heart-5856[.]zmfkc29[.]workers[.]dev
樣本 SHA256
index.html
24df225d70e399fa30a2d0761e8645e339d99a0f751af6f9e5e00ab555e2fa07
fomo-track.js
6d771096e442b36b0719a4e07b19c62a5a985005e8a07ab5d50dd6ca59c4ad06
VerifyRoute
d5576bb50cb299d0c48657ed0cfd3f03b4c2313db8b37abcee57f779d70f7f18
LiveTerminal
193b305baf9548a6dded341f3dd613a811e4604c7dfa4447219664f6c43818f8
五、總結
本次分析發現,攻擊者將惡意 JavaScript 包裝成瀏覽器書籤,並用「人機驗證」引導用戶在已登錄的 Fomo 頁面執行。其目標包括 Privy 登錄憑證和錢包相關本地數據,風險涉及嵌入式錢包控制權及資產安全。用戶沒有主動輸入私鑰或簽署鏈上授權,並不意味著錢包未受影響。
從樣本看,攻擊者通過惡意書籤採集並外傳憑證,為後續接管錢包提供條件。用戶反饋損失約 4.8 萬美元;本次事件最終通過私鑰導出還是錢包簽名等方式完成轉移,仍需進一步核實。
給用戶的建議
正常的人機驗證不需要把網頁圖標拖進書籤欄,再到錢包或交易頁面點擊執行。遇到這類要求,應立即停止操作。定期檢查書籤欄,刪除來歷不明的 javascript: 書籤,並為重要賬號開啟平台支持的多因素驗證。
如果已經執行過可疑書籤,應從可信設備訪問官方渠道,優先撤銷異常會話和相關授權,檢查並移除陌生的驗證器,同時聯繫平台協助處置。通過 Google 等第三方身份登錄的用戶,也應檢查對應身份賬號的安全狀態。不要只依賴修改密碼,現有會話和刷新令牌是否同步失效,需要以平台的實際機制為準。
如有證據表明助記詞或私鑰已經泄露,應使用全新生成的錢包轉移剩餘資產。保留可疑頁面地址、書籤內容、操作時間和交易記錄,有助於後續調查。
給項目方的建議
對 MFA 新增、替換、恢復以及資金轉移等敏感操作設置獨立的驗證和風控要求,避免只憑已有會話就完成安全設置變更。向用戶提供會話查看與撤銷入口,對異常設備、來源和 MFA 變更及時告警,並確保服務端能夠按需撤銷相關憑證。
同時檢查客戶端儲存的敏感數據範圍,減少長期有效憑證的暴露。對外鏈、用戶生成內容及站內引導加強審查,明確提醒用戶不要在已登錄頁面執行陌生書籤或代碼。若發現類似頁面,可保留線索並向慢霧安全團隊反饋。
來源:金色財經
發佈者對本文章的內容承擔全部責任
在投資加密貨幣前,請務必深入研究,理解相關風險,並謹慎評估自己的風險承受能力。不要因為短期高回報的誘惑而忽視潛在的重大損失。
暢行幣圈交易全攻略,專家駐群實戰交流
▌立即加入鉅亨買幣實戰交流 LINE 社群(點此入群)
不管是新手發問,還是老手交流,只要你想參與加密貨幣現貨交易、合約跟單、合約網格、量化交易、理財產品的投資,都歡迎入群討論學習!
- 讓加密貨幣幫你滾出年化30%現金流
- 掌握全球財經資訊點我下載APP
延伸閱讀
- 講座
- 公告
上一篇
下一篇