返回部落格

損失約 387萬 USD:Autheo Network、UNCX 遭駭|BlockSec 週報

Code Auditing
2026年10月22日
閱讀約 10 分鐘
核心要點
  • 本報告涵蓋 3 起重大安全事件,估計總損失約為 387萬 USD。這些事件涉及私鑰失陷、代幣歸屬計帳錯誤,以及錢包種子生成方式薄弱。

  • UNCX Network 的 Smart Token Vesting V2 事件影響了 Ethereum、BNB Chain、Base 和 Robinhood Chain 上的 10 種資產。有缺陷的份額總額計算將以不同代幣與份額比率建立的歸屬批次混合計算,使攻擊者得以提取約 80.7萬 USD 的已變現或經轉送價值。

  • 資產池的計帳方式必須維持每個批次的代幣數量、份額計算基準與歸屬進度之間的關係。以單一比率合併計算,可能讓其中一個部位超額提取共用餘額,減少可用於履行其他部位權益的資產。

過去一週(2026年10月12日–2026年10月18日)發生以下 3 起值得關注的安全事件,估計損失總額約為 387萬 USD。

日期 事件 類型 估計損失
2026年10月12日 Autheo Network 私鑰洩露 約 176萬 USD
2026年10月14日 UNCX Network 記帳錯誤 約 80.7萬 USD
2026年10月18日 Qubic Wallet 弱種子生成 約 130萬 USD

損失數字是根據已實現價值估算。

  • UNCX Network:本文詳細分析這起事件,因為其有缺陷的份額總量計算,提供了本週最清楚的合約記帳教訓。

免費安全掃描

使用我們自有的自動化分析引擎,快速進行安全檢查。

免費掃描

本週焦點:UNCX Network

2026年10月14日,攻擊者利用了 UNCX Network 在 Ethereum、BNB Chain、Base 和 Robinhood Chain 上的 Smart Token Vesting V2 合約漏洞。這起事件涉及 11 筆已確認的資產抽取交易中的 10 種資產,已實現或經轉移的價值約為 80.7609萬 USD [1]。根本原因是有缺陷的份額總量計算,將以不同代幣與份額比率建立的歸屬批次混合計算。這使倉位層級的紀錄與全域份額供給量出現落差,讓攻擊者控制的倉位得以提取超過其投入量的代幣。

背景

UNCX Network 是一家多鏈 DeFi 基礎設施供應商,其 Smart Token Vesting V2 產品可讓專案依照按時間設定的歸屬時程鎖定 ERC-20 代幣。每個時程均以一個歸屬 ID 表示,並記錄代幣、建立者、受益人、總量、已釋放量,以及一個或多個解鎖批次。允許追加投入的軟性鎖定倉位可在建立後接受額外批次,而其建立者可以取消尚未歸屬的部分。

同一代幣的倉位共用 VestingManager 中的一筆餘額,協議以份額決定每個倉位擁有該餘額的多少。因此,其記帳方式包含兩個相互關聯的層面:

Global pool, per token
  create / topUp: receive tokens and mint shares
  release: convert releasable shares into tokens
  _totalTokenShares[token]: active shares across all positions

Position record, per vesting ID
  _depositedShares[id]: share basis assigned to the position
  totalAmount: token amount represented by its tranches
  released: shares already paid to the beneficiary

執行釋放時,管理合約首先計算時程中已有多少比例完成歸屬。它使用 _depositedShares[vestingId],將 totalAmount 的該比例換算為已歸屬份額,減去 released,並將結果稱為 releasableShares。在下方公式中,tokenBalance 是管理合約目前持有的該時程代幣的 ERC-20 餘額,由該代幣的所有倉位共用;_totalTokenShares[token] 則是對應的全域有效份額供給量。代幣支付量取決於兩者的比率:

amount = releasableShares * tokenBalance / _totalTokenShares[token]

透過歸屬函式存入代幣,會同時增加代幣餘額與份額供給量。直接向管理合約轉入 ERC-20 代幣只會改變代幣餘額,因此會改變每個份額所代表的代幣數量。這種份額模型只有在每項生命週期操作都能使倉位紀錄與全域供給量保持一致時,才能支援共用資金池的倉位。

漏洞分析

受影響的 Ethereum VestingManager 位於 0xA98F...99F5,其中有缺陷的份額總量計算可透過 release()、topUpVesting() 和 cancel() 的組合加以利用。其他三條網路上也有同樣受影響的部署。

為了讓狀態變化更容易比較,下文以 D、R 和 V 作為簡寫。這些符號並未出現在合約程式碼中;下表將各符號對應至相關的合約變數或運算式。對應的值分為兩種數量類型:

符號 合約變數/運算式 數量類型 意義
D _depositedShares[vestingId] 份額數量 分配給該倉位所有已記錄存入款項的累計份額基數
R schedule.released 份額數量 已支付給受益人的累計份額
- schedule.totalAmount 代幣數量 該倉位目前各批次記錄的代幣總量
- vestedAmount 代幣數量 截至目前,totalAmount 中依這些批次規則已歸屬的部分
V vestedShare 份額數量 將單一混合後的已歸屬代幣比例套用至 D 所計算出的累計已歸屬份額

