header-langage
简体中文
繁體中文
English
Tiếng Việt
한국어
日本語
ภาษาไทย
Türkçe
掃碼下載APP
Partnered With:

Solidity極簡入門 | ERC721專題第四講:BAYC合約嚴重漏洞

閱讀本文需 19 分鐘
BAYC合約一共有兩個嚴重漏洞,一個可能導致圖片被調換,另一個會使BAYC超發,超過設定的10,000 枚
原文標題:《 Solidity 極簡入門 ERC721 專題:4. BAYC 合約嚴重漏洞 》
原文來源:0xAA  


我最近在重新學 solidity,鞏固一下細節,也寫一個「Solidity 極簡入門」,供小白們使用(編程大佬可以另找教程),每週更新 1-3 講。


所有代碼開源在 github:github.com/AmazingAng/WTFSolidity


不知不覺我已經完成了 Solidity 極簡教程的前 13 講(基礎),內容包括:Helloworld.sol,變量類型,存儲位置,函數,控制流,構造函數,修飾器,事件,繼承,抽象合約,接口,庫,異常。在進階內容之前,我決定做一個 ERC721 的專題,把之前的內容綜合運用,幫助大家更好的複習基礎知識,並且更深刻的理解 ERC721 合約。希望在學習完這個專題之後,每個人都能發行自己的 NFT。


TL;DR 太長不看


- 在我查看 BAYC 合約的時候我發現了兩個嚴重漏洞,其中一個可能會導致 BAYC 超發,超過設定的供應量上限 10,000 枚。


- 超發漏洞是由合約中用於項目方預留 BAYC NFT 的 reserveApes 函數沒有檢查是否超發,owner 地址可以隨時鑄造,不受供應量上限的限制。


- 兩種情況下漏洞會被觸發:項目方做惡(幾乎不可能)和黑客盜取 owner 私鑰(有可能)。


- 受漏洞影響的包括 BAYC 以及複用其代碼的其他 NFT 項目方。


- 最簡單的解決辦法就是 BAYC 項目方放棄 ownership。


- 發現這兩個漏洞並不難,我肯定不是第一個發現的(見這篇去年 10 月的博客),但是這些漏洞並沒有引起足夠的重視。鑑於現在 BAYC 市值超過 40 億美元,希望能引起項目方的重視。


聲明:本文只是技術探討,沒有 FUD BAYC。我很喜歡 BAYC,希望漏洞永遠不被觸發。


BAYC


這是 WTF Solidity 極簡入門 ERC721 專題的第 4 講,我們將介紹 BAYC 合約及其漏洞。


無聊猿 BAYC(Bored Ape Yacht Club)是最頂級的 NFT 項目,2021 年 4 月底以 0.08 ETH 的價格發售,一共 10000 枚。目前地板價約 130 ETH,漲了 1000 多倍,市值超過$40 億美元。



BAYC 合約


BAYC 的合約在etherscan上開源,所有人均可查看,今天我們就來仔細學習下它。


BAYC 的合約在 etherscan 上開源


BAYC 的合約是 flat 形式的,一個文件把所有父合約都包括了,一共 2021 行。但其實前面 1900 行都是父合約的內容,只有最後的 100 行是主合約,也是我們將重點學習的。


繼承 



BAYC 合約的 solidity 版本是 0.7.0,繼承了兩個合約,ERC721 和 Ownable。ERC721 合約詳見我的 ERC721 專題1,2, 3講,Ownable 合約最重要的是實現了 onlyOwner 修飾器,使得特定函數只能由合約的 owner 地址調用,詳見Solidity 極簡教程第 8 講:構造函數和修飾器。


狀態變量  



由於合約的 solidity 版本是 0.7.0,尚未內置 SafeMath,因此它用 using-for 聲明瞭對 uint256 類型使用 SafeMath 庫,防止溢出錯誤。


合約裏的狀態變量一共 8 個:


