引言
在 2026年9月29日和2026年10月1日 期間,攻擊者利用 NEAR Intents 的入金退款處理機制,建立了沒有相應資產作為支撐的內部餘額。經核實,從 BNB Chain 上的 HOT Bridge 金庫進行的七筆提領共轉出了 3,865,021 USDT。專案隨後發布的事後檢討將此缺陷歸因於 NEAR Intents 合約,並表示所有受影響資金已於 10 月 2 日歸還 [1]。
要理解退款缺陷如何產生可提領的餘額,必須沿著 NEAR 的非同步執行流程追蹤入金。以 NEAR 建構應用的開發者必須考慮狀態何時提交、誰能呼叫後續步驟,以及失敗如何影響整體流程。稽核也必須檢查完整流程中這些環節的交互作用。
根據我們稽核 NEAR 合約及分析安全事件的經驗,本文藉由此案例探討 NEAR 非同步結算的安全性。我們首先介紹理解這次攻擊所需的背景:NEAR 的非同步呼叫與收據、代幣轉移與退款,以及 NEAR Intents 與 HOT Bridge 之間的關係。接著,事件分析將說明漏洞與攻擊過程,並介紹修復措施和資金追回情況。最後,我們討論狀態管理與回呼處理,再延伸探討帳戶授權與儲存成本。
背景
以下分析仰賴三項 NEAR 特有的背景知識:非同步跨合約呼叫如何執行、NEP-141 和 NEP-245 如何處理代幣轉移與退款,以及 HOT Omni Balance 帳本上的資產如何支撐 NEAR Intents 記錄的內部餘額。
NEAR 上的非同步跨合約呼叫
在 Ethereum 上,合約 A 會同步呼叫合約 B 並等待其返回結果 [2];NEAR 則會安排跨合約作業於稍後執行。因此,發起呼叫、外部呼叫和回呼並不共用同一個執行上下文 [3]。此模型有兩個核心術語:
-
Promise: 合約安排執行的作業,例如呼叫另一個合約,或在之後執行回呼。
-
收據(Receipt): 網路用來執行操作並在帳戶之間傳遞結果的訊息。動作收據會在目標帳戶上執行已安排的操作,資料收據則會將執行結果傳送給相依的動作收據 [4]。
下圖以三個動作收據呈現這個呼叫與回呼流程。在收據 A 中,合約 A 更新自身狀態,並建立 Promise 以呼叫 B。收據 B 執行 B 的邏輯。圖中省略的資料收據將 B 的結果傳送至收據 C,由 A 的回呼處理該結果。收據 A 可以在 B 或回呼執行前完成,並提交其狀態。

