SC Price Oracle Manipulation

在去中心化金融(DeFi)中,預言機(oracles)扮演著重要角色,它們是連接區塊鏈內智能合約和區塊鏈外現實世界資料的橋樑。當智能合約需要知道某個資產的市場價格時,它會向預言機請求資料。然而,如果攻擊者能夠操縱預言機提供的資料,就會導致合約做出錯誤的判斷,進而引發一系列災難性後果。

攻擊者可能會通過以下方式利用這個漏洞:

  • 操縱預言機提供的價格資料,讓智能合約誤以為某個資產的價值發生了改變。
  • 利用這些被操縱的價格,進行未經授權的借貸、超額槓桿交易,甚至耗盡流動性池。

漏洞範例

以下是一個存在漏洞的智能合約範例:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IPriceFeed {
    function getLatestPrice() external view returns (int);
}

contract PriceOracleManipulation {
    address public owner;
    IPriceFeed public priceFeed;

    constructor(address _priceFeed) {
        owner = msg.sender;
        priceFeed = IPriceFeed(_priceFeed);
    }

    function borrow(uint256 amount) public {
        int price = priceFeed.getLatestPrice();  
        require(price > 0, "Price must be positive");

        // Vulnerability: No validation or protection against price manipulation
        uint256 collateralValue = uint256(price) * amount;

        // Borrow logic based on manipulated price
        // If an attacker manipulates the oracle, they could borrow more than they should
    }
    // Repayment logic
}

漏洞分析

這個合約的 borrow 函數直接使用從預言機 priceFeed 獲取的價格,但沒有任何機制來驗證這個價格的真實性或合理性。如果攻擊者能操控 priceFeed,將資產價格虛報,他們就能以較少的抵押品借出更多的資金。

影響

價格預言機操縱可能導致以下嚴重後果:

  • 超額借貸:攻擊者可以虛報資產價格,讓合約誤以為其抵押品價值更高,從而借出遠超過實際價值的資金。
  • 錯誤清算:當被操縱的價格導致抵押品被錯誤地低估時,可能使無辜的用戶在不該被清算時,卻被強制清算。
  • 資金池枯竭:攻擊者可以利用被操縱的價格,在市場上進行套利,甚至耗盡合約中的流動性。

如何修復?

為了防範這類攻擊,可以採取以下補救措施:

  • 多重預言機聚合:不要僅依賴單一預言機。可以從多個獨立且可靠的預言機獲取資料,然後取平均值或中位數,以降低單一來源被操縱的風險。
  • 設定價格門檻:在合約中設定可接受的最低(minimum)和最高(maximum)價格範圍。如果預言機提供的價格超出這個範圍,則拒絕該筆交易。
  • 時間鎖:在價格更新之間設置一個時間鎖,避免價格瞬間發生劇烈變化,給攻擊者可乘之機。
  • 資料驗證:使用加密證明(如信任方簽名)來驗證預言機資料的真實性。

修復後的範例

以下是修復了上述漏洞的合約範例:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IPriceFeed {
    function getLatestPrice() external view returns (int);
}

contract PriceOracleManipulation {
    address public owner;
    IPriceFeed public priceFeed;
    int public minPrice = 1000; // Set minimum acceptable price
    int public maxPrice = 2000; // Set maximum acceptable price

    function borrow(uint256 amount) public {
        int price = priceFeed.getLatestPrice();
        require(price > 0 && price >= minPrice && price <= maxPrice, "Price manipulation detected");

        uint256 collateralValue = uint256(price) * amount;

        // Borrow logic based on valid price
    }

    function repay(uint256 amount) public {
        // Repayment logic
    }
}

修復內容

在修復後的版本中,borrow 函數在取得價格後,會先使用 require 語句檢查價格是否落在預設的 minPricemaxPrice 範圍內。這樣一來,即使預言機被攻擊,合約也會因為價格不合理而拒絕執行,從而保護了合約的資產安全。

新增程式碼:int public minPrice = 1000;// 設定可接受的最低價格
新增程式碼:int public maxPrice = 2000;// 設定可接受的最高價格

新增程式碼:require(price > 0 && price >= minPrice && price <= maxPrice, "Price manipulation detected");// 關鍵修復:新增價格驗證,確保價格在預設的範圍內