BAYC_PROVENANCE:把所有 NFT 圖片的 hash 按一定順序合併到一起。這個其實是個很巧妙的設計,可證明的把圖片的內容和順序確定下來,又不用在開圖之前暴露圖片信息,還可以解決 NFT 項目方偷把稀有度高的換給自己。Bug 1。但是 BAYC 項目方犯了個錯誤,他們加了一個 setProvenanceHash 函數,可以讓 owner 無數次更改 BAYC_PROVENANCE,與它的初衷相違背,並且留有做惡可能,比如偷換圖片並更改 BAYC_PROVENANCE。正確的改法是把 BAYC_PROVENANCE 設成 immutable,在 constructor 裏初始化後就不能再被修改:  



startingIndexBlock:開始發售的區塊高度。

startingIndex:看起來像是個多餘的變量?

apePrice:BAYC 發售價格,0.08 ETH。

maxApePurchase:每次 mint 的數量限制,最多一次鑄造 20 只。一筆交易 mint 多個 NFT,比每次只能 mint 一個要節省 gas。

MAX_APES:NFT 的最大供給,10,000 個。

Bug 2saleIsActive:是否開始公售。

REVEAL_TIMESTAMP:開圖的區塊高度。


函數


BAYC 主合約定義了 10 個函數:


constuctor:構造函數,初始化代幣名稱,代號,MAX_APES,REVEAL_TIMESTAMP。  


withdraw:取出銷售 BAYC 得到的 ETH。



  reserveApes:**重要!**項目方給自己預留 BAYC,每次調用給自己 mint30 個。只有合約的 owner 可以調用。Bug 2



setRevealTimestamp:更改 REVEAL_TIMESTAMP。 



setProvenanceHash:更改 BAYC_PROVENANCE。Bug 1 



setBaseURI:設定 BAYC 的 BaseURI(ERC721 合約中的狀態變量)。 



flipSaleState:打開/暫停公售。 



mintApe:**重要!**買家支付 ETH 並鑄造 BAYC。調用 ERC721 的_safeMint 函數。條件:

saleIsActive 爲 true,即公售開始。

numberOfTokens <= maxApePurchase,每次只能 mint20 個。

mint 後的流通量小於總供給(10,000 枚)。

支付的 ETH 要大於 0.08 * mint 數量。       



setStartingIndex:看起來像是個多餘的函數?



emergencySetStartingIndexBlock:在緊急情況下,開始公售。將 startingIndexBlock 設爲當前區塊高度。 



BAYC 合約的嚴重漏洞


BAYC 合約一共有兩個嚴重漏洞,一個可能導致圖片被調換,另一個更嚴重,會使 BAYC 超發,超過設定的 10,000 枚。


Bug 1:圖片被換風險


用於證明圖片沒有被篡改、調換的 BAYC_PROVENANCE 變量可以被合約 owner 隨意更改。攻擊者(項目方或盜取私鑰黑客)可以調換圖片,利用 setBaseURI 函數設定新的 metadata 存放網址,然後算出新圖片的 BAYC_PROVENANCE 並更新。這樣,人們沒法通過 BAYC_PROVENANCE 驗證是否被篡改。


正確改寫方法:將 BAYC_PROVENANCE 變量設定爲 immutable,並在構造函數中初始化,之後不能被更改。


Bug 2:增發風險


用於給項目方預留 BAYC 的 reserveApes 函數沒有像公售 mintApe 函數一樣檢查供應量,因此,即使最大供給量 MAX_APES 被設定爲 10,000,合約的 owner(項目方或盜取私鑰黑客)仍可以調用 reserveApes 鑄造新的 BAYC,使得 BAYC#10000,BAYC#10001 等等被 mint 出來,沒有上限。


正確改寫辦法:在 reserveApes 函數中加入最大供應量檢查。


在什麼情況下會被攻擊


