作者:xxxeyJ
本文為作者投稿,Seebug Paper 期待你的分享,凡經采用即有禮品相送! 投稿郵箱:paper@seebug.org

前言

最近我搞了一個小蜜圈,星球主攻區塊鏈安全方向,但是目前由于圈內的小伙伴扎根在傳統安全行業久已,對于區塊鏈安全沒有進一步的了解(經過調研發現大多數小伙伴只停留在了曉得區塊鏈,比特幣等幾個基礎概念),在此之前發在小蜜圈的文章也并沒有很好的帶動學習氣氛,我想主要原因是由于小伙伴們對區塊鏈安全不甚了解才導致了這幅局面,于是本文便應運而生,由于本文是出于教學的目的編寫,故內容較為細化,適合對區塊鏈安全感興趣但目前處于新手村并且可以靜下心來閱讀學習的小伙伴食用,本文將會圍繞著遵循 附錄1 ERC20 標準的 SlowMist Zone Token 展開審計,希望本文的誕生會對后續小蜜圈以及各位小伙伴在區塊鏈這一領域的發展起到良好的鋪墊作用

前期準備工作

  • SlowMist Zone Token 智能合約流程圖

審計智能合約之前,需要先對審計對象有個基礎了解,比如這里的慢霧區通證

Smart Contract: 0xcb0797aaca2fd4edd3bf07e7157d40322629af8b (Contract Account)

Holders: 99 (持幣者數量)

Max Total Supply: 102,400,000 (最大發行總量)

Decimals: 18 (精度)

Name: SlowMist Zone Token (Token 全稱)

Symbol: SLOWMIST (Token 符號)

Owner Account: 0x06a3f099e75720fd7415f87edc8cd9953b36d171 (Ownership) 附錄2

CODE REVIEW

SlowMist Zone Token 采用單源文件多合約的形式部署智能合約,.sol 源文件內部合計共 9 個 Smart Contract,其在源文件內實現 SafeMath Library

Line 5 標識使用 Solidity 編譯器版本號不低于 0.4.23,且不高于下個大版本(0.5.0)

Line 12 - Line 52 在源文件內部實現了 SafeMath Library,將其作用于智能合約內部的數學運算以防止整型溢出漏洞的產生,在 SlowMist Zone Token 內部使用到的 SafeMath Library 只有sub() 以及 add()這兩個function,我想這也是為什么 div() 功能代碼被注釋掉的原因,這里值得一提的是,附錄3 Solidity ^0.8.0 版本之后編譯器內部默認集成了 SafeMath Library,因此,在后續的版本直接使用 Solidity 默認的數學運算符 即可避免整型溢出漏洞的產生

