圖文教程:無限刷BEC幣與漏洞分析
前不久BEC漏洞的事情想必大家都了解了,黑客通過這個漏洞給自己刷了兩波天文數字般的BEC幣,想必很多人都流著口水。雖然大熊不能教大家在現實中撈一把,但在虛擬環境下撈一筆還是可以的,順便還能學下區塊鏈、智能合約的部署,說不定以後能用得上,然後走上人生巔峰呢。
下面就開始搭建測試網路,也給自己印批BEC幣過過癮。
(一)環境搭建
安裝geth客戶端,命令行的方式,主要用來運行以太坊節點、管理賬戶、挖礦、部署智能合約。
具體環境是:Win10 64位、geth 1.8.6(64位)
下載地址:
https://ethereum.github.io/go-ethereum/downloads/
(二)以太坊、合約部署
1、準備創世塊文件genesis.json如下:
{
"mixhash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"difficulty": "0x4000",
"alloc": {},
"coinbase":"0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit":"0xffffffff",
"config": {}
}
相關參數的作用,可自行百度了解,其中difficulty代表挖礦難度。
2、初始化創世塊
管理員許可權打開CMD.exe,在geth.exe 的目錄下,輸入
geth --datadir "%cd%chain" init genesis.json
注意路徑和創世塊文件名要能對得上。
3、啟動區塊鏈節點
管理員許可權打開CMD.exe,在geth.exe 的目錄下,輸入:
geth --identity "MYeth" --rpc --rpccorsdomain "*" --datadir "%cd%chain" --port "30303" --rpcapi "db,eth,net,web3,debug" --rpcaddr "127.0.0.1" --rpcport "8545" --networkid 95518 console
相關參數的作用,可自行百度了解。
看到Welcome to the Geth JavaScript console!
還有最後的「>」 符號,就代表已經啟動完成。
4、創建用戶,創建用戶指令為下(括弧內為用戶密碼)
personal.newAccount("password")
可以看到我已經創建了3個用戶
為方便使用,把三個用戶分別命名為zhangsan、lisi、wangwu
5、挖礦ETH,先前配創世塊文件時,難度參數設定較低,所以很快就挖到一筆ETH(如果現實也可以這樣印鈔就好了...)
挖礦指令如下(括弧內為參與挖礦的CPU,如果不指定的話將會用全部CPU資源,這樣可能會影響操作)
> miner.start(1)
挖了一段時間之後,就需要如下指令來終止挖礦,不然會一直挖下去
> miner.stop()
查詢ETH數量指令如下,可以看到zhangsan上已經有一筆ETH
> eth.getBalance(zhangsan)
(三)無限印幣
1、複製BEC智能合約源碼,用在線Remix工具編譯,點擊「Start to compile」,然後下拉框選擇「BecToken」,點擊「Detail」。
之後,可以看到Remix界面右下方出現很多黃色的Warning,並不會影響使用,除非有紅色的Error。
BEC智能合約地址:
在線Remix工具:
2、複製WEB3DEPOLY裡面的代碼,並粘貼到Geth console,回車。
3、這時候會提示錯誤,因為主節點還沒解鎖賬戶,所以需要通過指令解鎖,然後輸入zhangsan的密碼,即可完成解鎖。
personal.unlockAccount(zhangsan)
4、把剛才的WEB3DEPOLY裡面的代碼複製,並粘貼到Geth console,回車。
5、可以看到合約已經提交到區塊鏈,但是還沒生成,所以需要挖下礦,這樣才能成功部署。然後,輸入「bectoken.」(後面有個點)然後按鍵盤上的Tab鍵,看到已可以使用bectoken裡面的函數了。
6、溢出轉賬
這裡一個坑,坑了我好久,無意中又發現了一個漏洞,不過不是又一個BEC合約的漏洞,而是源於console,先前我一直用這個指令來轉賬:(綠色長串數字就是2^255的具體數值)
>bectoken.batchTransfer([lisi,wangwu],57896044618658097711785492504343953926634992332820282019728792003956564819968,)
但是一直失敗,而且由於數值較大,每次我都會懷疑是不是複製錯了,囧,為了不糾結,還試過:
>bectoken.batchTransfer([lisi,wangwu],Math.pow(2,255),)
也還是失敗,李四和王五的賬號依舊為0。
既然如此,那麼用Remix單步調試看看到底是怎麼回事。
這裡要注意的是:調試前,需要先將Remix連接到本地環境。
調試環境配置好,回到console,輸入交易指令:
> bectoken.batchTransfer([lisi,wangwu],Math.pow(2,255),)
提示認證錯誤,因此解鎖張三的賬戶,然後再次輸入交易指令,就可以看到這次交易的哈希值。
當然,可以看到此次交易只是提交狀態,通過eth.getTransaction指令可以看到還沒有blockNumber,因此需要挖一下礦miner.start(1),才能記錄到區塊鏈,進行調試。
調試界面如下,右邊主要能用到的是
7個主要調試命令——如常用的步入、步過等
Solidity Locals——本地參數
Step detail——執行的詳情
Stack——堆棧
調試發現,原來一直不能成功繞過這條代碼:
require(_value > 0 && balances[msg.sender] >= amount);
因此amount也不會為0,而zhangsan的賬戶上根本沒那麼多BEC幣,所以不能繞過。
換個思路試試,在源代碼直接把_value的值設為2^255,這樣一來可以實現繞過並成功實現轉賬,最起碼證明繞過是肯定可行的。
這種情況下,我懷疑console傳遞_value 時出問題了,那麼是什麼問題呢,在百度上找了很多資料都沒能解決,最後在Github上嘗試發帖諮詢Geth團隊,發帖沒過多久就收到了這位小哥的回復,感謝!才知道原來也是個溢出漏洞。
小哥大概的意思是:控制台是基於JavaScript,而JavaScipt使用float-s表示數字,如果直接傳遞2^255這麼大的數值,將會產生溢出,直接給的結果是數值將會發生變化。
解決方法是:用JavaScript的大數字型檔來表示大數值,如此即能使用任意精度整數。
一言驚醒夢中人,然後我百度該如何表示這個想法,最終實現如下:
用web3.toBigNumber來表示2^255,成功給李四、王五賬戶上刷了一波天文數字BEC幣。
varvalue= web3.toBigNumber("57896044618658097711785492504343953926634992332820282019728792003956564819968");
另外,也許你會困惑,為什麼zhangsan賬戶上也有一筆BEC,仔細閱讀BEC合約,你會發現合約上規定,創造者會在合約生效之後持有一些初始的Token,這個規定在每個合約基本都會有,因為這是基本的盈利方法,也就見怪不怪了。
(四)安全代碼的作用
上面已經成功刷了一波BEC幣,在新聞上也能看到漏洞爆出來之後,BEC幣一落千丈,危害如此之大,那麼該如何解決整數溢出這個問題呢?
其實BEC合約它自己已經回答了這個問題,除了漏洞那行代碼之外,你會發現其它運算都用SafeMath庫里的函數,動手實操一下效果。
更改BEC合約源碼,把漏洞行代碼里的*改成庫裡面的mul函數,再重複上面的過程。
這時已不能繞過檢測,轉賬失敗。
分析下Mul函數,代入具體的數值:
假如:a = 2,b = 2^255
那麼:c = a * b = 0
但: c / a = 0 != b
因此也就繞不過安全運算函數了。
涉及內容較多,仍有許多不盡之處。
有不明白的地方歡迎關注公眾號並交流,大熊將儘快回復,謝謝。
TAG:進擊的大熊 |