在 release() 中,合約計算 releasableShares,將 schedule.released 增加同等數量,並從 _totalTokenShares[schedule.token] 扣除同等數量。它不會減少 _depositedShares[vestingId]。因此,釋放之後,該倉位對全域供給量的有效份額貢獻只剩 D - R,但其儲存的基數仍為 D。

function release(uint256 vestingId) external nonReentrant {
    ...
    uint256 releasableShares = _getReleasableShares(vestingId);
    uint256 balance = IERC20(schedule.token).balanceOf(address(this));
    uint256 amount =
        (releasableShares * balance) / _totalTokenShares[schedule.token];

    schedule.released += releasableShares;
    _totalTokenShares[schedule.token] -= releasableShares;
    IERC20(schedule.token).safeTransfer(msg.sender, amount);
}

cancel() 將單一混合後的歸屬比例套用至倉位的彙總份額基數。它先透過 getVestedAmount(vestingId) 計算 vestedAmount,接著以 V = (vestedAmount * D) / totalAmount 將以代幣計量的已歸屬比例換算為份額。最後,該函式將 D - V 視為該倉位可移除的未歸屬份額。V 是累計值,而非先前支付後剩餘的已歸屬份額。

function cancel(uint256 vestingId) external nonReentrant {
    ...
    uint256 vestedAmount = getVestedAmount(vestingId);
    uint256 remainingAmount = schedule.totalAmount - vestedAmount;

    uint256 vestedShare =
        vestedAmount * _depositedShares[vestingId] / schedule.totalAmount;
    uint256 sharesToRemove =
        _depositedShares[vestingId] - vestedShare;
    _totalTokenShares[schedule.token] -= sharesToRemove;

    _depositedShares[vestingId] = vestedShare;
    schedule.totalAmount = vestedAmount;
    schedule.cancelled = true;

    IERC20(schedule.token).safeTransfer(schedule.creator, remainingAmount);
}

缺陷就在於混合計算本身。每個批次都有各自的代幣數量、歸屬進度,以及依該批次加入時資金池比率鑄造的份額數量。因此,應分別計算各批次的已歸屬份額,再加總。相反地,由於合約只儲存一個 D 和一個 totalAmount,它先彙總代幣數量與份額基數,再將單一歸屬比例套用至合併後的倉位。只有各批次的每代幣份額比率相同,或歸屬進度相同時,這兩種算法才會得到相同結果。直接轉入代幣會在追加投入前改變資金池比率,因此新批次每個代幣取得的份額遠少於原批次。將單一混合後的歸屬比例套用至兩個批次,便可能產生不再代表其合計已歸屬份額的 V。

由於 R 已從該倉位的累計已歸屬份額中支付,一致的時程必須滿足 R <= V。違反這項不等式,正是混合計算出錯的直接徵兆。程式碼沒有為倉位維護獨立的有效份額餘額,而是直接從全域 _totalTokenShares 扣除 D - V。假設其他倉位貢獻了 1000 個份額,而這個倉位的 D = 100、R = 80。取消前,全域供給量包含 1,000 + (D - R) = 1,020 個份額。如果混合計算得出 V = 60,cancel() 便會扣除 D - V = 40,使全域份額只剩 980 個,比其他倉位貢獻的 1000 個份額少 20 個。如果全域供給量只包含此倉位的 20 個有效份額,扣除 40 個份額會發生下溢並回滾;這筆超額扣除之所以能成功,只因共用資金池包含其他倉位貢獻的份額。隨後,函式儲存 _depositedShares[vestingId] = 60,而 schedule.released 仍為 80,使倉位紀錄處於 D < R 這種不可能成立的狀態。

程式碼既未強制滿足 R <= V,也未將 sharesToRemove 限制在該倉位的有效份額以內。因此,取消操作可能扣除已不屬於全域供給量的歷史份額。同時,它直接以代幣單位轉出 totalAmount - vestedAmount,沒有透過資金池的份額比率換算退款。取消操作本身不會造成超額支付;它只是使全域份額供給量低於各倉位所記錄的有效份額總和,為後續超額贖回創造條件。

攻擊分析

