类Fomo3D游戏漏洞与修复方案全解析(FOMO3D)
今天给各位分享类Fomo3D游戏漏洞与修复方案全解析的信息,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!
摘要无论是 Fomo3D 山寨版还是正宗原版都摆脱不了“一轮就凉凉”的宿命,这与其智能合约的设计漏洞不无关系。
本文从合约安全开发的角度出发,详细分析了类 Fomo3D 游戏的两个问题,并提出若干个可能的解决方案。
希望能有所帮助,欢迎感兴趣的朋友加入技术社区讨论。
Part1黑客攻击之下,类 Fomo3D 游戏一蹶不振Fomo3D 游戏已正式进入第三轮。
截止北京时间 9 月 29 日上午 11 点整,本轮奖池仅累积了 97.8988 Ether,外加上一轮滚入的 680 Ether,奖池总金额不足 800 Ether,相较前两轮的盛况,可谓惨不忍睹。
安比(SECBIT)实验室曾经撰文分析了类 Fomo3D 游戏的衰败现状,先来简单回顾一下 [1]。
图一:Fomo3D 玩家参与度与入场资金状况上图展示了「Fomo3D 玩家参与度与入场资金状况」。
红色代表调用合约参与游戏的人次,蓝色则代表进入游戏合约的资金量。
图左侧出现数据曲线最高峰,对应时间分别是 7 月 20 日和 7 月 21 日。
这两天恰好大量媒体疯狂报道 Fomo3D 这一现象级游戏。
当时众多玩家跟风入场,游戏合约的参与次数和入场资金均达到了最高峰,入场资金量超过 40,000 Ether,而参与次数最高超过 18,000 次。
高峰过后,Fomo3D 游戏热度骤降,于 8 月 22 日前后结束第一轮,并随即进入第二轮,但游戏热度已然无法恢复。
尽管如此,黑客却没有停止攻击。
图二:Fomo3D 游戏合约被攻击状况上图是「Fomo3D 游戏合约被攻击状况」,第一轮游戏高峰前后以及第二轮开始后,有黑客疯狂地利用“空投漏洞”进行攻击,攫取高额收益 [2]。
而在第一轮临近结束,以及第二轮倒计时快结束之际,则有黑客疯狂尝试“阻塞交易”攻击,企图夺取最终大奖 [3]。
不仅仅是 Fomo3D 原版游戏,其他众多的类 Fomo3D 山寨游戏,也成为黑客的攻击目标。
Fomo3D 类游戏参与形式是用 Ether 购买游戏道具,最后一位购买者获得“最终大奖”,平时参与者有一定概率获得“空投奖励”,分别从主奖池和副奖池中获取。
这两类奖励是游戏设计层面对参与者的重要激励。
这一设计,目的在于利用“随机”和“竞争”提升游戏趣味度,吸引更多人投入资金参与,从而延长游戏时间。
然而事与愿违,由于合约代码存在漏洞,掌握攻击技巧的黑客能够以很高的概率持续获得“空投奖励”,而“最终大奖”也会被黑客利用特殊技巧夺走。
普通参与者在这类游戏中几乎无法获得这两种重要奖励。
因此,他们仅能幻想在每轮游戏开始后第一时间入场,然后靠后续他人的资金回本。
但是,游戏最重要的两个激励机制已然失效,无法持续吸引新资金,最终形成恶性循环。
黑客是如何利用这两个漏洞的?项目方难道就无计可施吗?Part2空投漏洞分析先看看“空投奖励”。
所有投入游戏的 Ether,会有 1% 数量进到副奖池。
空投的概率从 0% 开始,每增加一笔不小于 0.1 ETH 销售订单,空投概率会增加 0.1%。
同时空投奖励金额与购买金额也挂钩,如果购买 0.1 ~ 1 ETH,就有概率赢得 25% 副奖池奖金,购买越多则比例越大。
游戏界面会鲜明显示当前中奖概率和奖池金额。
Fomo3D 空投奖励实现存在两处问题:合约中的“随机数”可被预测判断调用者是否是合约地址的方法有漏洞空投奖励依靠智能合约内生成的“随机数”,在 Fomo3D 源码中由airdrop()函数控制。
/***@devgeneratesarandomnumberbetween0-99andcheckstoseeifthats*resultedinanairdropwin*@returndowehaveawinner?*/functionairdrop()privateviewreturns(bool){uint256seed=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);elsereturn(false);}airdrop()函数中的“随机数”seed由各种区块信息和交易发起者地址计算得来。
这显然十分容易预测 [4]。
为了防止合约自动化攻击,Fomo3D 开发者还使用isHuman()来防止合约账户参与 Fomo3D 游戏,试图以此方法来禁止玩家在合约内预测中奖随机数。
/***@devpreventscontractsfrominteractingwithfomo3d*/modifierisHuman(){address_addr=msg.sender;uint256_codeLength;assembly{_codeLength:=extcodesize(_addr)}require(_codeLength==0,"sorryhumansonly");_;}这里犯了另一个常见错误。
extcodesize操作符用来获取目标地址上的代码大小。
对于已部署成功的合约,由于其地址对应着特定代码,extcodesize的返回值始终大于 0。
因此不少人用此方法来判断目标地址是否是合约,Fomo3D 甚至以此为依据来阻止合约调用特定函数。
但该判断方法存在明显漏洞,在构造新合约的过程中(即合约构造方法里)调用游戏参与函数即可绕过该限制。
这是因为合约在构造过程中,其地址并未对应任何代码,extcodesize的返回值为 0 [5]。
上述的两个安全问题综合作用,最终导致黑客可以构造攻击合约,通过合约参与游戏,随意预测随机数,进而极大提高自己的胜率 [2]。
Part3如何修改空投漏洞那么究竟如何解决 Fomo3D 的“空投漏洞”?黑客能够成功攻击,是利用了上文列出的两个漏洞,构造攻击合约来预测游戏合约中的“随机数”。
因此,我们只需完成以下两件事之一,使攻击所需的必要条件不满足即可:防止智能合约中的“随机数”预测采取更安全的方式判断调用者是否是合约方案一防范智能合约中的“随机数”预测让我们先解决“随机数”预测的问题。
智能合约环境内“随机数”容易被预测的原因在于,“随机数”产生所依赖的“随机源”可以被任何人轻易获得。
攻击者可以构造一个攻击合约,在相同环境内执行“随机数”计算公式,即可得到需要的“随机数”,并以之作为下一步行动的判断依据。
智能合约内几乎一切可用变量都是公开的,并且“随机数”计算公式需要确保所有节点执行结果都一致。
本文到此结束,希望能给网友您带来不错的体验。