在過去的一週(2026/03/09 - 2026/03/15)中,BlockSec 檢測並分析了八起攻擊事件,估計總損失約為 166 萬美元。下表總結了這些事件,後續章節提供了每個案例的詳細分析。
| 日期 | 事件 | 類型 | 預估損失 |
|---|---|---|---|
| 2026/03/09 | EtherFreakers 事件 | 業務邏輯缺陷 | ~2.5 萬美元 |
| 2026/03/10 | Alkemi 事件 | 業務邏輯缺陷 | ~8.9 萬美元 |
| 2026/03/10 | MT 事件 | 業務邏輯缺陷 | ~24.2 萬美元 |
| 2026/03/11 | AAVE 清算事件 | 設定錯誤 | ~101 萬美元 |
| 2026/03/11 | Planet Finance 事件 | 業務邏輯缺陷 | ~1 萬美元 |
| 2026/03/12 | AM 事件 | 業務邏輯缺陷 | ~13.1 萬美元 |
| 2026/03/12 | DBXen 事件 | 業務邏輯缺陷 | ~14.9 萬美元 |
| 2026/03/15 | Goose Finance 事件 | 業務邏輯缺陷 | ~8 千美元 |
EtherFreakers 事件
事件簡報
2026 年 3 月 9 日,以太坊上的 NFT 遊戲 EtherFreakers 由於錯誤的重複計數,導致約 2.5 萬美元的損失。遊戲中的每個 NFT 都持有一個可提現的 ETH 餘額(稱為「能量」)。作為一種遊戲機制,玩家可以使用 attack() 讓一個 NFT 捕獲另一個 NFT 並領取目標的能量。然而,合約在結算會計之前就支付了目標的餘額並轉移了 NFT。轉移鉤子 (transfer hook) 這時讀取了過時的預支付數據,並將部分數據回饋到全球分紅池,在沒有新的 ETH 注入的情況下膨脹了資金池。攻擊者通過循環此捕獲機制來抬高全球指數,然後從一批 NFT 中提取了膨脹的餘額。
背景
EtherFreakers 是一款鏈上 NFT 遊戲,每個 NFT(稱為「Freaker」)持有一個稱為 energy 的可提現 ETH 餘額。該系統運作方式類似於分紅池:當特定動作發生時,一部分 ETH 會按比例分配給所有 Freaker。每個 Freaker 可領取的 ETH 由全球累積器 freakerIndex 結合每個代幣的份額權重 fortune 來追蹤。
具體來說,會計公式為:energyOf = basic + (freakerIndex - index) * fortune。當 _dissipateEnergyIntoPool(amount) 運行時,freakerIndex 會增加,將 amount 的 80% 分配給所有 Freaker,20% 分配給創建者。通過 charge() 直接存款只會增加 basic,而不影響 freakerIndex。因此,freakerIndex 的增加必須始終有進入系統的真實 Ether 作為支撐。如果 freakerIndex 在沒有相應 ETH 流入的情況下增長,Freaker 贖回的 Ether 將超過合約實際持有的金額。
漏洞分析
根本原因是 EtherFreak 合約 (0x3A27...c0f33) 中的執行順序不正確。當捕獲成功時,attack() 函數按順序執行以下步驟:
- 第 237 行:將
targetCharge(目標 NFT 的全部能量)作為直接 ETH 轉帳支付給防禦者。能量現在已被消耗。 - 第 240 行:調用
_transfer(defender, capturer, targetId)來移動 NFT。在內部,_transfer()調用了 ERC-721 鉤子_beforeTokenTransfer(),該鉤子以energyOf(targetId)的 0.1% 調用了_dissipateEnergyIntoPool()。這是對_dissipateEnergyIntoPool()的第一次調用,由於第 5 步尚未發生,它讀取的是過時的值。 - 第 241 行:顯式調用
_dissipateEnergyIntoPool(sourceSpent)。這是第二次調用,屬於正常的遊戲邏輯。 - 第 244-251 行:更新
sourceId和targetId的energyBalances。
錯誤在於第 2 步:由於 energyBalances[targetId] 尚未更新,鉤子仍看到了預支付前的餘額,並將部分已消耗的能量注入分紅池。第 1 步的直接 ETH 支付和第 2 步的資金池輸入都從相同的能量中提取,導致 freakerIndex 在沒有新 ETH 的情況下膨脹。
(此處省略圖片資源鏈接)
freakerIndex 在每次調用 _dissipateEnergyIntoPool() 時均會增長:
(此處省略圖片資源鏈接)
攻擊分析
以下分析基於交易 0x89e24d...9abd2942。
-
第 1 步:借入
1,700個WETH。 -
第 2 步:在攻擊者控制的地址下鑄造兩個新的 Freaker,代幣
590和代幣591。 -
第 3 步:重複調用遊戲的
attack(590, 591)函數,並保持執行在成功的捕獲分支上。 -
第 4 步:每次成功後,將代幣
591轉回協助位址,以便重複使用同一對組合。 -
第 5 步:每次成功循環都使
freakerIndex超出了系統實際保留的 Ether。 -
第 6 步:一旦指數足夠高,就贖回先前控制的一批 Freaker。代幣 ID
496到520每個被贖回了0.278052246002402082Ether。 -
第 7 步:將提取的 Ether 包裝成
WETH,償還1,700個WETH的閃電貸,並保留約7.498個WETH作為利潤。
結論
根本原因是 attack() 的成功捕獲流程中:EtherFreakers 在目標代幣的能量狀態結算前就支付了 targetCharge。隨後 _transfer() 觸發了 _beforeTokenTransfer(),它讀取了過時的預支付 energyOf(targetId) 並將部分能量散發到池中。這在沒有新 Ether 支撐的情況下增加了 freakerIndex,因此相同的目標能量既被計為支出又被計為資金池輸入。這是一個業務邏輯膨脹漏洞,而非重入漏洞。
為降低未來此類風險,請採取以下措施:
-
避免在同一交易尚未結算時,從轉帳鉤子內的易變狀態重新計算經濟價值。
-
如果轉帳鉤子讀取狀態變量,請確保執行順序不會影響結果(例如,在鉤子運行前結算狀態,而不是之後)。
Alkemi 事件
事件簡報
2026 年 3 月 10 日,以太坊上的 Alkemi 協議遭到攻擊,導致約 8.9 萬美元的損失。根本原因是會計錯誤和嚴重的業務邏輯缺陷。有缺陷的清算邏輯允許任何人能夠在同一交易中清算自己的倉位並從中獲利。此外,一個會計錯誤導致清算過程中攻擊者自身作為抵押品的扣除操作被覆蓋,使得攻擊者無需承擔預期成本即可獲得清算獎勵。
背景
Alkemi 是一個借貸協議。當借款人的倉位資不抵債時,任何人都可以調用 liquidateBorrow() 來償還部分債務並以折扣價獲取抵押品。為了防止過度清算,協議將每筆交易的可償還金額限制為以下三個值的最小值:
- 借款人當前的借款餘額 (
currentBorrowBalance_TargetUnderwaterAsset)。 - 應用清算折扣後借款人抵押品可覆蓋的最大還款額 (
calculateDiscountedBorrowDenominatedCollateral())。 - 將帳戶恢復到清算邊界所需的還款額 (
calculateDiscountedRepayToEvenAmount()),僅在市場isSupported時檢查。
(此處省略圖片資源鏈接)
漏洞分析
根本原因在於 Alkemi 協議 (0x4822...a888) 中的業務邏輯缺陷和會計錯誤。由於只要借款人有未償還債務,currentBorrowBalance_TargetUnderwaterAsset 就必然大於 0,且只要借款人有抵押品,calculateDiscountedBorrowDenominatedCollateral() 的返回值也必然大於 0,AlkemiEarnPublic 協議實質上依賴 calculateDiscountedRepayToEvenAmount() 來判斷某筆貸款是否可以清算。在此函數中,需要清算的債務金額應基於名為 accountShortfall_TargetUser 的變量計算。
但在實際實現中,該函數反而是使用一個全局變量 closeFactorMantissa 來計算允許償還債務金額的上限,並返回該值。因此,攻擊者能夠在同一交易中借入並立即清算自己的倉位。
此外,在 liquidateBorrow() 函數中,當清算人和借款人是同一個地址時,變量 supplyBalance_TargetCollateralAsset 和 supplyBalance_LiquidatorCollateralAsset 指向同一存儲槽。函數分別計算「減少後的餘額」和「獎勵後的餘額」,隨後按順序寫回同一個存儲槽。由於減少後的餘額先寫入,獎勵後的餘額後寫入,導致減少的效果被覆蓋並丟失,只留下了獎勵的結果。這使得攻擊者能夠進一步放大獲利。
攻擊分析
以下分析基於交易 0xa170...6d9d。
-
第 1 步:攻擊者從 Balancer 閃電貸借入
51e18個WETH。 -
第 2 步:將
51e18個WETH解包為ETH並存入 Alkemi 協議。 -
第 3 步:從 Alkemi 借入
39.5e18個ETH。 -
第 4 步:使用
39.5395e18個ETH清算自己的倉位。 -
第 5 步:從 Alkemi 提取
93.5e18個ETH。 -
第 6 步:償還閃電貸,獲利
43.4e18個ETH。
(此處省略圖片資源鏈接)
結論
根本原因是錯誤的清算邏輯允許攻擊者在同一交易中先借貸再清算自己的位置以獲利,而錯誤的會計邏輯進一步放大了攻擊者的收益。
為降低未來此類風險,請採取以下措施:
- 對於借款人和清算人的餘額更新,協議應直接在存儲變量上進行操作,而不是將餘額複製到臨時內存變量中進行單獨計算和寫回。
MT 事件
事件簡報
2026 年 3 月 10 日,BNB Chain 上的通縮代幣 MT Token 遭到攻擊,損失約 24.2 萬美元。根本原因是存在缺陷的交易限制邏輯,以及對特殊轉帳條件的不一致處理。在通縮階段,合約在資金池儲備超過固定閾值時會限制買入操作。然而,合約將精確金額的轉帳(例如 2e17 MT)視為推薦人綁定操作,允許攻擊者繞過買入限制並獲取初始代幣。此外,限制邏輯依賴不完整的路徑檢測 (isBuy),未能覆蓋從 Pair 到 Router 的間接交換路徑,且白名單檢查進一步短路了關鍵驗證。攻擊者在未觸發限制或費用的情況下累積了 MT 代幣,通過受控流動性操作和交易操縱了 pendingBurnAmount,並迫使資金池進入價格被人工操縱的異常狀態。
背景
MT Token 是 BNB Chain 上具有內置交易限制的通縮代幣。在通縮階段,當池中的 MT 儲備超過 21,000e18 時,合約會封鎖買入操作。一旦儲備低於此閾值,通縮階段結束,重新啟用買入。MT Token 還包括一個推薦機制:精確轉帳 2e17 或 1e17 個 MT 被視為推薦人綁定操作,而非正常交易。
漏洞分析
根本原因在於 MT 合約 (0x037E...b449) 中存在缺陷的買入限制設計。在正常情況下,攻擊者在限制階段應無法獲得 MT 作為種子資金。然而,合約將精確轉帳 2e17 個 MT 視為綁定行為,這允許攻擊者繞過買入限制購入 MT。
(此處省略圖片資源鏈接)
此外,交易限制依賴於 isBuy 分支來阻止購買,但它未能覆蓋「Pair 到 Router」的路徑。由於 Router 和 Pair 均為白名單地址,此類轉帳在白名單檢查時直接短路,從未觸及買入限制邏輯,允許攻擊者通過將買入路由到 Router,然後通過移除流動性提取代幣來獲取 MT。
(此處省略圖片資源鏈接)
攻擊分析
以下分析基於交易 0xfb57...fca6。
-
第 1 步:攻擊者閃電貸借入
~358,681e18個WBNB。 -
第 2 步:攻擊者購買了
2e17個MT,從而繞過了買入限制。 -
第 3 步:攻擊者向 Pair 提供
4e12個WBNB和2e17個MT以添加流動性。此轉帳因與上述相同的原因繞過了收費邏輯。 -
第 4 步:攻擊者從 Pair 向 Router 買入
~10,000,000e18個MT代幣,從而繞過了買入限制和收費邏輯。 -
第 5 步:攻擊者移除了一半的流動性倉位,在此過程中提取了 Router 持有的所有
MT代幣,隨後賣出恢復的MT以獲取WBNB。在此步驟中,pendingBurnAmount被操縱至約9,000,000e18。 -
第 6 步:攻擊者再次買入
~10,000,000e18個MT代幣,將資金池的MT儲備降至~6,756,516e18,此數值低於pendingBurnAmount。 -
第 7 步:攻擊者移除了剩餘的一半流動性倉位,撤出了買入的
MT代幣,並調用distributeDailyRewards()從池中銷毀MT。結果,MT儲備降至21,000e18。 -
第 8 步:攻擊者將所有
MT換回~1,198e18個WBNB,償還閃電貸,獲利離場。
結論
此漏洞源於錯誤的交易限制,允許攻擊者通過購買精確數量的 BINDING_AMOUNT 個 MT 代幣來繞過買入禁止令。獲得 MT 後,攻擊者通過添加流動性、將 MT 買入 Router,最後移除流動性獲取代幣,進一步繞過了收費邏輯和買入限制。攻擊者隨後通過賣出操作累積 pendingBurnAmount 並執行銷毀,將池儲備推至異常狀態,實現了以高價售出 MT 並獲利。
為降低未來此類風險,請採取以下措施:
- 在轉帳語義和交易邏輯之間實施嚴格的隔離。
AAVE 清算事件
事件簡報
2026 年 3 月 11 日,AAVE 在以太坊上遭遇了價值 2,100 萬美元的錯誤清算,導致約 101 萬美元的損失。根本原因是 wstETH 的預言機價格不正確,導致原本健康的倉位變得資不抵債。結果,用戶倉位被清算,造成了財務損失。
背景
AAVE 使用預言機適配器來定價像 wstETH 這樣的包裹資產。上限價格預言機 (CAPO) 通過將基礎 ETH/USD 價格乘以轉換比率 (getRatio(),即 1 個 wstETH 值多少 ETH) 來計算 wstETH 價格。為了防止比率操縱,CAPO 應用了一個基於快照的增長上限:
maxRatio = snapshotRatio + maxGrowthPerSecond x (currentTime - snapshotTimestamp)
並在定價時壓縮 getRatio() 的輸出(如果 currentRatio > maxRatio,則使用 maxRatio)。此機制有效地限制了比率的最大向上漂移及產生的價格。
漏洞分析
根本原因是 CAPO 預言機錨點配置中的時間比率不匹配 (0xe1D9...61Ef):設定了快照時間戳和快照比率,但快照比率配置得低於真正的 wstETH/ETH 比率。因此,適配器計算出的 maxRatio 低於實際比率,導致壓縮後的 getRatio() 值偏低,系統性地低估了 wstETH/USD 的預言機價格。這種抵押品價值的下調降低了使用 wstETH 作為抵押品的倉位的健康係數,導致原本健康的帳戶被錯誤地分類為不健康並被清算。
攻擊分析
以下分析基於交易 0x9064...8a9c。
-
第 1 步:清算人閃電貸借入了
~6304e18個WETH並清算了借款人。 -
第 2 步:清算人償還了閃電貸,完成了清算。
結論
此次清算是由於錯誤的預言機價格配置,將本應保持健康的借款人錯誤地推入不健康狀態,從而觸發了其倉位的清算。
為降低未來此類風險,請採取以下措施:
-
確保關鍵參數在每次更新前經過正確性驗證。
-
在實現中增加驗證檢查,拒絕錯誤的參數,防止錯誤的配置被成功應用。
Planet Finance 事件
事件簡報
2026 年 3 月 11 日,Planet Finance 在 BNB Chain 上遭到攻擊,損失預計約 1 萬美元。根本原因是該協議錯誤地將借款人存儲的借款餘額增加視為利息應計,允許攻擊者反覆借款並觸發折扣結算,從而少報其記錄的債務。
背景
Planet Finance 是一個借貸協議,允許借款人以利息折扣償還債務。折扣是分級的,由用戶質押的 GAMMA 與其質押的其他資產價值之間的比例決定:該比例越高,還款折扣越大。折扣機制包含三級,從 0%(最低)到 50%(最高)。
漏洞分析
根本原因是協議 (0x4c9E...F467) 在 changeUserBorrowDiscount() 中結算借款人折扣時,錯誤地將借款人存儲的借款餘額增加視為新產生的利息。結果,僅旨在適用於應計利息的折扣被錯誤地適用於新借出的本金,而不當地減少了借款人的記錄債務。攻擊者可以反覆執行「借款」然後「調整折扣」的循環來積累過高的折扣,導致鏈上記錄的負債始終低於實際借款金額,並最終從差異中獲利。
攻擊分析
以下分析基於交易 0x5f45...5ec9。
-
第 1 步:攻擊者閃電貸借入了
200,000e18個USDT。 -
第 2 步:使用
5,000e18個USDT購買WBNB,然後利用獲得的WBNB購買了~8,726,524e18個GAMMA。 -
第 3 步:攻擊者將所有獲得的
GAMMA質押到 gGAMMA 市場,然後存入剩餘的USDT作為抵押品,這將他們的還款折扣提高到 5% 並啟用了後續借款。 -
第 4 步:攻擊者反覆調用
borrow然後updateUserDiscount來持續減少記錄債務。 -
第 5 步:攻擊者最終償還債務,贖回抵押品並實現獲利。
結論
此次事件由 Planet Finance 在 changeUserBorrowDiscount() 中有缺陷的折扣結算邏輯引起,該邏輯錯誤地將借款餘額的增加視為利息並應用了利息折扣。攻擊者可以重複調用 borrow 後接 updateUserDiscount 來少報債務,並最終通過償還少於真實負債的金額來提取利潤。
為降低未來此類風險,請採取以下措施:
- 在借貸協議中區分利息和新借貸。
AM 事件
事件簡報
2026 年 3 月 12 日,BNB Chain 上的通縮代幣 AM Token 遭攻擊,損失預計約 13.1 萬美元。AM Token 實現了一種通縮機制,每筆賣出都會從流動性池中觸發額外的銷毀,以減少總供應量。然而,銷毀並非立即執行——相反,全部賣出金額被記錄為 toBurnAmount,實際銷毀則推遲到下一次賣出。這種延遲創造了記錄和執行之間的時間窗口,攻擊者可以趁此機會買入 AM 將池中的 AM 儲備壓縮至 toBurnAmount 以下。當下一次賣出觸發延遲銷毀時,整個 AM 儲備耗盡,導致價格呈現極端波動,允許攻擊者賣出 AM 獲利。
背景
AM Token 是 BNB Chain 上的通縮代幣。每次賣出時,合約將交換中涉及的 AM 數量記錄為 toBurnAmount,並在下一次賣出時從池中銷毀該記錄金額。實際上,賣出會觸發延遲銷毀,從而縮減池中的 AM 儲備。此外,在執行銷毀前,協議還會將累積的 totalTokenFee 交換為 USDT 並根據其費用分配邏輯進行分配。
漏洞分析
根本原因是代幣 (0x27f9...213f) 的賣出邏輯將全部交換的 AM 金額累積為 toBurnAmount,僅在下一次賣出時通過從 AM/USDT 對中刪除代幣並調用 pair.sync() 來更新儲備來執行銷毀。這種設計允許攻擊者操縱池的 AM 儲備、扭曲鏈上價格並通過套利獲利。
攻擊分析
以下分析基於交易 0xd0d1...f859。
-
第 1 步:攻擊者閃電貸借入
~27,265,119e18個USDC和~361,710e18個WBNB,隨後將其換為~100,423,811e18個USDT。 -
第 2 步:攻擊者將
~5,062e18個AM代幣換為USDT,將合約記錄的toBurnAmount操縱為~4,303e18。 -
第 3 步:攻擊者用
USDT換入 AM Token,將池中的AM儲備推至~4,303e18。 -
第 4 步:攻擊者轉帳
6 weiAM到池中,觸發賣出途徑的銷毀邏輯。結果,合約銷毀了池中全部的AM餘額,將AM儲備降至 0。注意:協議在銷毀前先嘗試將累積費用交換為USDT。此費用轉換途徑也會觸發賣出分支的銷毀邏輯。銷毀執行後AM儲備達到 0,費用交換失敗。因為被包裹在 try/catch 中,錯誤不會導致交易回滾。執行繼續,費用累積器重置為 0。 -
第 5 步:攻擊者調用
pool.sync()並將剩餘的USDT和1 weiAM轉入池中。由於兩種代幣同時轉入,合約將其視為 addLiquidity,因此未累積toBurnAmount。AM儲備更新為 7。 -
第 6 步:攻擊者將剩餘
AM換回USDT。在此交換過程中,將AM轉入 Pair 觸發了賣出途徑的銷毀邏輯,使AM儲備降至 1。此外,由於totalFeeAmount在第 4 步已重置為 0,費用到USDT的轉換不再執行,允許攻擊者以人為操縱的高價賣出AM。 -
第 7 步:攻擊者償還閃電貸並收穫剩餘利潤。
結論
此次事件是由 AM Token 缺陷的銷毀機制引起的,該機制在下一次賣出時銷毀特定金額,並調用 pool.sync()。這允許攻擊者將 Pair 的 AM 儲備操縱至極低水平,並以虛高價格賣出 AM 以耗盡 USDT。
為降低未來此類風險,請採取以下措施:
- 限制每筆交易的最大銷毀金額,並限制銷毀觸發頻率,防止攻擊者在短時間內消耗池中大量代幣儲備。
DBXen 事件
事件簡報
2026 年 3 月 12 日,以太坊和 BNB Chain 上的「燃燒獲利」(burn-to-earn) 協議 DBXen 遭到攻擊,總損失約 14.9 萬美元。根本原因在於 _msgSender() 和 msg.sender 之間的不一致。當 burnBatch() 通過 forwarder 調用時,燒毀的 XEN 金額記錄在 _msgSender()(攻擊者控制)名下,但週期記錄卻在 msg.sender(即 forwarder)上更新。這種分離使攻擊者能夠領取基於過時週期紀錄的獎勵和費用,導致異常巨大的賠付。
背景
DBXen 是一個燒毀獲利協議:用戶燒毀 XEN 代幣以換取 DXN 獎勵和累積協議費用的份額。關鍵機制按週期運作。當用戶調用 burnBatch() 時發生兩件事:(1) 燒毀的 XEN 金額記錄在調用者地址下(由 _msgSender() 識別);(2) XEN 合約回調 DBXen 的 onTokenBurned(),將調用者的週期記錄(燒毀週期和 lastFeeUpdateCycle)更新為當前週期。
獎勵和費用通過 updateStats() 結算,獎勵與用戶在其燒毀週期內燒毀的 XEN 總量所佔份額成比例。費用基於用戶自上次記錄週期以來累積的協議費用。兩者計算都依賴用戶週期記錄的即時更新。
漏洞分析
根本原因是 DBXen 協議 (0xf5c8...2abd) 中的業務邏輯缺陷。_msgSender() 函數檢查 msg.sender 是否為 forwarder。如果是,它返回 calldata 的最後 20 個字節,而該值可以在 forwarder 上下文中隨意控制。然而,burnBatch() 直接燒毀了 msg.sender 持有的 XEN。結果,攻擊者可以通過 forwarder 調用 burnBatch(),導致協議燒毀 forwarder 持有的 XEN,並將 forwarder 的燒毀週期記錄和費用更新週期記錄更新為當前週期。與此同時,協議將燒毀的 XEN 金額記錄在對應 _msgSender() 的地址下。
此後,攻擊者調用 claimFees(),這會觸發 updateStats()。由於 _msgSender() 地址的週期記錄從未更新(燒毀週期和 lastFeeUpdateCycle 均為 0),updateStats() 計算了當前週期的獎勵,並計算了自週期 0 以來累積的費用——這跨越了協議的整個歷史費用。隨後攻擊者通過調用 claimFees() 和 claimRewards() 獲利。
攻擊分析
以下分析基於交易 0x914a5a...b808bc37。
-
第 1 步:攻擊者調用了
Forwarder合約的registerDomainSeparator()函數,啟用了後續對Forwarder.execute()的調用。 -
第 2 步:攻擊者在 Uniswap V2 池中用
0.14e18個ETH換取了13,900,000,000e18個XEN。 -
第 3 步:將
13,900,000,000e18個XEN轉帳給Forwarder合約。 -
第 4 步:使用
Forwarder.execute()授權 DBXen 支出Forwarder持有的13,900,000,000e18個XEN。 -
第 5 步:使用
Forwarder.execute()調用DBXen.burnBatch()並燒毀了13,900,000,000e18個XEN。燒毀金額記錄在0x425D3eC2DCeBE2c04bA1687504D43AFC6be7328d下,同時XEN通過onTokenBurned()回調 DBXen,更新了Forwarder上的週期記錄。 -
第 6 步:使用
Forwarder.execute()調用DBXen.claimFees()並獲得65.36e18個ETH。 -
第 7 步:使用
Forwarder.execute()調用DBXen.claimRewards()並鑄造了2,305.4e18個DXN。
結論
該事件的根本原因是 DBXen 協議對 _msgSender() 和 msg.sender 的不一致使用。由於這兩個值可能不同,協議內部會計變得不一致,從而允許攻擊者利用該差異獲利。
為降低未來此類風險,請採取以下措施:
- 在所有邏輯路徑中一致地使用
_msgSender(),或確保依賴msg.sender的操作和依賴_msgSender()的會計始終引用同一個地址。
Goose Finance 事件
事件簡報
2026 年 3 月 15 日,BNB Chain 上的收益耕作協議 Goose Finance 遭到攻擊,損失約 8 千美元。根本原因是 StrategyGooseEgg 中的份額定價順序缺陷:deposit() 在將已收穫獎勵結算進會計系統之前就鑄造了份額,導致定價使用的總資產分母排除了這些獎勵,數值低於真實價值。這意味著存幣者獲得了過多的份額。當調用 withdraw() 時,會觸發增加總資產的獎勵收割,使得每份份額價值更高。通過在單筆交易中循環執行存入和贖回,攻擊者多次鑄造溢價份額並以修正後(較高)的價值贖回,從中提取利潤。
背景
Goose Finance 是一個 BNB Chain 收益耕作協議,用戶資金從金庫流入策略,該策略將資產質押在 MasterChef 中以賺取 EGG 獎勵。
與此事件相關的組件包括:
-
VaultChef(0x3f64...):追蹤用戶倉位並轉發資本至StrategyGooseEgg。 -
StrategyGooseEgg(0x0980...):維護策略層級的會計記錄,包括sharesTotal和wantLockedTotal。 -
MasterChef(0xe70e...):接收質押資產並支付EGG獎勵。 -
WrappedEgg(0xb815...):將EGG1:1 包裹為WEGG以進行質押。
運作上,存款從 VaultChef 路由到 StrategyGooseEgg,然後質押到 MasterChef。贖回由 VaultChef 發起,並由策略執行。
關鍵的會計期望是份額定價應反映定價時的總資產(質押本金加上策略已持有的閒置獎勵)。然而在 StrategyGooseEgg 中,deposit() 在 _farm() 將閒置資產結算進 wantLockedTotal 之前鑄造份額,而 withdraw() 可以觸發來自 MasterChef 的獎勵收割。此順序是下述漏洞分析的基礎。
漏洞分析
根本原因是 StrategyGooseEgg (0x0980...b26b) 中獎勵收割與份額定價之間的會計同步異常。
在 StrategyGooseEgg 中,份額定價使用 wantLockedTotal 作為分母:shares = deposit * sharesTotal / wantLockedTotal。為保證公平,wantLockedTotal 必須反映策略實際持有的所有資產,包括閒置的 EGG 獎勵。然而,deposit() 在 _farm() 將閒置獎勵結算進 wantLockedTotal 之前就鑄造了份額。這意味著分母排除了尚未記錄的獎勵,低於真實總資產,導致存幣者獲得了比應得更多的份額。
此外,withdraw() 調用了 MasterChef.withdraw(),這將質押本金加上未決的 EGG 獎勵返回給策略。策略會計僅從 wantLockedTotal 中扣除要求的 _wantAmt,因此收割的獎勵保留在策略餘額中而未反映在 wantLockedTotal 中。這擴大了實際持有資產與記錄的 wantLockedTotal 之間的差距,使得隨後的任何 deposit() 份額定價更加不準確。
攻擊分析
以下分析基於交易 0x86efdf...ce316223。
-
第 1 步:攻擊者從兩個 Pancake 池閃電貸借入
EGG。 -
第 2 步:首次存入
VaultChef/StrategyGooseEgg(10,170,000e18EGG)。 -
第 3 步:第一次贖回(
12,593,884e18EGG)並收割獎勵;359,561e18EGG轉移至StrategyGooseEgg並作為閒置/未結算價值保留 (R > 0)。 -
第 4 步:第二次存入,重複使用贖回的資本(
12,593,884e18EGG)。份額在閒置價值結算前定價,因此這是溢價鑄造步驟。 -
第 5 步:第二次贖回(
12,826,027e18EGG)實現了溢價鑄造份額的利潤(即比第 4 步存款輸入多出232,143EGG)。 -
第 6 步:攻擊者償還閃電交換並保留淨利潤。
結論
此漏洞源於 StrategyGooseEgg 中的份額定價順序錯誤:deposit() 在 _farm() 更新 wantLockedTotal 前鑄造份額,而 withdraw() 收割的獎勵卻暫時閒置且未加入會計統計。這使得存款可以基於過時的分母進行鑄造,並在資產更新後贖回。
為降低未來此類風險,請採取以下措施:
-
在份額鑄造和燒毀計算之前,結算獎勵並更新會計。
-
在精確計算點,將份額對單一
totalAssets(staked + idle) 進行定價。 -
在閒置獎勵非零的情況下,為
shares_minted <= D * S / (A + R)增加不變性測試。
關於 BlockSec
BlockSec 是一家全棧區塊鏈安全和加密合規服務提供者。我們構建產品和服務,協助客戶在協議和平台的整個生命週期中進行程式碼稽核(包含智慧合約、區塊鏈和錢包)、即時攔截攻擊、分析事件、追蹤非法資金並滿足 AML/CFT 合規要求。
BlockSec 已在知名會議上發表多篇區塊鏈安全論文,通報了多個 DeFi 應用的零日漏洞,成功攔截了多次駭客攻擊並挽回了超過 2,000 萬美元的資金,並保護了數十億美元的加密貨幣資產。
-
官方 Twitter 帳號:https://twitter.com/BlockSecTeam
-
🔗 BlockSec 稽核服務 : 提交請求