由於這些動作收據各自獨立執行,合約可以在等待期間處理其他請求。如果回呼收據失敗,該收據內所做的變更會回滾,但原始收據已提交的狀態仍會保留。失敗無法向前傳遞以撤銷該狀態,因此應用程式必須明確恢復一致性。
代幣標準與非同步退款結算
NEP-141 和 NEP-245 是 NEAR 上的代幣標準。NEP-141 涵蓋同質化代幣,大致相當於 Ethereum 上的 ERC-20。NEP-245 涵蓋多種代幣類型與批次操作,大致相當於 ERC-1155 [5] [6] [7] [8]。
這種對應關係並不完全相同。一般的 NEAR 代幣轉移會將資產傳送至目的地 receiver_id,其所指向的帳戶可能有合約程式碼,也可能沒有。在此討論的轉移並呼叫流程中,接收方是實作了 NEP-141 所需的 ft_on_transfer(),或 NEP-245 所需的 mt_on_transfer() 的合約帳戶。接收方的鉤子函式在一個收據中執行;代幣合約隨後在另一個收據中執行 ft_resolve_transfer() 或 mt_resolve_transfer(),確定最終使用量及退款金額。因此,源自單筆使用者交易的流程可能跨越多個收據。
接收方透過其鉤子函式回報未使用的數量。此回傳值是結算的輸入值,不一定是最終退款金額。在 NEP-141 的 near-contract-standards 參考實作中,結算函式會依據原始轉移數量及接收方的可用餘額,限制回報的未使用數量。回應失敗或無效時,系統首先將其視為要求退還全額轉移數量,之後再套用相同限制 [9]。依據 NEP-245,若 Promise 鏈失敗,多代幣結算函式必須撤銷代幣轉移 [8]。無論哪種情況,代幣層級的退款都不會自動撤銷接收方在先前收據中提交的應用程式狀態。
NEAR Intents 與 HOT Bridge
NEAR Intents 是 NEAR 上以意圖為基礎的結算協議。使用者將資產存入 intents.near,該合約會將其記錄為內部餘額。使用者之後可以簽署意圖,兌換或提領這些餘額 [10]。
HOT Bridge 也稱為 HOT Omni Bridge,提供跨鏈資產層。資產鎖定在外部鏈上的合約中,而對應的全鏈資產則在 NEAR 上的 HOT Omni Balance 合約中鑄造。HOT Omni Balance 實作了 NEP-245 代幣帳本 [11]。
因此,這項整合包含三個記帳層:鎖定在外部鏈上的資產、該資產在 HOT Omni Balance 中的全鏈資產表示,以及使用者在 intents.near 中的內部餘額。這些層之間必須保持一致。
下圖以一筆 10 單位的入金為例,呈現 Intents 將金額記入內部餘額後的兩條分支。若沒有入金動作,mt_on_transfer() 會回傳未使用數量為零,且不呼叫接收方的鉤子函式。若有 DepositAction::Notify,Intents 會呼叫接收方,之後再透過 mt_resolve_deposit(),根據接收方的回應調整記入內部餘額的金額。在 Notify 分支中,接收方使用 6 單位,並回報 4 單位未使用。HOT Omni Balance 的 mt_resolve_transfer() 會退還這 4 單位,使使用者的內部餘額保留 6 單位,而其 NEP-245 帳本中則有額外 6 單位作為支撐 [12]。

