智能合約安全審計之路-訪問控制漏洞
- 2020 年 3 月 8 日
- 筆記
核心問題:publi c的惡意使用(本次案例合約為例) ) )
作者-畢竟話少
描述:合約沒有設置合理的訪問控制模型,以及沒有對合約有效的校驗導致訪問控制漏洞的發生
核心問題:public的惡意使用(本次案例合約為例)
漏洞描述
智能合約的訪問控制漏洞主要體現在以下倆個方面:
- 代碼層面可見性
針對函數和變量,限制其所能被修改和調用的作用域
- 邏輯層面權限約束
通常針對函數,限制某些特權用戶訪問
代碼層面可見性的函數普及:
- public
默認狀態下,可以進行任何形式的調用
- external
可以通過其他合約或者交易來調用,不能在合約內部進行調用
- internal
只能在合約(含子合約)內部進行調用
- private
只能在合約(不包含子合約)內部進行調用
邏輯層面的權限約束的函數普及:
- modifier
1.用於函數執行前的函數檢查
2.可以設置參數
3.特殊符號「_」用於指代函數代碼的執行位置
modifier noReetrancy() { if (locked) throw; locked = true; _; locaked = false; }
漏洞合約分析
pragma solidity ^0.4.24; contract AccessGame{ uint totalSupply=0; address public owner; mapping (address => uint256) public balances; event SendBouns(address _who, uint bouns); modifier onlyOwner { if (msg.sender != owner) revert(); _; } constructor() public { initOwner(msg.sender); //initOwner()初始化管理員權限 } function initOwner(address _owner) public{ owner=_owner; } function SendBonus(address lucky, uint bouns) public onlyOwner returns (uint){ require(balances[lucky]<1000); require(bouns<200); balances[lucky]+=bouns; totalSupply+=bouns; emit SendBouns(lucky, bouns); return balances[lucky]; } }
漏洞點:第21行,在進行初始化管理員的時候,並沒有對init0wner()函數設置合理權限,使用public函數進行調用(默認狀態下,可以進行任何形式的調用),攻擊者可以自己調用init0wner()函數使自己成為管理員,從而調用SendBonus()增加自己的balances
使用Remix進行進行調試
- 首先對合約進行編譯(Current version設置為0.4.24,Auto compile,Enable Optimization全部勾上。編譯完成後會出現1個合約為AccessGame
- 首先部署AccessGame(漏洞合約),Account設置默認管理員地址(0Xca3…a733c),點擊Deploy,部署完成後,首先點擊owner,查看管理員為(0xca3…a733c),到這裡漏洞合約就已經部署完成了
- 模擬攻擊調試,Account換一個地址為攻擊者地址(0x147…c160c),由於init0wner()函數是使用public自由調用的,所以這裡直接將攻擊者地址(0x147…c160c)複製粘貼到init0wner處點擊即可,這裡使用owner查看發現管理員為(0x147…c160c),已被成功越權替換,由於這裡攻擊者地址已經被設置為管理員權限了,所以可以直接調用SendBonus()為自己賬戶添加ETH(lucky設置為0x147…c160c,bouns設置為100 wei ETH),點擊transact進行充值,充值完成後使用Balances進行查看,發現攻擊者賬戶為100 wei ETH,實驗成功。
漏洞預防
- 設計合理的訪問控制模型,並在代碼中進行校驗
- 合理使用可見性約束和modifier
- 使用形式化驗證檢測智能合約的訪問控制漏洞