發(fā)布時間:2024-03-07 09:36:52 瀏覽量:250次
摘要:無論是 Fomo3D 山寨版還是正宗原版都擺脫不了"一輪就涼涼"的宿命,這與其智能合約的設計漏洞不無關系。本文從合約安全開發(fā)的角度出發(fā),詳細分析了類 Fomo3D 游戲的兩個問題,并提出若干個可能的解決方案。希望能有所幫助,歡迎感興趣的朋友加入技術社區(qū)討論。
Fomo3D 游戲已正式進入第三輪。截止北京時間 9 月 29 日上午 11 點整,本輪獎池僅累積了 97.8988 Ether,外加上一輪滾入的 680 Ether,獎池總金額不足 800 Ether,相較前兩輪的盛況,可謂慘不忍睹。
安比(SECBIT)實驗室曾經(jīng)撰文分析了類 Fomo3D 游戲的衰敗現(xiàn)狀,先來簡單回顧一下 [1]。
圖一:Fomo3D 玩家參與度與入場資金狀況
上圖展示了「Fomo3D 玩家參與度與入場資金狀況」。紅色代表調(diào)用合約參與游戲的人次,藍色則代表進入游戲合約的資金量。圖左側出現(xiàn)數(shù)據(jù)曲線最高峰,對應時間分別是 7 月 20 日和 7 月 21 日。這兩天恰好大量媒體瘋狂報道 Fomo3D 這一現(xiàn)象級游戲。當時眾多玩家跟風入場,游戲合約的參與次數(shù)和入場資金均達到了最高峰,入場資金量超過 40,000 Ether,而參與次數(shù)最高超過 18,000 次。高峰過后,F(xiàn)omo3D 游戲熱度驟降,于 8 月 22 日前后結束第一輪,并隨即進入第二輪,但游戲熱度已然無法恢復。
盡管如此,黑客卻沒有停止攻擊。
圖二:Fomo3D 游戲合約被攻擊狀況
上圖是「Fomo3D 游戲合約被攻擊狀況」,第一輪游戲高峰前后以及第二輪開始后,有黑客瘋狂地利用"空投漏洞"進行攻擊,攫取高額收益 [2]。而在第一輪臨近結束,以及第二輪倒計時快結束之際,則有黑客瘋狂嘗試"阻塞交易"攻擊,企圖奪取最終大獎 [3]。
不僅僅是 Fomo3D 原版游戲,其他眾多的類 Fomo3D 山寨游戲,也成為黑客的攻擊目標。
Fomo3D 類游戲參與形式是用 Ether 購買游戲道具,最后一位購買者獲得"最終大獎",平時參與者有一定概率獲得"空投獎勵",分別從主獎池和副獎池中獲取。這兩類獎勵是游戲設計層面對參與者的重要激勵。這一設計,目的在于利用"隨機"和"競爭"提升游戲趣味度,吸引更多人投入資金參與,從而延長游戲時間。
然而事與愿違,由于合約代碼存在漏洞,掌握攻擊技巧的黑客能夠以很高的概率持續(xù)獲得"空投獎勵",而"最終大獎"也會被黑客利用特殊技巧奪走。普通參與者在這類游戲中幾乎無法獲得這兩種重要獎勵。因此,他們僅能幻想在每輪游戲開始后第一時間入場,然后靠后續(xù)他人的資金回本。但是,游戲最重要的兩個激勵機制已然失效,無法持續(xù)吸引新資金,最終形成惡性循環(huán)。
黑客是如何利用這兩個漏洞的?項目方難道就無計可施嗎?
先看看"空投獎勵"。
所有投入游戲的 Ether,會有 1% 數(shù)量進到副獎池??胀兜母怕蕪?0% 開始,每增加一筆不小于 0.1 ETH 銷售訂單,空投概率會增加 0.1%。同時空投獎勵金額與購買金額也掛鉤,如果購買 0.1 ~ 1 ETH,就有概率贏得 25% 副獎池獎金,購買越多則比例越大。游戲界面會鮮明顯示當前中獎概率和獎池金額。
Fomo3D 空投獎勵實現(xiàn)存在兩處問題:
1. 合約中的"隨機數(shù)"可被預測
1. 判斷調(diào)用者是否是合約地址的方法有漏洞
空投獎勵依靠智能合約內(nèi)生成的"隨機數(shù)",在 Fomo3D 源碼中由 airdrop() 函數(shù)控制。
airdrop() 函數(shù)中的"隨機數(shù)" seed 由各種區(qū)塊信息和交易發(fā)起者地址計算得來。這顯然十分容易預測 [4]。
為了防止合約自動化攻擊,F(xiàn)omo3D 開發(fā)者還使用 isHuman() 來防止合約賬戶參與 Fomo3D 游戲,試圖以此方法來禁止玩家在合約內(nèi)預測中獎隨機數(shù)。
這里犯了另一個常見錯誤。extcodesize 操作符用來獲取目標地址上的代碼大小。對于已部署成功的合約,由于其地址對應著特定代碼,extcodesize 的返回值始終大于 0。因此不少人用此方法來判斷目標地址是否是合約,F(xiàn)omo3D 甚至以此為依據(jù)來阻止合約調(diào)用特定函數(shù)。但該判斷方法存在明顯漏洞,在構造新合約的過程中(即合約構造方法里)調(diào)用游戲參與函數(shù)即可繞過該限制。這是因為合約在構造過程中,其地址并未對應任何代碼,extcodesize 的返回值為 0 [5]。
上述的兩個安全問題綜合作用,最終導致黑客可以構造攻擊合約,通過合約參與游戲,隨意預測隨機數(shù),進而極大提高自己的勝率 [2]。
那么究竟如何解決 Fomo3D 的"空投漏洞"?
黑客能夠成功攻擊,是利用了上文列出的兩個漏洞,構造攻擊合約來預測游戲合約中的"隨機數(shù)"。因此,我們只需完成以下兩件事之一,使攻擊所需的必要條件不滿足即可:
1. 防止智能合約中的"隨機數(shù)"預測
1. 采取更安全的方式判斷調(diào)用者是否是合約
讓我們先解決"隨機數(shù)"預測的問題。
智能合約環(huán)境內(nèi)"隨機數(shù)"容易被預測的原因在于,"隨機數(shù)"產(chǎn)生所依賴的"隨機源"可以被任何人輕易獲得。攻擊者可以構造一個攻擊合約,在相同環(huán)境內(nèi)執(zhí)行"隨機數(shù)"計算公式,即可得到需要的"隨機數(shù)",并以之作為下一步行動的判斷依據(jù)。
智能合約內(nèi)幾乎一切可用變量都是公開的,并且"隨機數(shù)"計算公式需要確保所有節(jié)點執(zhí)行結果都一致。因此,很難找到十分簡潔的方法來產(chǎn)生無法被預測的"隨機數(shù)"。
但仍有一些稍復雜但可行的解決方案。如開發(fā)者可通過先提交再披露(commit/reveal)、或延遲若干個區(qū)塊開獎。此外,還有一些引入外部預言機(Oracle)的方案,如 Oraclize 和 BTCRelay [6]。
安比(SECBIT)實驗室結合 Fomo3D 游戲機制,介紹一種利用"當前/未來"區(qū)塊的哈希值來防止"隨機數(shù)"被預測的方案 [7]。
以太坊智能合約中可以通過 block.blockhash() 來獲取特定區(qū)塊的哈希值。該函數(shù)接受參數(shù)為區(qū)塊高度,可取范圍為除當前區(qū)塊外的最近 256 個區(qū)塊。當傳入其他值時,該函數(shù)均返回 0。
常見不安全的"隨機數(shù)"計算方法,會讀取當前塊的前一個塊的哈希 block.blockhash(block.number-1) 作為隨機源。而在合約內(nèi)執(zhí)行 block.blockhash(block.number) 返回值為 0。我們無法在合約內(nèi)獲得當前區(qū)塊的哈希,這是因為礦工打包并執(zhí)行交易時,當前區(qū)塊哈希尚未被算出。因此,我們可以認為"當前區(qū)塊"哈希是"未來"的,無法預測。
我們可以在用戶首次購買道具參與游戲時,記錄其地址、當前區(qū)塊高度 N 至一個數(shù)組中,最終拿到一個唯一的 id(如下面 _purchase() 函數(shù)所示)。
在接下來的 255 個區(qū)塊內(nèi),用戶可以用該 id 再次參與游戲,此時高度為 N 的區(qū)塊哈??烧+@得,以此來生成"隨機數(shù)",判斷用戶是否中獎(如下面 _airdrop() 函數(shù)所示)。
255 個區(qū)塊之后,用戶參與游戲時的區(qū)塊哈希在合約內(nèi)無法正常獲得。因此,務必要限制用戶在一定時間范圍內(nèi)查詢是否中獎,并及時參與游戲領取獎勵。當然,為了游戲體驗,如果用戶錯失領獎,也可以參照上面的原理再給他一次機會重新抽獎。結合游戲規(guī)則,這里仍有一些技術細節(jié)需注意,歡迎添加小安同學微信(secbit_xiaoanbi),加入到「SECBIT 智能合約安全技術群」參與討論。
這種方法也用在知名的區(qū)塊鏈卡牌游戲 Gods Unchained 中,用來控制用戶所購卡牌稀有程度。當然我們也可以用當前高度后指定數(shù)量(如五個)的區(qū)塊哈希來作為隨機源,原理是一樣的 [8]。
另一個問題,我們?nèi)绾闻袛嗾{(diào)用者是否是合約地址?
有一個簡便但是有效的方法。
以太坊安全開發(fā)最佳實踐中推薦盡量不要使用 tx.origin,因為很多人將 tx.orign 和 msg.sender 混淆。tx.orign 代表的是一筆交易的發(fā)起者,而 msg.sender 代表每一次合約調(diào)用(call)的發(fā)起者。
如普通賬戶 A 調(diào)用合約 B,合約 B 再調(diào)用合約 C。在合約 C 內(nèi),msg.sender 是合約 B,而 tx.origin 是賬戶 A。msg.sender 可以是合約地址,但 tx.origin 永遠不會是合約。因此,上面的方法可以有效防止合約調(diào)用合約。
再看看"最終大獎"。
Fomo3D 類游戲存在倒計時,在每輪游戲結束前最后一個購買道具的參與者獲勝,可以拿走主獎池中近半的資金。因此眾多參與者會在臨近結束時,發(fā)起購買交易參與游戲,如果能幸運地在最后一刻被礦工打包入塊,即可獲勝。
普通人在游戲快結束時都是類似的策略:緊盯著時間,調(diào)高 Gas 費用,發(fā)起參與游戲的交易,然后閉上眼睛祈禱,希望自己能是最后一個參與者。然而,采用這種方法幾乎不可能中獎。
據(jù)安比(SECBIT)實驗室分析,F(xiàn)omo3D 前兩輪獲獎者使用手法如出一轍,均在游戲快結束時,發(fā)起攻擊交易。
獲獎者(黑客)通過提前部署好的攻擊合約,在合約內(nèi)調(diào)用 getCurrentRoundInfo() 接口查詢游戲信息,重點關注剩余時間和最后一位購買者地址。當游戲剩余時間達到一個閾值,并且最后一個購買者是自己時,則通過 assert() 讓整個交易失敗,并耗光所有 Gas;當剩余時間很長或最后一個購買者不是自己時,則不做任何操作,僅消耗很少的 Gas。
獲獎者(黑客)就是利用這種方法,發(fā)起大量類似的可變神秘交易:在自己極有可能成為中獎者時,利用這些高額手續(xù)費的神秘交易,吸引礦池優(yōu)先打包,占滿后續(xù)區(qū)塊,從而使得其他玩家購買 key 的交易無法被正常打包,最終加速游戲結束,并極大地提高自己的中獎概率。
普通玩家只能在游戲快結束時手動調(diào)高 Gas 費用參與游戲,也有人試圖使用自動腳本在臨近游戲結束時調(diào)高 Gas Price 發(fā)起參與游戲交易。與這些盲目的方法相比,黑客的攻擊手法顯然高明許多。
其實,這一問題不止會威脅類 Fomo3D 游戲。所有采用類似機制,即需要玩家搶在某個時間范圍內(nèi)完成某種競爭操作的智能合約,都會受此威脅。只要游戲獎勵足夠豐厚,攻擊回報遠大于投入,就會有人利用前文提到的方法來破壞游戲公平性。
要杜絕這一問題,安比(SECBIT)實驗室建議游戲開發(fā)者,從游戲機制入手,切斷游戲最終勝利(獲得某個巨額大獎)和倒計時結束(最后一個交易被打包)之間的必然聯(lián)系,從而使黑客的攻擊獲利概率和攻擊意愿都降到最低。
例如,我們可以修改游戲規(guī)則為:每輪游戲結束前最后一個購買道具的參與者有概率獲得最終大獎,并將此概率調(diào)整為一個較低的值,如 5 %。在倒計時結束但大獎因概率原因沒有正常開出的情況下,合約自動給游戲續(xù)一定時間。這樣一來,前面提到的堵塞區(qū)塊、阻止別人參與游戲的技巧,無法確保攻擊者一定能獲得最終大獎。而黑客持續(xù)進行"阻塞交易"攻擊需耗費大量 Gas 費用,成本會很高,最終會選擇放棄攻擊。
上面為示例代碼,其中 shouldRndEnd() 函數(shù)用來在倒計時結束后控制中獎概率,決定這一輪游戲是否真的結束。這里的概率同樣依賴"隨機數(shù)"不能被預測,具體實現(xiàn)原理與前文提到的空投概率控制代碼類似。
Fomo3D 最終獲勝者可以輕易攻擊成功的另一個原因是,游戲合約開放了一個完整的游戲進度信息查詢接口,并且普通賬戶和合約賬戶都可以任意調(diào)用查詢。這方便了黑客在攻擊合約內(nèi)實時查詢游戲狀態(tài),進而執(zhí)行不同策略來降低攻擊成本和提高命中率。
因此,針對 Fomo3D 游戲,還有另一個簡易的防范方法。對 getCurrentRoundInfo() 函數(shù)使用前文提到的安全版的 isHuman() 校驗來保護,就可以有效避免合約自動化攻擊。
有安全和公平性問題的 Fomo3D 原版以及山寨版,僅是"黑客"掘金的對象,注定無法吸引更多普通玩家參加。隨著一輪一輪的進行,玩家會逐漸流失,這些游戲會進一步?jīng)]落。
安比(SECBIT)實驗室呼吁后來者吸取教訓,不要再原封不動地復制代碼,不要試圖僅靠"運營"來吸引新人入場。作出一些小小的改變,智能合約的安全性會得到很大的提升,去中心化游戲才能走得更遠。
· [1] Fomo3D二輪大獎開出,黑客獲獎,機制漏洞成游戲沒落主因,
https://zhuanlan.zhihu.com/p/45330743, 2018/09/25
· [2] 智能合約史上最大規(guī)模攻擊手法曝光,盤點黑客團伙作案細節(jié),
https://zhuanlan.zhihu.com/p/42318584, 2018/08/17
· [3] Fomo3D 千萬大獎獲得者"特殊攻擊技巧"最全揭露,
https://zhuanlan.zhihu.com/p/42742004, 2018/08/23
· [4] How to PWN FoMo3D, a beginners guide, https://www.reddit.com/r/ethereum/comments/916xni/howtopwnfomo3dabeginnersguide, 2018/07/23
· [5] Using EVM assembly to get the address' code size, https://ethereum.stackexchange.com/questions/14015/using-evm-assembly-to-get-the-address-code-size, 2017/04/07
· [6] Predicting Random Numbers in Ethereum Smart Contracts, https://blog.positive.com/predicting-random-numbers-in-ethereum-smart-contracts-e5358c6b8620, 2018/02/01
· [7] Random Number Generation on Winsome.io — Future Blockhashes, https://blog.winsome.io/random-number-generation-on-winsome-io-future-blockhashes-fe44b1c61d35, 2017/05/07
· [8] Gods Unchained, https://etherscan.io/address/0x482cf6a9d6b23452c81d4d0f0f139c1414963f89#code, 2018/07/16
熱門資訊
探討游戲引擎的文章,介紹了10款游戲引擎及其代表作品,涵蓋了RAGE Engine、Naughty Dog Game Engine、The Dead Engine、Cry Engine、Avalanche Engine、Anvil Engine、IW Engine、Frostbite Engine、Creation引擎、Unreal Engine等引擎。借此分析引出了游戲設計領域和數(shù)字藝術教育的重要性,歡迎點擊咨詢報名。
2. 手機游戲如何開發(fā)(如何制作傳奇手游,都需要準備些什么?)
?如何制作傳奇手游,都需要準備些什么?提到傳奇手游相信大家都不陌生,他是許多80、90后的回憶;從起初的端游到現(xiàn)在的手游,說明時代在進步游戲在更新,更趨于方便化移動化。而如果我們想要制作一款傳奇手游的
3. B站視頻剪輯軟件「必剪」:免費、炫酷特效,小白必備工具
B站視頻剪輯軟件「必剪」,完全免費、一鍵制作炫酷特效,適合新手小白??靵碓囋嚕?/span>
游戲中玩家將面臨武俠人生的掙扎抉擇,戰(zhàn)或降?殺或放?每個抉定都將觸發(fā)更多愛恨糾葛的精彩奇遇。《天命奇御》具有多線劇情多結局,不限主線發(fā)展,高自由...
5. Bigtime加密游戲經(jīng)濟體系揭秘,不同玩家角色的經(jīng)濟活動
Bigtime加密游戲經(jīng)濟模型分析,探討游戲經(jīng)濟特點,幫助玩家更全面了解這款GameFi產(chǎn)品。
6. 3D動畫軟件你知道幾個?3ds Max、Blender、Maya、Houdini大比拼
當提到3D動畫軟件或動畫工具時,指的是數(shù)字內(nèi)容創(chuàng)建工具。它是用于造型、建模以及繪制3D美術動畫的軟件程序。但是,在3D動畫軟件中還包含了其他類型的...
7. 3D動漫建模全過程,不是一般人能學的會的,會的多不是人?
步驟01:面部,頸部,身體在一起這次我不準備設計圖片,我從雕刻進入。這一次,它將是一種純粹關注建模而非整體繪畫的形式。像往常一樣,我從Sphere創(chuàng)建它...
8. 如何自己開發(fā)一款游戲(游戲開發(fā)入門必看:五大獨立游戲開發(fā)技巧)
?游戲開發(fā)入門必看:五大獨立游戲開發(fā)技巧無論您是剛剛起步開發(fā)自己的第一款游戲,還是已經(jīng)制作了幾款游戲,本篇文章中的5大獨立游戲開發(fā)技巧都可以幫助您更好地設計下一款游戲。無論你對游戲有著什么樣的概念,都
?三昧動漫對于著名ARPG游戲《巫師》系列,最近CD Projekt 的高層回應并不會推出《巫師4》。因為《巫師》系列在策劃的時候一直定位在“三部曲”的故事框架,所以在游戲的出品上不可能出現(xiàn)《巫師4》
想讓你的3D打印模型更堅固?不妨嘗試一下Cura參數(shù)設置和設計技巧,讓你輕松掌握!
同學您好!