Yearn 被盜 $9M 美金攻擊分析
前言
2025 年 12月1日,Yearn 協議遭遇了一起精心設計的多階段複雜黑客攻擊,最終導致約900萬美元資產損失。攻擊並非單一漏洞利用,而是攻擊者透過閃電貸撬動資金、利用協議多重邏輯缺陷逐步操控資金池狀態,最終實現近乎無限鑄造yETH相關LP代幣並耗盡資金池的惡性事件。
本次攻擊以閃電貸為初始資金槓桿,透過多步驟操作層層突破協議防護,核心攻擊流程可分為資金籌備、狀態操控、無限鑄幣及獲利了結四個關鍵階段,各環節環環相扣,精準利用了協議設計中的邏輯漏洞。
攻擊tx: https://etherscan.io/tx/0x53fe7ef190c34d810c50fb66f0fc65a1ceedc10309cf4b4013d64042a0331156
技術分析
首先透過2個閃電貸分別從Balancer 和 Aave 中借出 wstETH, rETH, WETH 和 0xa35b_ETHx, rETH, wstETH, cbETH。


在閃電貸回調函數中將借出的ETH用1100 ETH 存入Tornado.Cash: 100 ETH混幣,隨後借助Tornado.Cash: 100 ETHwithdraw函數取款 100 ETH 到惡意合約0x3e8e7533dcf69c698Cf806C3DB22f7f10B9B0b97並觸發其fallback函數。


在fallack函數中,可以看到下圖最後一筆exchange與下一步remove_liquidity數值一致,可以推斷前面的步驟都是為了將閃電貸得到的資產都透過exchange等操作兌換成大量的yETH weighted stableswap pool的LP代幣,為後續攻擊做準備。

至此,核心的攻擊流程正式開始。
1.首先將上述exchange得到的LP代幣透過yETH weighted stableswap pool的remove_liquidity函數全部銷毀轉化成按份額分配的8種該pool中的底層資產。
該remove_liquidity函數的邏輯可以理解為假設池子總共有 10,000 個 LP Token,你銷毀了 416.37 個 LP Token,你的比例就是:416.37 / 10,000 = 4.16%。
然後對於每一種資產,假設池子裡有 1,000 個 wstETH(虛擬餘額prev_vb)。你能取走的虛擬餘額:dvb = 1,000 * 416.37 / 10,000 = 41.637 wstETH,然後再除以匯率rate轉換為實際代幣數量。
2.其次透過反覆調用addliquidity類似注入單邊池子,一共有8個amounts參數分別對應要注入的不同資產的數量。觀察到前面的幾次循環index3[rETH代幣]、index6[wOETH代幣]和index7[mETH代幣]都輸入0,即每次加流動性都不加這3個代幣。

透過如上方式注入單邊資產並提取池中代幣的方式人為地擴大池子中rETH、w0ETH和mETH和其他代幣的數量差距。
3.緊接著單邊注入巨量的rETH代幣,而後關鍵的一步removeliquidity,但是輸入amount=0。

為什麼可以提取0個代幣?透過remove_liquidity 的內部實現。

removeliquidity函數沒有對0⾦額進⾏短路處理,依然執行了完整的vbprod計算循環,並且是基於上述人為製造的池子中代幣數量差距計算並更新全局packedpoolvb狀態。
4.而後調用updaterates函數只更新index6[wOETH]的池子比例,最後再調用removeliquidity提取池中代幣,此時該pool中的W0ETH數量已經所剩無幾。

5.同樣的透過類似的方式榨乾pool中index6[w0ETH]和index7[mETH]的份額,注意這裡前兩次更新index6後馬上remove_liquidity提取代幣,而最後一個index7[mETH]目前只做了更新還未提取。

至此透過上述加巨量單邊池並不斷的提取所有池子代幣的方式,pool中W0ETH和mETH的比例已經近乎為0。
此時創建新的惡意合約0xADbE952eBB9b3e247261d2E3b96835f00f721f8E ,並將所有的代幣轉到該合約。注意在這之前的上一步驟中單邊加rETH獲得的LP代幣並沒有兌換成底層代幣,而是也轉移到了新的惡意合約。

