歡迎回到 Sherlock 的漏洞聚焦,在這裡我們會突顯在 Sherlock 審計中發現的一個影響深遠的漏洞。 本週,我們檢視在 @plaza_finance 競賽中發現的錯誤抵押品水平計算,該競賽由 @0xadrii、@KupiaSecurity、@f、 @farman1094_ 和 @0xnovaman33 提供。
漏洞摘要: 在 getRedeemAmount(...) 中,合約使用交易後狀態計算 BOND 贖回的抵押品水平: // 當前代碼(易受攻擊) collateralLevel = ((tvl - (depositAmount * BOND_TARGET_PRICE)) * PRECISION) / ((bondSupply - depositAmount) * BOND_TARGET_PRICE); 因為贖回定價然後使用這個估算的 collateralLevel 來決定是否支付最高價格($100),攻擊者可以以混合(有時折扣)創建價格購買 BOND,直到(當前)抵押品水平降至 ≤ 1.2,然後以 $100 上限贖回所有 BOND——計算時使用一個精心設計的 depositAmount,將估算的抵押品水平推回到 1.2 以上。這讓攻擊者提取 ETH(“無風險”利差),直到池的當前抵押品水平達到閾值。
攻擊步驟: 1) 設置階段 池範例參數: - poolReserve = 120 ETH,bondSupply = 3000,levSupply = 200,ETH 價格 = $3075 定價規則: 創建(購買)BOND: - 如果 collateralLevel ≤ 1.2:creationRate = tvl * 0.8 / bondSupply - 否則:creationRate = $100 贖回(出售)BOND: - 如果估計的 collateralLevel ≤ 1.2:redeemRate = tvl * 0.8 / bondSupply - 否則:redeemRate = $100
2) 階段 A – 以混合/折扣價格購買 BOND - 在監控 (當前) 抵押品水平 = tvl / (bondSupply * 100) 的同時購買 BOND。 - 首次購買發生在抵押品水平 > 1.2 時 → 每 BOND 鑄造接近 $100。 - 隨後的購買將當前抵押品水平壓低至 1.2 以下 → 以折扣創建價格鑄造 (例如,約 ~$94.07),以便便宜地累積大量 BOND 餘額。
3) 階段 B – 以最高價格贖回所有 BOND - 呼叫 redeem(BOND, depositAmount = attackerBondBalance, ...) - 合約使用贖回後的狀態 (bondSupply - depositAmount) 和 (tvl - depositAmount * 100) 計算預估的抵押品水平,並且 (在這個例子中) 得到一個值 > 1.2 - 因為該預估值超過了閾值,redeemRate 被設置為最高 $100,允許攻擊者以 $100 贖回所有累積的 BOND
4) 利潤實現 - 折扣購買與 $100 出售之間的差異產生淨 ETH 利潤。 - 在 PoC 數據中:花費 60 ETH 進行兩次購買,贖回時返回約 61.89 ETH → 約 1.89 ETH 利潤。 - 攻擊者可以不斷迭代,直到當前池的抵押品水平降至約 1.2,提取大約:可提取的 USD ≈ ethPrice × poolReserve − 120 × bondSupply
影響是什麼? 直接資金提取 / 價值流失:攻擊者以折扣價格鑄造並以 100 美元贖回,從池中抽取 ETH。 在閾值之前無限制:可以持續進行,直到池的當前抵押水平縮小至約 1.2。 系統性定價不一致:造成套利,誠實用戶因此支付更差的池儲備/結果。
根本原因: 使用交易後狀態來定價贖回 該代碼計算 collateralLevel,假設贖回已經發生: // 使用 (tvl - depositAmount*100) 和 (bondSupply - depositAmount) collateralLevel = ((tvl - (depositAmount * BOND_TARGET_PRICE)) * PRECISION) / ((bondSupply - depositAmount) * BOND_TARGET_PRICE); 1. 這讓攻擊者可以選擇 depositAmount,使得估計的水平超過閾值 (> 1.2),解鎖 $100 的 redeemRate,即使當前的池狀態並不合理。 2. 基於操縱指標的閾值限制 $100 的上限決策依賴於這個可操縱的估計抵押品水平,而不是當前的(交易前)水平,這使得價格操控成為可能。
減輕措施: 根據當前池狀態計算贖回定價,而不是估算的贖回後餘額。該項目的建議修正是正確的: - collateralLevel = ((tvl - (depositAmount * BOND_TARGET_PRICE)) * PRECISION) - / ((bondSupply - depositAmount) * BOND_TARGET_PRICE); + collateralLevel = (tvl * PRECISION) / (bondSupply * BOND_TARGET_PRICE);
額外加強(建議): 1. 價格單調性:確保贖回價格不會隨著存款金額的增加而上升(沒有「賣得越多,獲得更好的單位價格」)。 2. 不變量定價:從單一不變量推導創建/贖回,以便買賣對稱防止單邊套利。 3. 滑點檢查:要求用戶提供創建和贖回的最小/最大匯率。 4. 限制與調節:每筆交易和每個區塊的贖回上限,以限制接近閾值時的損害。 5. 路徑一致性:對齊創建和贖回路徑,以使用相同的抵押品水平定義(僅限當前狀態)。
我們很自豪能夠通過這次發現幫助 @plaza_finance 確保安全。 當它絕對需要安全時,福爾摩斯是正確的選擇。
3.27K