前面講的 BAYC 合約中兩個嚴重漏洞,都需要合約 owner 去執行。一種情況就是項目方做惡,去攻擊漏洞。但很顯然 BAYC 非常成功,項目方不做惡會獲得更大的收益,完全沒有做惡的動機,因此這種情況幾乎不會發生。第二種情況就是 owner 錢包私鑰被黑客盜取,黑客做惡調用 reserveApes 超發 BAYC 出售。鑑於 BAYC 官方 ins 前幾天剛被盜,這種情況發生不是絕無可能。目前 BAYC 合約的 owner 地址爲:0xaba7161a7fb69c88e16ed9f455ce62b791ee4d03


讓我們默默祈禱。


如何解決?


其實這兩個漏洞的方法很簡單,就是 BAYC 項目方調用 renounceOwnership 放棄合約 owner。因爲這兩個漏洞的相關函數都需要 owner 去調用,放棄 owner 權限之後將沒人可以攻擊漏洞。


其他的解決辦法大家也可以討論。


彩蛋:項目方預留的 BAYC 給了誰?


BAYC 項目方總共只調用過一次 reserveApes 函數,一共給自己預留了 30 個 BAYC,#0 到 #29,併發送給了 30 個地址,大家可以挖掘一下他們都是誰(按 tokenId 排序):


1、emperortomatoketchup.eth

2、20x46efbaedc92067e6d60e84ed6395099723252496

3、0xc5c7b46843014b1591e9af24de797156cde67f08

4、garga.eth

5、0xwave.eth

6、0xed7c0117d7d35850d71e2a3f390972406f8d5d46

7、0x898c4607809945b49d65ea51580101798931b241

8、rdlwriter.eth

9、bmouse.eth

10、cryptorobo.eth

11、puzzle.eth

12、0xddb338bc464fde06b382d28f37e57cb3727c2e1b

13、chrishol.eth

14、keltron.eth

15、yourstruly.eth

16、0x7225fd5032038bcf49c36deba23a16262521ede9

17、dmnets.eth

18、nabito.eth

19、tropofarmer.eth

20、0xc3fbc3f485f0d9b0bd21b13a4aaa8340160156cb

21、nftfox.eth

22、d34thst4lker.eth

23、thephotographer.eth

24、0xed2d1254e79835bf5911aa8946e23bf508477da4

25、0xf9cb2a5944654b0c9b07d2311715728e30d3ee82

26、billymcsmithers.eth

27、web3ireland.eth

28、yourstruly.eth

29、0x822a16309a9ee40f15e196898f11a010ecb1c963

30、brulik.eth


總結


- 這是 Solidity 極簡教學 ERC721 專題的第 4 講,我們介紹 BAYC 合約及其漏洞。


- 在我查看 BAYC 合約的時候我發現了兩個嚴重漏洞,其中一個可能會導致 BAYC 超發,超過設定的供應量上限 10,000 枚。


- 超發漏洞是由合約中用於項目方預留 BAYC NFT 的 reserveApes 函數沒有檢查是否超發,owner 地址可以隨時鑄造,不受供應量上限的限制。


- 兩種情況下漏洞會被觸發:項目方做惡(幾乎不可能)和黑客盜取 owner 私鑰(有可能)。


- 受漏洞影響的包括 BAYC 以及複用其代碼的其他 NFT 項目方。


- 最簡單的解決辦法就是 BAYC 項目方放棄 ownership。


- NFT 項目方需要更嚴格的審計合約!


聲明:本文只是技術探討,沒有 FUD BAYC。我很喜歡 BAYC,希望漏洞永遠不被觸發。


原文鏈接


歡迎加入律動 BlockBeats 官方社群:

Telegram 訂閱群:https://t.me/theblockbeats

Telegram 交流群:https://t.me/BlockBeats_App

Twitter 官方帳號:https://twitter.com/BlockBeatsAsia

举报 糾錯/舉報
選擇文庫
新增文庫
取消
完成
新增文庫
僅自己可見
公開
保存
糾錯/舉報
提交