前面的攻擊操作在updaterates更新了index7[mETH]而未做提取的代幣在這裡透過調用removeliquidity提取,此時pool中index6[w0ETH]占比份額很小,index7[mETH]的占比份額更小。

此時pool中代幣比例已經嚴重失調,攻擊者再次調用add_liquidity添加流動性,按照[1, 1, 1, 1, 1, 1, 1, 9]的比例獲取巨量LP代幣。

到這裡攻擊者已經獲得大額LP代幣,後續便是透過exchange、redeem等方式獲利了結並償還閃電貸的費用。

攻擊復盤
本次攻擊是一起複雜的多階段組合攻擊,攻擊者利用了pool.vy合約中的三個核心漏洞:精度丟失 (Precision Loss)、收益剝離 (Yield Stripping) 和零供應初始化 (Zero Supply Initialization)。
階段一:製造極端失衡
* 操作 : 攻擊者反覆調用add_liquidity,但刻意避開index 3 (rETH), index 6 (wOETH), index 7 (mETH)。
* 目的 : 人為製造池子中資產比例的失衡。
* 關鍵步驟 : 而後單邊注入巨量rETH。
* 後果 : 極度拉大rETH與其他資產(特別是wOETH和mETH)的數量差距,為精度丟失創造數學條件。
階段二:觸發並鎖定誤差
* 操作 : 調用removeliquidity(amount=0)。
* 原理 :
- remove_liquidity未對0金額進行短路處理。
- 即使不轉帳,合約依然執行vb_prod的完整計算循環。
- 在極端權重失衡下,powdown函數產生顯著的向下取整誤差。
- 合約將這個錯誤偏小的vbprod寫入全局狀態packedpool_vb。
* 本質 : 這是一個"零成本"的狀態攻擊,攻擊者未付出任何代價就成功篡改了池子的賬面價值。
階段三:收益剝離與份額榨取
* 操作 :
- update_rates([6]) (更新wOETH匯率)。
- remove_liquidity (提取資產)。
- update_rates([7]) (更新mETH匯率)。
* 原理 :
- updaterates會觸發updatesupply。由於vbprod之前被惡意壓低,系統誤判池子價值縮水,從而銷毀Staking合約持有的LP代幣來平賬。
- 攻擊者利用remove_liquidity在匯率更新前後進行套利,逐步榨乾池子中wOETH和mETH的份額。
* 結果 : Staking合約的份額被大量銷毀,攻擊者手中的LP份額占比被動提升,池子Total Supply被推向0。
階段四:零供應無限鑄幣
* 前置狀態 : 經過上述操作,池子已被掏空,Total Supply接近0,且wOETH和mETH餘額極低。
* 操作 : add_liquidity,參數為 _amounts=[1, 1, 1, 1, 1, 1, 1, 9]。
* 原理 :
- 當prevsupply ≈ 0時,calc_supply的迭代公式在處理極小數值(1 wei, 9 wei)時失效。
- 合約錯誤地計算出了天文數字的LP Token鑄造量。
- 結果: 攻擊者憑空獲得了235,443… 個yETH LP Token。
總結
Yearn本次攻擊事件暴露了DeFi協議在邊緣場景邏輯校驗、數值計算精度控制及多漏洞組合風險防控上的多重不足。攻擊者以閃電貸為工具、漏洞組合利用為核心、資金混淆為掩護的攻擊模式,凸顯了當前DeFi攻擊的專業化、複雜化趨勢。本次攻擊的核心教訓包括:一是協議需強化對"零金額""極端失衡"等邊緣場景的邏輯校驗,避免因未短路處理產生狀態篡改風險;二是數值計算中需重視極端比例下的精度損失問題,優化powdown等關鍵函數的計算邏輯,此前Balancer協議就曾因精度損失出現安全事件,這已是前車之鑑;三是應建立多維度風險監控體系,對高頻單邊流動性注入、異常匯率更新等可疑操作進行預警。對於整個DeFi行業而言,本次事件再次證明,協議安全不僅需要單個漏洞的修復,更需從全流程視角防範多漏洞組合利用的攻擊,同時加強對攻擊者資金流向的追蹤與攔截,提升行業整體安全防護能力。