以下分析採用一筆具代表性的 Ethereum 交易:0x352065...c23823。攻擊合約在該筆交易中,對五種代幣執行相同的核心步驟,並針對每種代幣使用閃電貸流動性。

  • 步驟 1:攻擊者建立了一個立即歸屬的小型倉位 #5058,以及兩個規模大得多、立即歸屬且允許追加投入的軟性鎖定倉位 #5059 和 #5060。小型倉位會保留至最後提取,而大型倉位則提供破壞全域記帳所需的歷史份額紀錄。

  • 步驟 2:攻擊者釋放兩個大型倉位。在初始接近 1:1 的資金池比率下,每次釋放返還的數量約等於各自的淨存入量。相應份額已從 _totalTokenShares 移除,但原始數值仍保留在倉位 #5059 和 #5060 的 _depositedShares 紀錄中,且僅在各時程獨立的 released 欄位中記為已釋放。

  • 步驟 3:攻擊者直接向 VestingManager 轉入代幣。這恢復了代幣餘額,卻沒有恢復已釋放的份額,因此每個剩餘份額所代表的代幣數量大幅上升。

  • 步驟 4:攻擊者對已釋放的大型倉位追加投入。由於追加投入是按新提高的每份額代幣比率計價,大量存入的代幣只鑄造出少量新份額。此時,這些倉位結合了龐大但已過時的歷史基數,與少量的有效份額貢獻。

  • 步驟 5:攻擊者取消了兩個追加投入後的倉位。每次取消都將單一混合後的歸屬比例套用至彙總的存入份額歷史紀錄。重新計算的 vestedShare 低於已釋放的份額,因此 sharesToRemove 超過該倉位的有效份額貢獻。儘管每個倉位在追加投入時只增加了少量有效份額,全域供給量仍因每個倉位而減少約 5.0e25 個虛增份額。

  • 步驟 6:由於分母被嚴重低估,攻擊者釋放了先前保留的小型倉位。在所舉的代幣範例中,淨存入約 5.73e22 個原始單位,卻提取了約 1.07e26 個原始單位,約為存入量的 1,873 倍。攻擊者利用失真的比率,重複建立及釋放倉位,並償還閃電貸流動性。

官方事件報告指出,11 筆已確認的資產抽取交易均呈現相同模式。部分變體在單一原子交易中完成,其他變體則在關聯交易中執行最後的釋放。UNCX 在排除攻擊者本金、暫時性的閃電貸交易量及已返還資產後,根據已實現或經轉移的所得,計算出約 80.7609萬 USD 的數字 [1]。

開始使用 Phalcon Explorer

深入瞭解交易,做出明智決策

立即免費試用

結論

根本原因是有缺陷的份額總量記帳方式。協議合併了以不同代幣與份額比率建立的批次,再將單一歸屬比例套用至其彙總份額基數。這導致累計已歸屬份額計算錯誤,讓倉位得以移除超過其剩餘貢獻的份額,並使倉位層級的紀錄與全域份額供給量出現落差。攻擊者利用被低估的全域供給量,從共用餘額中提取了原本仍需用來滿足其他歸屬倉位的代幣。

若記帳模型允許在份額比率變動後繼續存入代幣,就應分別保存各批次的代幣數量、份額基數及歸屬進度,而非以單一比率將其混合計算。此外,也應強制確保累計支付量絕不超過累計已歸屬份額,且倉位無法移除超過其有效貢獻的份額。

參考資料

[1] UNCX Network Smart Token Vesting V2 事件報告

Web3 最佳安全審計機構

上線前驗證設計、程式碼及業務邏輯

訂閱最新動態
超越安全儲存:第 1 部分——設計安全的付款與簽署流程
Security Insights

超越安全儲存:第 1 部分——設計安全的付款與簽署流程

攻擊者未竊取私鑰,未經授權的操作如何取得有效簽章?《Beyond Secure Storage》第 1 部分以 Bitget、Bybit 和 Binance 等事件為例,檢視付款請求、交易建構、簽署、執行與結算各環節的授權失效問題。文章據此歸納防止未經授權操作及限制損失的設計原則,並說明如何透過審查、稽核、滲透測試與演練驗證這些防護措施。

NEAR Intents 遭攻擊:退款漏洞與安全教訓
Security Insights

NEAR Intents 遭攻擊:退款漏洞與安全教訓

NEAR Intents 遭攻擊事件中,攻擊者利用金額過大的退款事件,在存入的資產退還後仍保留內部餘額。本文分析重建了收據處理流程及 BNB Chain 上總額達 3,865,021 USDT 的七筆出金,區分這些資金流出與專案方報告的資金全數追回,並概述開發與稽核 NEAR 智能合約時的安全注意事項。

損失約 557萬 USD:X100 Freezer、NEM 遭攻擊 | BlockSec 週報
Security Insights

損失約 557萬 USD:X100 Freezer、NEM 遭攻擊 | BlockSec 週報

本週報涵蓋 2026年10月19日–2026年10月25日 期間發生在 Ethereum 和 BNB Chain 上的兩起安全事件。報告分析了以閃電貸提供資金、奪取 X100 Freezer 治理權的事件,以及影響 BNB Chain 上某個 NEM 代幣流動性池的稅費結算缺陷。報告範圍內的估計損失合計約 557萬 USD:具代表性的 X100 交易造成約 475萬 USD 的損失,NEM 流動性池事件造成約 82.0萬 USD 的損失。此合計金額不包含另行報導的後續 X100 資金提取。

Web3 最佳安全審計方

在上線之前驗證設計、程式碼與業務邏輯,對標業內最高安全標準。

BlockSec 審計
損失約 387萬 USD:Autheo Network、UNCX 遭駭|BlockSec 週報