2025 年 8 月 25 日,在 Cantina 和 Seal911 的協助下,Panoptic 進行了白帽救援行動,保護了約 40 萬美元的風險資金 [1]。根本原因是 s_positionsHash 建構方式存在缺陷:協議使用異或(XOR)運算將倉位 ID 的 Keccak256 哈希值聚合為單一指紋。雖然單個 Keccak256 哈希值仍具備抗碰撞性,但 XOR 的數學線性使得複合指紋變得不安全。攻擊者可以產生一組偽造的倉位 ID,使其 XOR 聚合後的哈希值與任何目標指紋相匹配,從而繞過協議的倉位驗證並在不償還債務的情況下提取抵押品。
背景
Panoptic 是一個建立在以太坊上的去中心化永續期權交易協議,允許用戶交易看跌和看漲期權。
withdraw() 函數有一個名為 positionList 的輸入參數,由一組 tokenId 組成。每個 tokenId 代表一個倉位。withdraw() 函數會根據 s_positionsHash 檢查每個倉位的債務狀態,然後提取用戶的抵押品。
為了節省 Gas,協議不會儲存用戶的每一個倉位(即 tokenId)。相反,它根據用戶的所有 tokenId 計算出一個指紋,並將其記錄在 s_positionsHash 中。每個 s_positionsHash 的高 8 位代表 numLegs,而低 248 位代表 user position hash。
對於每個傳入的 tokenId,協議會計算其哈希值,取低 248 位,並透過將其與當前 s_positionsHash 的低 248 位進行按位異或運算來更新 user position hash。
同時,countLegs 會根據 tokenId 的數值範圍進行調整:當 tokenId 小於 時保持不變;當處於 、 和 範圍內時,分別增加 1、2 或 3。最終將此結果寫入 s_positionsHash 的高 8 位以更新 numLegs。
漏洞分析
根本原因在於合約建構 s_positionsHash 的演算法存在缺陷,具體表現為使用 XOR 運算來聚合 Keccak256 哈希結果。雖然單個哈希函數仍然安全,但 XOR 運算的數學線性使得整體的指紋演算法(即哈希值的 XOR 和)變得不安全 [2]。
線性意味著攻擊者不需要破解哈希函數本身(即從哈希中反推 tokenId)。相反,他們可以採用組合策略:產生大量隨機的 tokenId,計算其 Keccak256(tokenId),並從這些哈希值中選擇一個特定的子集,使得這些 tokenId 哈希值的 XOR 和精確匹配受害者的目標指紋。
這使得攻擊者可以在呼叫 withdraw() 時傳入一組偽造的 tokenId,從而通過健康檢查並提取 s_positionsHash 對應的所有抵押品。
理論
假設用戶的倉位指紋 s_positionsHash 的 user position hash 為 ,numLegs 為 ,用戶的 tokenId 為 。因此:
這裡,每個 248 位的哈希值可以被視為一個 248 維的向量。
因此, 存在於由 0 和 1 組成的 248 維空間()中。在這個空間中,XOR 運算等同於向量加法(附錄 I)。
攻擊者的目標是從所有可用向量中找出 個 248 維向量 ,使得它們的 XOR 和的低 248 位等於 。因此,我們可以將攻擊者的目標表述為一個線性方程組:
具體來說,我們不需要嘗試直接建構 。相反,我們選擇 個線性無關的哈希向量 (其中 等於維度 248),並將它們作為列向量來建構一個 矩陣 :
問題隨即轉換為尋找係數向量 ,使得:
其中 ,且 。
根據線性代數理論,只要矩陣 滿秩,它就生成了整個 維空間。這意味著對於任何目標 ,該方程組都有唯一解。解出 後,我們只需保留那些 對應的向量 ,它們的 XOR 和即為 。
範例
為了便於理解,我們透過一個案例研究來演示此建構過程。假設向量是 3 維的,每個維度僅由 0 或 1 組成,且目標哈希值為 101,即 。
接下來,我們隨機產生 3 個哈希值:
我們使用這三個向量作為列建構矩陣 ,並建立方程 :
透過高斯消去法求解,我們得到 。這意味著我們需要選擇 和 (對應於 ),它們的 XOR 和正好等於目標 。
選擇 n 個線性無關向量
如前所述,要解出 ,我們需要建構一個滿秩矩陣 。鑑於我們處理的是一個極大的向量空間(),核心問題是:如何從這個巨大的空間中快速選擇 個線性無關的向量?
考慮最簡單的方法:隨機產生 個 tokenId 並選擇它們的哈希結果作為向量。
在 上, 個隨機選擇的 維向量形成滿秩矩陣的機率 為:
當 很大時(在本例中 ),該機率收斂為一個常數(附錄 II):
這意味著每次隨機嘗試都有大約 28.9% 的成功機率。平均而言,攻擊者只需要約 3.5 次嘗試即可找到一組線性無關向量。因此,計算成本極低,攻擊者可以快速建構滿足條件的矩陣 。
為了控制高 8 位的 countLegs,我們只需要根據目標 countLegs 調整隨機產生的 tokenId 值的範圍即可。
例如,如果我們希望偽造指紋中的 numLegs 為 0,我們只需確保 個隨機產生的 tokenId 全部小於 。由於此範圍內 tokenId 的 leg 增量為 0,無論高斯消去法的解 選擇了哪些向量,最終累積的 numLegs 都必然為 0。
攻擊分析
白帽救援人員發起了多次救援交易。為簡潔起見,以下討論僅基於其中一筆交易 [3]。
核心邏輯包含以下 5 個步驟:
- 透過 Aave 閃電貸借入 0.23e8 WBTC 和 28e18 WETH。
- 將 0.23e8 WBTC 和 28e18 WETH 存入 poWBTC 合約和 0x1f8d_poWETH 合約。
- 使用正常的
positionIdList呼叫PanopticPool合約的mintOptions(),以借入資金並開立槓桿倉位。 - 呼叫
withdraw(),並傳入偽造的tokenId。由於這些偽造倉位的positionSize為 0,該函數返回的tokenRequired為 0,這意味著所有倉位所需的總抵押品被錯誤地計算為零。同時,由這些tokenId產生的s_positionsHash與步驟 3 中產生的完全相同,從而允許救援人員在不償還任何債務的情況下提取所有抵押品。 - 償還閃電貸並執行下一輪。
總結
此次事件突顯了兩個共同作用的缺陷,它們共同實現了未經授權的抵押品提取。
- XOR 對於哈希而言並非安全的聚合函數。 Keccak256 具有抗碰撞性,但 XOR 的線性意味著多個哈希值的 XOR 和並不繼承該屬性。建構一組其哈希值 XOR 為任何目標值的輸入,簡化為在 上求解線性方程組,這在計算上是微不足道的。哈希複合需要能夠保持抗碰撞性的運算,例如連接後再進行哈希處理。
- 缺少倉位 ID 的驗證。 協議未驗證傳入的
positionId是否對應於有效的期權倉位。小於 的值具有 0 的countLegs和 0 的positionSize,這意味著偽造的倉位不會產生債務。這允許攻擊者在抵押品要求為零的情況下透過健康檢查,同時匹配目標指紋。
參考資料
附錄
以下兩個附錄提供了對正文中陳述的數學解釋和證明,即 XOR 運算等同於向量加法(附錄 I)以及隨機矩陣滿秩的機率(附錄 II)。
附錄 I
在有限域 中,加法定義為模 2 加法:
觀察發現這與邏輯運算「異或」(XOR,符號為 )完全相同。
對於 維向量空間 (本例中 ),兩個向量 和 的加法定義為分量模 2 加法:
因此,在 向量空間中,向量加法等同於向量分量上的按位異或運算。
附錄 II
要使矩陣滿秩,這 個向量必須線性無關。
第一個向量 可以是 中除零向量外的任何向量,提供 種選擇;第二個向量 不能位於 生成的子空間中(該子空間包含 個向量),因此有 種選擇;根據此邏輯,第 個向量 不能位於前 個向量生成的子空間中,導致有 種可能的選擇。
此類矩陣的總數(即 的階數)為:
而所有可能的 矩陣總數為 。
因此,機率 為:
令 ,我們可以將該表達式重寫為:
當 時,該乘積收斂為一個常數:
這意味著對於較大的 ,隨機矩陣滿秩的機率約為 28.9%。
關於 BlockSec
BlockSec 是一家全端區塊鏈安全與加密合規服務供應商。我們建構產品與服務,協助客戶在協議與平台的全生命週期內進行代碼審計(包括智慧合約、區塊鏈與錢包)、即時攔截攻擊、分析安全事件、追蹤非法資金,並履行反洗錢/打擊資助恐怖主義(AML/CFT)義務。
BlockSec 已在知名會議上發表多篇區塊鏈安全論文,通報了多項 DeFi 應用的零日漏洞,阻斷了多次駭客攻擊並成功挽救超過 2000 萬美元資金,保護了數十億美元的加密貨幣資產。
-
官方 Twitter 帳號:https://twitter.com/BlockSecTeam
-
🔗 BlockSec 審計服務 : 提交申請
-
🔗 Phalcon 安全應用: 預約演示