事件分析
我們從三個部分檢視此次事件:漏洞分析說明退款處理如何可能留下沒有資產支撐的內部餘額;攻擊分析追蹤利用此行為的交易與收據;修復與追回則涵蓋所做的變更及據報已歸還的資金。
漏洞分析
以下原始碼分析以專案用於重現問題的修訂版本 35044fd 為基礎 [13]。退款驗證不足可能產生過大的退款事件,導致回呼失敗,使內部餘額與持有的資產不一致:
-
退款金額驗證不足。
intents.near中受影響的入金路徑會依據接收方的餘額及請求限制退款,卻沒有納入正在結算的轉移所存入的數量。因此,若既有餘額很大,就可能使退款金額遠超過本次入金數量。
-
過大的退款事件。 包含長代幣識別碼與大額退款值的批次,可能產生序列化後超過日誌大小限制的
MtBurnEvent。使用emit()發出該事件可能導致退款回呼中止 [14]。此限制適用於事件酬載,包括其中的陣列與格式;單憑數值很大的退款,無法斷定事件會超出限制。
入金事件使用轉移的數量,因此較小的項目可使該事件保持在限制內。之後的退款事件則使用結算函式接受的數量。若沒有以入金數量設定上限,檢查原始事件也無法確保金額更大的退款事件符合限制。
-
退款結算不一致。 Intents 的
mt_resolve_deposit()回呼在其自身的收據中扣減內部餘額及供應量。如果發出退款事件導致該收據失敗,這些扣減就會回滾,但先前入金收據所提交的入帳金額仍會保留。上游代幣合約接著可能退還已轉移的資產,使保留下來的內部入帳金額失去相應資產的支撐。重複此過程可能進一步推高沒有資產支撐的內部餘額。
最優秀的 Web3 安全稽核機構
上線前驗證設計、程式碼與業務邏輯
攻擊分析
攻擊者使用一種代幣填充退款事件(「填充代幣」),並利用惡意接收方觸發過大的退款請求,反覆推高沒有相應資產支撐的內部餘額。專案報告共有 23 筆失敗的入金交易 [1]。經核實,七筆提領從 BNB Chain 上的 HOT Bridge 金庫轉出了 3,865,021 USDT。
此次攻擊涉及多筆交易。本文分析聚焦於附錄 A 所列的 13 筆關鍵交易,並依功能將其分為三個階段。
-
階段 1:準備(Tx 1–4)。 攻擊者取得測試所需的資產、部署惡意接收合約,並預先為其內部填充代幣餘額注資。
-
階段 2:餘額放大(Tx 5–6)。 Tx 5 和 Tx 6 分別是已識別的第一筆和最後一筆餘額放大交易。
-
階段 3:在 BNB Chain 上出金(Tx 7–13)。 攻擊者利用膨脹的內部餘額,從 BNB Chain 上的 HOT Bridge 金庫提出
USDT。
這些階段是對攻擊者行為的分類,並非三個互不重疊的時段。餘額放大與出金活動在時間上有所重疊。以下詳細重建以 Tx 5 及其完整的動作收據執行結果為依據,再核對 BNB Chain 上的七筆出金。
第一個餘額放大案例使用下表所示的惡意接收者;後續交易則使用其他惡意接收者帳戶。完整地址和代幣 ID 列於附錄 B。以下時間均為 UTC。
| 下文使用的名稱 | 角色 | 鏈 |
|---|---|---|
| 攻擊者 | 由攻擊者控制的交易發送者 | NEAR |
| 惡意接收者 | 通知回呼合約/內部餘額持有者 | NEAR |
| 填充代幣 | 攻擊者提供、用於填充批次的代幣 | NEAR |
USDT 表示形式 |
在 NEAR 上表示的 BNB Chain 資產 | NEAR |
USDT |
底層代幣 | BNB Chain |
| Intents | 內部結算合約 | NEAR |
| HOT Omni Balance | NEP-245 代幣帳本 | NEAR |
| BNB 接收者 | 由攻擊者控制的出金接收者 | BNB Chain |
| HOT Bridge 金庫 | 跨鏈資產金庫 | BNB Chain |
階段 1:準備(Tx 1–4)
-
步驟 1(Tx 1):9 月 29 日 12:30:44,攻擊者透過 HOT Bridge 取得
10e18個原始單位的 BNB ChainUSDT表示形式,並記入攻擊者在 HOT Omni Balance 中的帳戶。該代幣 ID 的後綴可解碼為附錄 B 中的 BNB ChainUSDT地址。以 18 位小數計,10e18個原始單位相當於 10USDT。 -
步驟 2(Tx 2):攻擊者透過 HOT Bridge 取得
97e36 + 97個原始單位的填充代幣。這種自訂代幣於當天稍早在 Osmosis 上建立並鑄造,隨後經由 Kava 和 Gonka 轉移,最後在 NEAR 上被領取;準備階段的紀錄詳見附錄 C。 -
步驟 3(Tx 3):攻擊者部署並初始化惡意接收合約。
-
步驟 4(Tx 4):攻擊者透過 HOT Omni Balance 的
mt_transfer_call(),將97e36個原始單位的填充代幣轉移至 Intents,並以msg指定惡意接收者。Intents 將款項記入惡意接收者的內部帳戶。這筆預先注入的餘額,使惡意接收者得以在 Tx 5 期間支應 97 筆退款請求,每筆為1e36個原始單位。
階段 2:餘額放大(Tx 5–6)
第一筆餘額放大交易 Tx 5 於 9 月 29 日 16:14:19 執行。其五份核心動作收據涵蓋批次轉移、入金、通知、失敗的帳務調整,以及上游退款。這些收據的識別碼和執行結果列於附錄 D。
-
步驟 5(Tx 5):攻擊者對 HOT Omni Balance 呼叫
mt_batch_transfer_call(),目標為 Intents。該批次包含 97 筆相同填充代幣的項目,每筆金額為 1 個原始單位,另有一筆金額為10e18個原始單位的USDT項目。Intents 的mt_on_transfer()將全部 98 筆項目記入惡意接收者名下,並發出MtMint入金事件。每筆填充項目的金額設為 1 是刻意安排的:入金流程呼叫check_refund(),以驗證初始事件及其預期的退款額外開銷是否符合日誌大小限制。較小的入金金額通過了這項檢查,而惡意接收者稍後提出的數額大得多的退款請求,則產生了超出大小限制的退款事件 [13]。
-
步驟 6(Tx 5):完成內部入帳後,Intents 進入
DepositAction::Notify分支,並以全部 98 筆項目呼叫惡意接收者的mt_on_transfer()一次。惡意接收者成功執行,並針對填充項目回傳 97 筆退款請求,每筆為1e36個原始單位;針對USDT項目,則回傳一筆金額為 0 的退款請求。 -
步驟 7(Tx 5):Intents 的
mt_resolve_deposit()接受了全部 97 筆退款請求,每筆為1e36個原始單位,因為惡意接收者在 Tx 4 中預先注入的內部填充代幣餘額足以支付這些退款。這些大額退款數值,加上重複出現的長代幣識別碼,使MtBurnEvent日誌膨脹至 16,495 位元組,超過 16,384 位元組的限制。事件發出失敗,導致這份收據中嘗試扣除的餘額遭到回滾,但先前的入金入帳仍然保留。
-
步驟 8(Tx 5):HOT Omni Balance 的
mt_resolve_transfer()收到來自 Intents 的mt_resolve_deposit()的失敗 promise 結果。因此,它依照原始轉移金額,將全部 98 筆項目退還給攻擊者,其中包括 10USDT,儘管惡意接收者要求對USDT退款的金額為零。攻擊者取回了資產,而惡意接收者保留了 Intents 中相應的內部入帳餘額。
攻擊者重複此流程,進一步膨脹內部餘額。Tx 6 使用了另一個惡意接收者,並觸發相同的日誌長度超限錯誤。
階段 3:在 BNB Chain 上出金(Tx 7–13)
- 步驟 9(Tx 7–13):攻擊者利用膨脹的內部餘額,透過 HOT Bridge 請求出金。在 BNB Chain 上,附錄 A 所列的 Tx 7–13 這七筆交易,將
USDT從 HOT Bridge 金庫轉移至攻擊者控制的 BNB 接收者。
前兩筆小額出金合計為 21 USDT。後續五筆合計為 3,865,000 USDT,因此七筆交易總計為 3,865,021 USDT。這些金額根據該代幣的轉移日誌及其 18 位小數精度計算。BNB Chain 上的時間戳記描述的是目的鏈上的轉移,應與 NEAR 上的入金或出金請求時間戳記區分。
修復與資金追回
團隊表示已於 10 月 2 日部署修復措施 [1]。修正後的退款計算將每筆退款的上限設為當前轉移的入金金額,同時保留請求金額及可用內部餘額所施加的限制 [15]:
let refund_amount = requested_refund.min(*deposited).min(balance_left);
這可防止先前入金累積的大額餘額,被用來支應後續較小額入金的超額退款。
團隊隨後於 10 月 7 日移除入金通知 [1],封堵惡意接收者提供退款請求的途徑。PR #374 記錄了這項移除作業 [16]。事後檢討報告還提到一項額外防護措施:監控機制現在會比對使用者內部餘額總額與合約實際持有的代幣數量,並在兩者不一致時自動暫停合約 [1]。
關於資金追回,專案於 10 月 2 日宣布所有資金均已歸還 [17]。其後發布的事後檢討報告確認,所有受影響使用者的損失均已獲得補償 [1]。
NEAR 智能合約的安全考量
這起事件提供了一個切入點,可用來檢視 NEAR 非同步收據之間的狀態一致性。本節以這項分析及我們的 NEAR 審計經驗為基礎,涵蓋三個面向:非同步執行、透過存取金鑰進行帳戶授權,以及儲存成本。後兩個面向將討論延伸至應用程式如何委派權限及為持久化狀態提供資金。重點在於這些 NEAR 機制所形成的風險,以及開發與審計期間需要進行的具體檢查;一般安全實務則在有助於解釋或因應這些風險時納入討論。

