Integer Overflow | Why Your Smart Contract Isn't Safe
三句話摘要
Solidity 智能合約中 unchecked 關鍵字導致的整數下溢漏洞如何讓攻擊者虛造巨額餘額並掏空金庫。 刪除一個關鍵字修復了一個導致 90 萬美元損失的漏洞,足以說明靜態審計和對原語危險性的深刻理解有多重要。 無符號整數的下溢行為特異。區塊鏈上的餘額是無符號整數,無法為負。當減法結果應為負數時(如 0−1),不會顯示負值,而是環繞到最大值——就像里程表從 00000 往回滾變成 99999,Solidity 數字也會跳到 78 位數的天文數字。
重點整理
重點- 1
無符號整數的下溢行為特異。區塊鏈上的餘額是無符號整數,無法為負。當減法結果應為負數時(如 0−1),不會顯示負值,而是環繞到最大值——就像里程表從 00000 往回滾變成 99999,Solidity 數字也會跳到 78 位數的天文數字。
- 2
Solidity 0.8 自動在每個算術運算前設防。任何可能導致下溢的減法都會自動回滾整個交易,預設安全。但開發者可用 unchecked 關鍵字手動關閉此保護以省少許 gas 費,這正是漏洞的源頭。
- 3
vulnerable settle 函數將費用從使用者餘額中扣除,但該減法被 unchecked 包裹。若費用大於餘額(如 1−2),下溢發生無人察覺,餘額變成接近 2^256 的數字,使用者聲稱對金庫擁有遠超實際的權利。
- 4
攻擊四步驟即可排乾金庫:存入 1 個代幣(餘額 = 1)→ 呼叫 settle(fee=2)→ 1−2 下溢變成近無限大 → 提取 101 個代幣(遠超金庫持有)。整個過程在 Sepolia 測試網上真實重現並驗證可行。
實用技巧與重點
乾貨- 受害者:NFT 流動性協議(混合型代幣,既可流通也可作 NFT)
- 漏洞金額:約 90 萬美元
- 漏洞位置:settle 函數的 `credit -= fee` 被 unchecked 包裹
- 測試網驗證:Sepolia testnet,Etherscan 可查
- 漏洞數學:uint256 最大值 = 2^256 − 1
- 典型攻擊數據:
- 步驟 1:deposit(1) → credit = 1
- 步驟 2:settle(fee=2) → 1−2 下溢 → credit ≈ 2^256
- 步驟 3:redeem(101) → 檢查「credit ≥ 101」成立(因 credit 近無限大)
- 步驟 4:金庫餘額 100 → 全部轉給攻擊者
- 修復:刪除 unchecked 關鍵字一個詞
- 修復後結果:同樣的 settle(fee=2) 交易變成 revert,金庫保持安全
結論
結論“刪除一個關鍵字修復了一個導致 90 萬美元損失的漏洞,足以說明靜態審計和對原語危險性的深刻理解有多重要。”
完整解析
詳細區塊鏈智能合約的餘額本質上是無符號整數,無法表示負數。在傳統計算中,0 減 1 得 −1,但無符號整數無法存儲負值,因此會產生環繞效應——就像汽車里程表從 00000 反轉一圈會變成 99999,Solidity 中 0−1 會變成一個 78 位數的天文數字,接近 2^256。
Solidity 0.8 版本之後,開發者做出重大安全改進:每一個算術運算都預設進行溢出檢查。若減法結果應為負,交易直接回滾,使得簡單的數學錯誤無法造成合約破裂。然而,為了省略這些檢查帶來的少許 gas 成本,開發者可以用 `unchecked` 關鍵字手動關閉保護。這在某些場景下合理(例如已數學證明不可能下溢),但若使用不當就成為漏洞。
在此案例中,一個 NFT 流動性協議的 settle 函數負責從使用者的信用額度中扣除費用。問題在於這條減法語句被 `unchecked` 包裹。攻擊者只需存入 1 個代幣取得信用額度 1,再用費用 2 呼叫 settle。1−2 本應回滾,但 unchecked 讓它無聲地環繞,信用額度瞬間膨脹到近無限大。之後攻擊者聲稱自己有足夠額度,一口氣從金庫提走 101 個代幣(金庫正好持有 100 個)。整個攻擊在 Sepolia 測試網上被完整重現且可在區塊瀏覽器查證——這不是理論漏洞,而是真實的鏈上交易記錄。
修復方案簡直諷刺地簡單:刪除 `unchecked` 一個詞即可。恢復檢查後,同樣的攻擊交易會在 1−2 下溢時自動回滾,信用額度保持為 1,金庫和攻擊者的餘額都被保護。90 萬美元的漏洞與安全合約的唯一差異,就是一個英文單詞。
關鍵時刻
Pipeline v2帶時間戳的重點,會在逐字稿層級分析上線後產生。目前請先透過原始影片觀看。
事實查核
Pipeline v2說法查證是下一次管線升級的一部分。KeyFrame 只會顯示它真正能驗證的內容。

