美鏈BEC合約漏洞技術分析
這兩天幣圈鏈圈被美鏈BEC智能合約的漏洞導致代幣價值幾乎歸零的事件刷遍朋友圈。這篇文章就來分析下BEC智能合約的漏洞
漏洞攻擊交易
我們先來還原下攻擊交易,這個交易可以在這個鏈接查詢到。
我截圖給大家看一下:
攻擊者向兩個賬號轉移57896044618…000.792003956564819968個BEC,相當於BEC憑空進行了一個巨大的增發,幾乎導致BEC價格瞬間歸零。
下面我們來分析下這個攻擊過程。合約漏洞分析
我們先來看看BEC智能合約的代碼,
BEC在合約中加入一個批量轉賬的函數,它的實現如下:
function batchTransfer(address[] _receivers, uint256 _value) public whenNotPaused returns (bool) { uint cnt = _receivers.length; uint256 amount = uint256(cnt) * _value; require(cnt > 0 && cnt <= 20); require(_value > 0 && balances[msg.sender] >= amount); balances[msg.sender] = balances[msg.sender].sub(amount); for (uint i = 0; i < cnt; i++) { balances[_receivers[i]] = balances[_receivers[i]].add(_value); Transfer(msg.sender, _receivers[i], _value); } return true;
這個函數的作用是,調用者傳入若干個地址和轉賬金額,在經過一些條件檢查之後,對msg.sender的餘額進行減操作,對每一個對每一個傳入的地址進行加操作,以實現BEC的轉移。
問題出在 uint256 amount = uint256(cnt) * _value; 這句代碼,當傳入值_value過大時(接近uint256的取值範圍的最大值),uint256 amount = uint256(cnt) * _value計算時會發生溢出,導致amount實際的值是一個非常小的數(此時amount不再是cnt * _value的實際值),amount很小,也使得後面對調用者餘額校驗可正常通過(即require(_value > 0 && balances[msg.sender] >= amount)語句通過)。我們來結合實際攻擊交易使用的參數來分析一下:
batchTransfer
的參數_value
值為16進位的800000000000000000000...
,參數_receivers
數組的大小為2,相乘之後剛好可超過uint256所能表示的整數大小上限,引發溢出問題amount
實際的值為0,後面的轉賬操作實際上msg.sender的餘額減0, 而對兩個賬號進行了加16進位的800000000000000000000...
,最終的結果是相當於增發了2 * 16進位的800000000000000000000...
。
實際上對於這種整數溢出漏洞,最簡單的方法是採用 SafeMath 數學計算庫來避免。有趣的是BEC智能合約代碼中,其實其他的都使用了SafeMath, 而關鍵的uint256 amount = uint256(cnt) * _value
卻沒有使用。
uint256 amount = _value.mul(uint256(cnt));
就可以防止溢出問題所以在做加減乘除的時候請記得一定使用:SafeMath,代碼在這裡
溢出補充說明
溢出補充說明為小專欄訂閱用戶福利,小專欄的文章內介紹了什麼時候會發生上溢,什麼時候會發生下溢,並且給出了代碼事例。
大家可請前往我的小專欄閱讀。
知識星球深入淺出區塊鏈做好的區塊鏈技術問答社區,歡迎來提問,作為星球成員福利,成員可加入區塊鏈技術付費交流群。
深入淺出區塊鏈 - 系統學習區塊鏈,打造最好的區塊鏈技術博客。http://weixin.qq.com/r/8imlvW-EYjIdrSve93zg (二維碼自動識別)
微信號:深入淺出區塊鏈技術,歡迎訂閱
推薦閱讀:
※馬航 2014 年接連發生事故,會對馬航公司產生何種影響?
※牢記這九點,歲末年終,行車保平安!
※用濃硫酸疏通管道可行嗎?
※尚比亞近300人感染霍亂疫情,中使館再發安全提醒 ,你都知道哪些霍亂防治知識?
※如何快速成為信息安全領域的專家?