非同步執行
1. 跨收據的狀態管理
在 NEAR 上,跨合約呼叫及其回呼會在不同的收據中執行,後續執行失敗不會自動撤銷先前已提交的狀態。合約也能在呼叫尚未完成時處理其他請求,因此狀態更新的時機與隔離方式,對於維持內部餘額與實際資產一致至關重要。以下三種常見情境說明了這些風險:
-
延後扣除餘額: 如果直到回呼時才扣除或保留可支用餘額,同一筆資金可能在轉移完成結算前再次被使用。
-
過早將入金記入餘額: 在外部處理完成前,便將資金記入可支用餘額,會產生兩項風險:
- 結算前支用: 使用者可能在外部呼叫仍待完成、結算尚未確定時,支用已記入餘額的資金。
- 回呼失敗後仍保留入帳餘額: 如果退款回呼失敗,上游代幣合約可能退還資產,而先前已提交的內部入帳餘額仍然保留。NEAR Intents 事件展現了這項風險。
-
共用狀態遭覆寫: 如果待處理請求共用儲存使用者或金額的變數,後續請求可能覆寫較早請求的回呼所需資訊。如此一來,退款可能被歸屬於錯誤的使用者或金額。
建議。 由於 NEAR 上的跨合約流程在不同收據之間並非原子性,開發與稽核時都需要考慮餘額更新的時機、待處理請求的隔離,以及呼叫和回呼失敗後的復原。發起出金前先扣除或預留資金;只有在轉帳失敗時,才恢復一次餘額。對於入金,應防止使用者在結算完成前動用資金,並確保資產退款後不會留下可動用的內部額度,包括結算回呼本身失敗的情況。為每筆待處理請求分別記錄使用者、金額和結算狀態。針對呼叫成功與失敗、回呼失敗、交錯執行的請求,以及重複嘗試結算的情況,驗證上述行為。
2. 跨合約呼叫中的回呼
NEAR 合約使用 Promise 排程跨合約呼叫及回呼,以處理呼叫結果。回呼的存取控制與失敗處理,決定後續記帳或結算能否如預期執行。由此產生兩項風險:
-
未受限制的回呼存取: 回呼必須作為可呼叫的合約方法對外提供,但若未限制存取,外部呼叫者也能呼叫該方法。攻擊者可能以偽造的參數呼叫未受保護的回呼,導致記帳或結算邏輯在原本應先執行的操作未發生時就執行。
-
回呼失敗: NEAR 合約使用
.then()附加回呼,以處理跨合約呼叫的結果並執行必要的完成或復原邏輯。如果回呼本身失敗,其自身的狀態變更會回復,但先前已成功的收據仍會保持提交狀態,導致結算狀態不一致。
建議。 使用 #[private] 將回呼的存取權限限制為合約本身 [18]。為回呼分配足夠的 gas,並限制其可能執行的工作量及產生的日誌量。明確處理失敗的 Promise 結果與格式錯誤的回傳資料。由於失敗的回呼無法提交自身的復原變更,應在較早的收據中記錄復原所需的待結算狀態。驗證回呼失敗後不會留下缺乏資產支持、卻可動用的額度,且復原程序不會將同一操作結算兩次。
帳戶授權
NEAR 透過兩種類型的存取金鑰提供細緻的帳戶授權 [19]:Function-Call 金鑰和 Full Access 金鑰。
如果使用者以 Function-Call 金鑰授權網站,該網站便可對獲准的接收方呼叫獲准的方法,而無須每次操作都重新取得錢包簽署。執行環境會強制執行此權限範圍,並拒絕使用此類金鑰發起、且附帶非零存入金額的呼叫 [20]。
在此權限範圍內,帳戶身分無法區分操作是使用委派金鑰簽署,還是由使用者逐筆核准。如果敏感方法只依賴該身分,而授權又涵蓋這些方法,惡意網站就可能發起轉帳、出金或權限變更。
建議。 審查可透過受限金鑰呼叫的敏感方法,以及每項操作所需的授權。要求透過 #[payable] 和 assert_one_yocto() 附加恰好 1 yoctoNEAR,可排除受限金鑰直接發起交易的路徑。仍須保留應用程式自身的身分與權限檢查:存入金額的要求並不能證明操作由真人發起,因為軟體可以持有 Full Access 金鑰,其他合約也可以附加 NEAR。
儲存成本
NEAR 要求合約為其儲存的資料預留 NEAR,因此狀態增長會減少可供其他操作使用的資金 [21]。風險取決於由誰支付狀態增長的成本:
-
由協議負擔的儲存成本: 如果使用者無須付費即可建立記錄,且狀態增長沒有上限,重複進行低成本呼叫就可能增加合約的儲存資金承諾,並耗盡其可用資金。
-
由使用者負擔的儲存成本: 向使用者收費時,既要確保費用完全涵蓋成本,也要準確衡量用量:
- 繞過收費: 替代的進入點可能在未收取一般註冊或寫入路徑所要求費用的情況下建立記錄。
- 用量歸屬錯誤:
env::storage_usage()衡量的是整個合約的儲存用量。在外部呼叫前儲存基準值,再於後續收據中進行比較,可能將無關的寫入或刪除納入計算,導致收費高於或低於該使用者自身造成的儲存變化。
建議。 應一併考慮儲存成本的資金來源、寫入路徑的收費涵蓋情況,以及用量歸屬。對新增儲存空間收費,或明確限制協議補貼及容量。檢查每條寫入路徑是否能繞過收費。可行時,應在同一收據內衡量操作造成的儲存變化;若記帳橫跨多個收據,應先排除無關變化,再將用量歸屬於個別使用者。
結論
在 NEAR 上,即使後續回呼失敗,已成功的收據仍可能留下持續有效的狀態。不同於 Ethereum 上的同步呼叫鏈,跨收據流程沒有共用的回復邊界。因此,應用程式必須考量每種可能的失敗發生後,仍會留下哪些狀態與資產。
在 NEAR Intents 事件中,代幣退款已完成,但對應的內部額度在記帳調整失敗後仍然存在。退款驗證不足,使退款數額大到足以觸發該失敗。此案例顯示,即使在代幣層返還資產,應用程式仍可能留下缺乏資產支持、卻可動用的餘額。
對於類似的非同步流程,開發與稽核應追蹤每種可能的失敗後哪些狀態變更仍然有效、待結算餘額能否動用,以及如何在不重複給予額度或退款的情況下復原未完成的結算。檢查每筆收據時,都必須一併檢視其所依賴的先前狀態,以及它所排程的後續操作。
除結算外,存取金鑰權限和儲存成本的資金來源也值得明確審查:委派呼叫必須維持在預期的權限範圍內,而由使用者驅動的狀態增長必須有明確的付費方或上限。
參考資料
[1] NEAR Intents 事後檢討報告,2026年10月16日
[3] NEAR 文件:跨合約呼叫
[5] ERC-20:代幣標準
[6] ERC-1155:多代幣標準
[7] NEP-141:同質化代幣標準
[8] NEP-245:多代幣標準
[11] HOT Bridge 架構與 HOT Omni Balance
[12] NEP-245 入金流程,重現版本 35044fd
[13] 入金解析器,重現版本 35044fd
[15] 目前 Intents 原始碼中的退款界限,存取日期:2026年10月26日
[16] PR #374:移除入金通知
[17] NEAR Intents 復原聲明,2026年10月2日
[18] NEAR 文件:私有回呼
[19] NEAR 文件:存取金鑰
[20] NEAR RuntimeSpec:函式呼叫存取金鑰驗證
[21] NEAR 文件:儲存成本攻擊
附錄
A. 交易時間軸 {#appendix-verified-transaction-timeline}
本附錄保留原始調查使用的交易編號,列出四筆準備階段交易、已辨識出的第一筆與最後一筆餘額放大交易,以及七筆 BNB Chain 出金交易。這並非專案方所報告全部 23 筆失敗入金交易的完整清單。所有時間均為 UTC;階段依操作分類,時間上可能重疊。
| 交易 | 階段 | 鏈 | 時間 (UTC) | 操作 | 交易 |
|---|---|---|---|---|---|
| 1 | 準備 | NEAR | 2026-09-29 12:30:44 | 取得 10 USDT 的表示形式 |
9SiSBvDe... |
| 2 | 準備 | NEAR | 2026-09-29 16:09:34 | 取得填充用代幣 | FmwaoRND... |
| 3 | 準備 | NEAR | 2026-09-29 16:11:48 | 部署並初始化惡意接收方 | GgbwMV8N... |
| 4 | 準備 | NEAR | 2026-09-29 16:12:40 | 預先為惡意接收方的內部填充用代幣餘額提供資金 | 4wf2FWcE... |
| 5 | 餘額放大 | NEAR | 2026-09-29 16:14:19 | 已辨識出的第一筆餘額放大交易 | 3k91uDpU... |
| 6 | 餘額放大 | NEAR | 2026-10-01 05:47:27 | 已辨識出的最後一筆餘額放大交易 | GAQKwHdT... |
| 7 | 跨鏈出金 | BNB Chain | 2026-09-30 18:57:07 | 將 10 USDT 從 HOT Bridge 金庫轉至 BNB 接收方 |
0x4f426e23... |
| 8 | 跨鏈出金 | BNB Chain | 2026-09-30 20:05:24 | 將 11 USDT 從 HOT Bridge 金庫轉至 BNB 接收方 |
0xc002bd17... |
| 9 | 跨鏈出金 | BNB Chain | 2026-09-30 23:54:30 | 將 800,000 USDT 從 HOT Bridge 金庫轉至 BNB 接收方 |
0x9fe58e03... |
| 10 | 跨鏈出金 | BNB Chain | 2026-10-01 00:24:02 | 將 1,200,000 USDT 從 HOT Bridge 金庫轉至 BNB 接收方 |
0x0381265d... |
| 11 | 跨鏈出金 | BNB Chain | 2026-10-01 00:50:42 | 將 1,500,000 USDT 從 HOT Bridge 金庫轉至 BNB 接收方 |
0x69d1c68c... |
| 12 | 跨鏈出金 | BNB Chain | 2026-10-01 01:46:20 | 將 330,000 USDT 從 HOT Bridge 金庫轉至 BNB 接收方 |
0x9c10b967... |
| 13 | 跨鏈出金 | BNB Chain | 2026-10-01 06:08:26 | 將 35,000 USDT 從 HOT Bridge 金庫轉至 BNB 接收方 |
0x16ddfa69... |
B. 帳戶與代幣識別碼 {#appendix-accounts-and-token-identifiers}
原始調查將以下兩個跨鏈地址都歸屬於攻擊者。鏈上紀錄則分別證實了它們作為 NEAR 發送方及 BNB Chain 出金接收方的角色。此處列出的惡意接收方是 Tx 5 中使用的帳戶;後續用於擴大攻擊效果的交易使用了其他惡意接收方帳戶。
| 下文使用的名稱 | 角色 | 鏈 | 帳戶/識別碼 |
|---|---|---|---|
| 攻擊者 | 由攻擊者控制的交易發送方 | NEAR | 20e6bfe4685d99004fc2095d3a0fc6158cd810ce8f801196141e183ed6e19d65 |
| 惡意接收方 | 通知回呼合約/內部餘額持有者 | NEAR | dd1fe58ec316ada5b673b88c14fe2fa2b7ede82080440901dfbd64b994241757 |
| 填充代幣 | 攻擊者提供、用於填充批次的代幣 | NEAR | 4444119_ |
USDT 的映射資產 |
BNB Chain 資產在 NEAR 上的映射 | NEAR | 56_2CMMyVTGZkeyNZTSvS5sarzfir6g |
USDT |
底層代幣 | BNB Chain | 0x55d398326f99059ff775485246999027b3197955 |
| Intents | 內部結算合約 | NEAR | intents.near |
| HOT Omni Balance | NEP-245 代幣帳本 | NEAR | v2_1.omni.hot.tg |
| BNB 接收方 | 由攻擊者控制的出金接收方 | BNB Chain | 0x09Fd1f5d9F185067A92493E43AA259ea4AB3ad37 |
| HOT Bridge 金庫 | 跨鏈資產金庫 | BNB Chain | 0x233c5370CCfb3cD7409d9A3fb98ab94dE94Cb4Cd |
C. 填充代幣的建立與跨鏈轉移 {#appendix-filler-token-origin}
填充代幣最初是在 Osmosis TokenFactory 上建立的自訂資產。其建立、鑄造及後續轉移將它與攻擊準備工作聯繫起來。下列時間均為 2026年9月29日 的 UTC 時間;NEAR 上的領取對應附錄 A 中的 Tx 2。
| 時間(UTC) | 鏈 | 操作 | 交易 |
|---|---|---|---|
| 14:00:29 | Osmosis | 建立代幣幣種 | C489A91E... |
| 14:01:03 | Osmosis | 鑄造 97e36 + 97 個原始單位 |
5FD2CF0E... |
| 14:02:00 | Osmosis | 透過 IBC 將鑄造的數量轉移至 Kava | 8EFD2659... |
| 14:02:32 | Kava | 透過 IBC 將相同數量轉移至 Gonka | D26EABBE... |
| 14:16:07 | Gonka | 將資產存入 HOT Bridge | 41982DF3... |
| 16:09:34 | NEAR | 在 HOT Omni Balance 中領取其映射資產(Tx 2) | FmwaoRND... |
同一個 Osmosis 帳戶建立、鑄造並發送了該代幣。兩筆 IBC 轉移都帶有備註 hot intents ctf filler。鑄造數量為 97e36 + 97 個原始單位,與兩筆轉移、Gonka 橋接存入及 NEAR 上的領取數量一致。Osmosis 轉移的接收方是 Kava 轉移的發送方,而後者的接收方則是 Gonka 橋接存入的發送方。綜合這些紀錄可見,該代幣是作為攻擊準備工作的一部分而建立的。
Gonka 幣種追蹤紀錄記載了 IBC 路徑 transfer/channel-5/transfer/channel-1 及原始 Osmosis 資產識別碼:
| 資產層級 | 識別碼 |
|---|---|
| 原始 Osmosis 幣種 | factory/osmo1dnjr753vam6 |
| Gonka IBC 幣種 | ibc/C679139C206D0E7379C1 |
對 NEAR Tx 2 中的 contract_id 進行 Base58 解碼,會得到上方的 Gonka IBC 幣種。Gonka 橋接存入與 NEAR 上的領取使用相同的 nonce 1790691367000000007133;來源存入的接收方雜湊值也與攻擊者 NEAR 帳戶 ID 的 SHA-256 雜湊值相符。這些欄位將來源存入與 NEAR 上的入帳聯繫起來。「填充代幣」一詞描述的是該資產在擴大退款事件方面的作用。
D. Tx 5 的收據詳情 {#appendix-tx5-receipts}
下列五筆核心操作收據對應步驟 5–8。步驟 5 同時包含最初的 HOT Omni Balance 轉移及 Intents 存入收據。
| 對應步驟 | 收據 | 執行方 | 方法 | 結果 |
|---|---|---|---|---|
| 5 | 8fWiEwQUbVATPC3J |
HOT Omni Balancev2_1.omni.hot.tg |
mt_batch_transfer_call() |
成功;轉移了整批資產,並排程執行 Intents 的 mt_on_transfer() |
| 5 | DSfNwH18mEASbDg2 |
Intentsintents.near |
mt_on_transfer() |
本地執行成功;傳回一個 promise |
| 6 | 7wwKtfGzK1YSGqT2 |
惡意接收方dd1fe58ec316ada5 |
mt_on_transfer() |
成功;傳回退款陣列 |
| 7 | 4CPmVneKa1UWEuQa |
Intentsintents.near |
mt_resolve_deposit() |
失敗:日誌長度超出限制 |
| 8 | 7y7VKm4tM3rEspHG |
HOT Omni Balancev2_1.omni.hot.tg |
mt_resolve_transfer() |
成功;退還了已轉移的資產 |