Line 59 - Line 64 實現了一個更為精簡的 ERC20 標準,其中聲明了 3 個 function,以及定義了一個 Transfer 事件,Line 70 BasicToken 子合約繼承 ERC20Basic 父合約,Line 71 表示將 SafeMath Library 中的 function 應用于 uint256 整數類型,Line 73 構造一個名為 balances映射(Mapping),在當前智能合約中給它的定位是將此映射表示為指定賬戶持有的 Token 數量,Line 75 定義了一個 totalSupply_ 狀態變量,在當前 Token 中,使用到該狀態變量的功能共有三處,其一是 Line 80 的 totalSupply() function,可見性為 public,表示可公開調用,函數返回值為 totalSupply_,用以獲取該 Token 中的發行總量,其二被作用在了 MintableToken 合約內的mint() function,用來與 tmpTotal變量聯動判斷當前已發行的代幣數量,以確保其發行數量不超過最大發行總量,其三是這個變量(最大發行總量)會在后續主合約中的構造函數中定義下來,Line 89 - Line 97 實現了 Transfer 轉賬功能,檢查to接收者地址不為 0x00 并檢查轉賬金額小于等于發起人余額,通過兩步檢查后,使用 SafeMathsub()function 給調用者uint256 balances(address(msg.sender) 扣除轉賬金額,然后使用 SafaMathaddfunction 給to 目標地址增加相應的轉賬金額(Token),而后觸發 Transfer 事件,返回 True 表明調用成功

通過 balanceOf() function 實現獲取給定地址賬戶的余額(Token數量)

ERC20 合約繼承自 ERC20Basic 合約,合約內部實現了三個方法,定義了一個 Approval事件

StandardToken 這一合約實現了標準化的 ERC20 ,其繼承自 ERC20, BasicToken 兩個合約,合約內部定義了一個 allowd 映射(Mapping),allowd 在此合約內表示_owner這一賬戶授權給 _spender 賬戶可使用的金額(Token), 映射分為兩部分,mapping(keyType => valueType),其中 keyType存在一定的限制,keyType 不能為 映射, 變長數組, 合約, 枚舉, 結構,而 valueType無任何限制,可以為任意類型,包括(Mapping)自身類型,transferFrom()approve() 這兩個方法需要組合使用,首先通過 approve() 授權指定賬戶(_spender)可以使用相應金額的 Token, 然后被授權者通過 transferFrom 實現轉賬邏輯,而后給 allowd[_from][msg.sender]減去相應已使用的金額,由于approve()在早期版本存在條件競爭的風險,OpenZeppelin 提出了一種解決方案 詳情見 附錄4,慢霧在此沿用了這種方案,使其在 Token 內部實現了 increaseApproval() 用以追加支付授權額度,以及實現了 decreaseApproval() 用以撤銷指定額度的支付授權,其中 decreaseApproval() 需要傳遞兩個參數,被授權者地址以及想要撤銷的金額,邏輯如下,將已授權的金額賦值給 oldValue 以便后續比對金額,如果想要削減的金額比被授權者持有使用權的金額大的情況下,則將授權金額直接清零,否則,根據其(_subtractedValue)指定的撤銷金額對被授權者減去相應的金額使用權,最后,觸發 ERC20 合約內的 Approval 事件

Line 255 實現了 Ownable Library,其中定義了一個名為owner的狀態變量,表明合約所有者(Ownership),定義了兩個事件,OwnershipRenounced 以及 OwnershipTransferred ,盡管合約內并沒有寫關于放棄所有權的代碼,緊接著是一個構造函數,用于初始化 Ownable 合約,將調用者 address(msg.sender) 賦值給 owner 這一狀態變量,下面是一個修飾器(modifier),在當前 Token 中用于校驗調用者是否為所有者身份(Ownership),transferOwnership() 方法用于移交所有權

MintableToken 是一個專門用于鑄幣的合約,繼承自 StandardTokenOwnable 這兩個合約,繼承 Ownable 合約的原因是為了使用其 owner 狀態變量以便于確認所有者身份,mint() 使用了 hasMintPermissioncanMint 修飾器加以修飾,hasMintPermission 用于確認鑄幣者是否為 owner 賬戶,canMint 用于檢查是否允許鑄幣,Line 301 定義了一個名為 mintingFinished 的 bool 類型的狀態變量,其值為 false,修飾器內進行了!取反操作,則通過檢查,函數體內首先將當前已鑄幣量和待鑄幣數量相加并賦值給一個臨時變量以便檢驗發行量是否小于 1.024 億 這個數字 (從這點可以看出此Token不可增發!),條件判斷成立后給 mintTotal 變量增加發行的金額以及給指定賬戶鑄造了指定 Token數量,最后,觸發兩個事件以確認成功鑄幣

Pausable 繼承自 Ownable Contract,合約內部定義了兩個用于暫停/取消暫停的事件,Line 348 定義了一個名為 paused的 bool 類型狀態變量,可見性為 public,此合約將該變量作用于 whenNotPausedwhenPaused 修飾器,paused 初始狀態為 false,表示為暫停狀態,這時只能夠調用unpause() 以取消其暫停狀態,而后 paused 變量被賦值為 false,這時則可以通過由 whenNotPaused修飾的 pause() 方法將其暫停

PausableToken 繼承自 StandardToken, Pausable,使用到了Pausable 的修飾器whenNotPausedwhenNotPaused 修飾器 !paused 執行取反操作則為 false,得出 Token 目前處于暫停狀態,可以將 super.function 關鍵詞理解為繼承關系的最上游,比如說 Line 399 的 return super.transfer(_to, _value),調用到的 function() 來自于最后一個實現此方法的合約,繼承關系如下:

最后是 SlowMistToken 這一主合約,定義了三個用于標識 Token 信息的狀態變量,以及 Line 455 的構造函數設定最大發行總量為 102,400,000Token,Line 458 的 fallback() 回退函數不可用于接收 ETH,強行向該合約賬戶轉賬將會導致狀態回滾

后記

總體看下來,慢霧科技的 SlowMist Zone Token 在合約代碼滿足了其業務需求的同時盡可能將攻擊面降至最低,就目前市面上公開的攻擊手法來講,慢霧區 Token 的安全性毋庸置疑,回歸審計文章原題,在我看來,代碼層面沒有漏洞,不代表其它層面沒有問題,漫霧科技給SlowMist Zone Token的定位是社區激勵代幣,它沒有在二級市場流動所以不具備金融屬性,即便劫持了該 Token 的 Ownership賬戶 ,在我看來也做不了什么大的文章,目前來講,該 Token 直面的威脅主要有兩點,一個是防范 Ownership 賬戶淪陷的風險(比如說通過釣魚等手段劫持其 Owner 賬戶),另一個則是目前藏匿于區塊鏈生態中那片光亮照不到的 0day

總結

近年來,區塊鏈生態安全形勢愈演愈烈,區塊鏈自身的金融屬性是其它行業所不具備的,據統計加密貨幣市值已超過 1.66 萬億美金$,區塊鏈中的鏈上安全形勢尤為嚴峻,且伴隨著DApp(去中心化應用), DeFi (去中心化金融),NFT (非同質化代幣) 等底層架構依附于區塊鏈技術的新興概念誕生,區塊鏈也將會給一眾從業者們帶來前所未有的機遇,如果你對區塊鏈安全感興趣,并且想要加入知識星球 區塊危機 共同學習,可以掃描下方二維碼添加我的微信,星球主體內容為當下較為冷門的區塊鏈安全(Blockchain Security),相信加入本星球的小伙伴們能夠有所收獲

附錄


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1664/