8 月 22 日,一个名不见经传的游戏 God.Game 发出通告,声称遭遇黑客攻击,游戏内的以太币被黑客全部转走。这一消息一时间传遍各大媒体以及讨论群,人们在质疑相关游戏安全性之余,也在揣测项目方动机,一时间难以分清到底是黑客攻击,还是游戏开发方留有后门跑路。

安比(SECBIT)实验室的小伙伴在得到消息后,迅速开展了追踪分析。

God.Game 简单规则如下:GOD 股份购买的所有数量的 10% 被征税并且作为被动的 ETH 收入分配给所有GOD所有者。

通过游戏官网规则,以及合约源码分析,不少人会认为 God.Game 是 PoWH3D 的直接仿品,安比(SECBIT)实验室仔细分析后发现,它其实是综合“借鉴” PoWH3D 和 Zethr 的混合仿品。

PoWH3D 是最近大热的 Fomo3D 游戏团队上一款作品。而 Zethr 则是在 PoWH3D 基础上进一步开发优化,新增不同玩法的另一款热门游戏。二者在玩法规则层面的细节差别,这里不做讨论。

God.Game 游戏漏洞本身不复杂,不少安全公司也发出相关攻击手法的短篇快讯消息,部分不够详尽,安比(SECBIT)实验室通过本文全面分析该漏洞,重点分享漏洞追踪和定位的详细过程与大家讨论交流。

疑点一:攻击是无意还是刻意

一下子提走合约内所有以太币的人,是参与游戏过程中无意发现了漏洞,还是刻意进行的操作?

安比(SECBIT)实验室认为是后者,因为分析下来,该漏洞虽然隐藏不是很深,但实际触发需要一系列组合操作(类似玩游戏按上上下下左左右右开启作弊),正常游戏玩家的普通参与几乎不可能触发漏洞。安比(SECBIT)实验室分析攻击者的交易记录,发现其手段十分娴熟,目的性极强,明显是奔着该漏洞而来。

疑点二:攻击者的时机选择

攻击者为什么恰好选择在奖池金额 243 个以太币时发动攻击?

上面是游戏合约账户余额趋势图,横坐标是区块高度,纵坐标是 God.Game 合约账户余额。此图可反映随着时间推进,入场资金情况。安比(SECBIT)实验室发现,God.Game 合约部署上线后,合约资金量长期一直在 50 以太币以下,但在 6179500 区块高度以后,入场资金开始猛增到接近 260 个以太币(大量韭菜入场),随后略有衰退(一部分人选择提现退出),进入一段很长的调整停滞期。

无论是 Fomo3D 还是 PoWH3D,这类庞氏游戏最早期入场资金优势都很大,可以较快速回本。后续只有在持续大规模地运营宣传下,才可能有大量新资金入场参与游戏。因此游戏第一时间内的入场资金,基本决定了游戏资金量的总体规模。

而攻击者正是在资金规模就快回升到前期高点时,果断出击,利用漏洞果断提走游戏内的所有以太币。于是形成了上图类似“高台跳水”的有趣情景。

这蹊跷的手法、这迷人的走势是不是有些眼熟?

疑点三:是漏洞还是后门

到底是无意引入的漏洞还是刻意暗留的后门?

前面提到,God.Game 游戏代码重度参考了 PoWH3D 和 Zethr。而与漏洞相关的关键函数名 transferFromInternal() 只在 Zethr 合约代码中有出现。


上图所示问题代码,“创新”地增加了一组关于转账双方是合约、还是普通账户的分支情况处理。面对这一串冗长的代码,只要清楚 PoWH3D 工作原理,就很容易能发现此处代码逻辑根本说不通,也无法在游戏实际规则中找到适配点。并且这种根据账户类型分别处理账本的逻辑在原版 PoWH3D 和 Zethr 中根本没有出现。

God.Game 代码此处函数命名仿照了 Zethr,但是具体变量名却是仿造 Fomo3D,代码风格十分诡异。可以推断以下两种情况:代码作者有可能是因为没有理解 PoWH3D 游戏机制引入了漏洞;也有可能是故意增加代码混乱度来迷惑他人,以达到埋藏后门之目的。

特别地,安比(SECBIT)实验室还发现同样是 transferFromInternal() 函数,God.Game 代码中唯一与 Zethr 相近的地方,就是上图示例中针对 ERC223 代码做的回落处理,似乎是想通过引入此段代码(需要判断目标地址是否是合约)来为前面提到的不合逻辑代码打掩护。

异常:飙升的 Token 售价

下面让我们进入安比(SECBIT)实验室安全研究员 sha3 的第一视角,让 TA 为你拨开漫漫迷雾找出漏洞。

Good Luck Have Fun.

我们首先进入游戏首页,发现单个God token的售价已经飙升至300ETH,而被God.Game抄袭的火爆原版游戏PoWH3D的单价才0.02ETH,面对不寻常的数值,敏感的安比(SECBIT)实验室小伙伴首先怀疑该游戏合约可能存在整数溢出漏洞。

为了考证我们的想法,我们想到了回溯God.Game过往的售价变化过程(感谢区块链技术,让我们无法消灭历史),寻找在何处触发了整数溢出漏洞。

通过遍历区块历史数据,发现在6182409高度时,buyPrice/sellPrice等数据飙升,于是我们便仔细分析该区块中和God.Game相关的交易。

分析发现,在6182409区块中,唯一和God.Game产生关联的交易是0x368688a944059fdd657e7842d8762b05250bd45f3a2a16cbae1b29727023b00f

在该交易中,0x2368Beb4调用0x7f325EfC的reinvest()后,继而调用了0xca6378fc中的reinvest(),(通过简单的逆向分析,我们暂时认为0x7f325EfC是一个简单的代理合约,实现了God.Game游戏的基本接口)。

一番操作:定位到攻击源

我们不禁问道,为何调用一次reinvest()就可以将游戏中的各个数据全部暴增,我们怀疑创建这个合约的账户就是攻击者。

顺着这条线索,我们观察到这个合约的创建者,即0x2368Beb4,在6182409高度之前通过合约0x7f325EfC进行了另外几次操作。

具体操作历史如下:

区块高度 From To call
6182399 0x2368Beb4 0xca6378fc transfer(address,uint256)
6182399 0xca6378fc 0x7f325EfC tokenFallback(address,uint256,bytes)
6182403 0x2368Beb4 0x7f325EfC withdraw() 3ccfd60b
6182403 0x7f325EfC 0xca6378fc withdraw() 3ccfd60b
6182403 0xca6378fc 0x7f325EfC
6182406 0x2368Beb4 0x7f325EfC transfer(address,uint256)
6182406 0x7f325EfC 0xca6378fc transfer(address,uint256)
6182409 0x2368Beb4 0x7f325EfC reinvest() fdb5a03e
6182409 0x7f325EfC 0xca6378fc reinvest() fdb5a03e
6182419 0x2368Beb4 0x7f325EfC sell(uint256)
6182419 0x7f325EfC 0xca6378fc sell(uint256)
6182439 0x2368Beb4 0x7f325EfC transfer(address,uint256)
6182439 0x7f325EfC 0xca6378fc transfer(address,uint256)
6182462 0x2368Beb4 0x7f325EfC transfer(address,uint256)
6182462 0x7f325EfC 0xca6378fc transfer(address,uint256)

再看看reinvest()函数调用时产生的event。

我们看到了0000000000000000fffffffffffffffffffffffffffffffffffcf2ac578ec8d9这个极像溢出的值。

随即我们打开God.Game源代码,搜寻其中的蛛丝马迹。

我们将目标锁定到reinvest()函数。

function reinvest()
onlyProfitsHolders()
public
{// fetch dividendsuint256 _dividends = myDividends(false);// retrieve ref. bonus later in the code// pay out the dividends virtuallyaddress _customerAddress = msg.sender;payoutsTo_[_customerAddress] += (int256) (_dividends * magnitude);// retrieve ref. bonus_dividends += referralBalance_[_customerAddress];referralBalance_[_customerAddress] = 0;// dispatch a buy order with the virtualized "withdrawn dividends"uint256 _tokens = purchaseTokens(_dividends, 0x0);// fire eventemit onReinvestment(_customerAddress, _dividends, _tokens);
}

首先大概浏览一下reinvest()函数主体,仅有两个简单的加法,但是通常在减法溢出中会出现巨型整数,我们便开始探索reinvest()调用的函数。

首先引起我们注意的便是myDividends(false)函数,由于参数传入了false,我们就直接研究它最终调用的函数dividendsOf(_customerAddress)

function dividendsOf(address _customerAddress)
view
public
returns (uint256)
{return (uint256) ((int256)(profitPerShare_ * tokenBalanceLedger_[_customerAddress]) - payoutsTo_[_customerAddress]) / magnitude;
}

Aha,看到减法了!

会不会就是在这里发生了溢出呢?

历史回放:精确找到溢出点

带着这样的疑问,我们回溯了0x368688a944059fdd657e7842d8762b05250bd45f3a2a16cbae1b29727023b00f这笔交易的trace,我们跟着静态分析结果,直接在trace中将PC指针定位到了dividendsOf函数中。

发现在0x0a8c指针处执行了sub指令,并且sub指令在栈上的两个参数分别为0和0x30d53a87137270000000000000000减法、除法执行完毕后栈顶变成了0xfffffffffffffffffffffffffffffffffffcf2ac578ec8d9,和event中的值完全相同。

果然,我们找到了发生溢出的地方,并且确定reinvest()函数使用了溢出后的值。

顺藤摸瓜:推理怎么构造溢出条件

那么问题来了,我们有什么办法能让这个减法溢出呢?

回想sub指令的参数:

  • 第一个参数 0 对应 profitPerShare_ * tokenBalanceLedger_[_customerAddress]
  • 第二个参数 0x30d53a87137270000000000000000 对应 payoutsTo_[_customerAddress]

思路来了,我们需要达成2个目标

  1. 使得 profitPerShare_ * tokenBalanceLedger_[_customerAddress]的计算结果为0,
  2. 使得 payoutsTo_[_customerAddress]中存储的值为正数

首先我们看目标1,对于profitPerShare_变量,纵观全部代码,只有增加没有减,无法有效地将这个值变为0,那么只有tokenBalanceLedger_[_customerAddress]才能给我们修改的机会。

然后目光看向目标2payoutsTo_[_customerAddress]必须设置为正值。

我们看到在transferFromInternal()withdraw()函数均中对该值有操作,不由得想到了上文看到攻击者的4步组合拳,这4步具体发生的操作如下:

  1. transfer (攻击者调用God.Game合约的transfer函数将token转移到到攻击者创建的合约)
  2. withdraw (攻击者调用代理合约的withdraw函数,代理合约调用God.Game的withdraw函数讲ETH提入代理合约)
  3. transfer (攻击者调用代理合约的transfer函数,将God.Game中代理合约的token转移到攻击者账户)
  4. reinvest (攻击者调用代理合约的reinvest函数,代理合约调用God.Game的reinvest函数触发溢出)

谜底揭开:漂亮的组合拳

我们不妨看看在God.Game合约中发生了什么?

攻击者第1步:从自己账户转移token到合约,触发transferFromInternal函数中的第一个else if分支:

else if (fromLength <= 0 && toLength > 0) {// human to contractcontractAddresses[_toAddress] = true;contractPayout += (int) (_amountOfTokens);tokenSupply_ = SafeMath.sub(tokenSupply_, _amountOfTokens);payoutsTo_[_from] -= (int256) (profitPerShare_ * _amountOfTokens);
}

攻击者将自身的payoutsTo_[_customerAddress]被减为负数,紧接着修改`tokenBalanceLedger_[from/to]进行普通的token转账操作,给代理合约一些token以便拥有dividens。

攻击者第2步:代理调用withdraw()payoutsTo_[_customerAddress]值增加。

攻击者第3步:将代理合约的token转移到攻击者账户,触发transferFromInternal中的if分支:

if (fromLength > 0 && toLength <= 0) {// contract to humancontractAddresses[_from] = true;contractPayout -= (int) (_amountOfTokens);tokenSupply_ = SafeMath.add(tokenSupply_, _amountOfTokens);payoutsTo_[_toAddress] += (int256) (profitPerShare_ * _amountOfTokens);
}

攻击者的payoutsTo_[_customerAddress]值增加,同时将代理合约中的token全部转移到攻击账户中。

可以看到,这3步组合让代理合约满足了减法溢出所需条件:

  1. 通过第1、第3两步将代理合约的tokenBalanceLedger_[_customerAddress]值为0
  2. 通过第2步将payoutsTo_[_customerAddress]值置为正数

攻击者第4步,猛烈一击,调用reinvest()触发dividendsOf()的减法溢出,攻击者获取巨量的dividens,将divisions转换为token。

由于token数量过多,合约储备金额不够withdraw(),攻击者便将部分token转移到0xC30E89DB73798E4CB3b204Be0a4C735c453E5C74,通过0xC30E89DB73798E4CB3b204Be0a4C735c453E5C74进行sell操作卖出token换取ETH,合约储备金面对巨量增发的token,瞬间消耗殆尽,攻击者成功提取了几乎所有的ETH。

Good Game.

God.Game 风波带来的思考

近来各类山寨版本智能合约游戏盛行,已经发生很多起安全事件,安比(SECBIT)实验室不久前已针对 Fomo3D 和 Last Winner 进行了一系列详细的漏洞披露和解析。而这次 God.Game 甚至上线不久就宣告被黑客攻击游戏结束,很多玩家的投入无法兑现,导致出现一些「游戏(投资)群」秒变「维权群」的闹剧。

安比(SECBIT)实验室提醒广大智能合约游戏爱好者,务必要擦亮双眼,提高安全意识,谨慎参与不明游戏(小心漏洞与后门),并且对于任何游戏都不要投入超出承受能力范围的资金。

游戏智能合约在一定程度上比一般 Token 合约更复杂,一些漏洞会隐藏得更深,触发条件更苛刻。很多游戏甚至会有更高层次的关于公平性、博弈机制的漏洞存在,需要从游戏模型设计、代码实现等各种角度进行安全评估。安比(SECBIT)实验室建议所有负责任的智能合约游戏开发商,都应该提高安全意识,加大安全投入。

参考文献

  • [1] God.Game 合约地址,https://etherscan.io/address/0xca6378fcdf24ef34b4062dda9f1862ea59bafd4d
  • [2] PowH3D (P3D) 合约地址,https://etherscan.io/address/0xb3775fb83f7d12a36e0475abdd1fca35c091efbe
  • [3] Zethr (ZTH) 合约地址,https://etherscan.io/address/0xD48B633045af65fF636F3c6edd744748351E020D
  • [4] BCSEC:GodGame漏洞原理以及黑客攻击手法分析,https://bcsec.org/index/detail/tag/2/id/252
  • [5] 安比实验室:Fomo3D 千万大奖获得者“特殊攻击技巧”最全揭露,https://mp.weixin.qq.com/s/MCuGJepXr_f18xrXZsImBQ
  • [6] 安比实验室:智能合约史上最大规模攻击手法曝光,盘点黑客团伙作案细节,https://mp.weixin.qq.com/s/YBG8YyPwh374HbGWcUKTdQ

以上数据均由安比(SECBIT)实验室提供,合作交流请联系info@secbit.io。


安比(SECBIT)实验室

安比(SECBIT)实验室专注于区块链与智能合约安全问题,全方位监控智能合约安全漏洞、提供专业合约安全审计服务,在智能合约安全技术上开展全方位深入研究,致力于参与共建共识、可信、有序的区块链经济体。

安比(SECBIT)实验室创始人郭宇,中国科学技术大学博士、耶鲁大学访问学者、曾任中科大副教授。专注于形式化证明与系统软件研究领域十余年,具有丰富的金融安全产品研发经验,是国内早期关注并研究比特币与区块链技术的科研人员之一。研究专长:区块链技术、形式化验证、程序语言理论、操作系统内核、计算机病毒。

God.Game 漏洞复盘:跑路还是黑客攻击?相关推荐

  1. 暴力拒绝白嫖,著名开源项目作者删库跑路!神秘Bug影响超2万个项目,亚马逊云也躺枪...

    [文章来源][公众号:新智元] "从GitHub上删除自己的代码是违反他们的服务条款的?WTF? 这是一种绑架行为." 这两天,一些开发者感觉有点懵-- 一觉醒来发现,自己程序跑出 ...

  2. 著名开源项目,神秘Bug影响超20000个项目,原因竟是作者删库跑路?

    热门资讯早知道,吃瓜唠嗑不冷场, 记得加个星标,第一时间获得推送 图文编辑:xj 来源:公众号「新智元」 "从GitHub上删除自己的代码是违反他们的服务条款的?WTF? 这是一种绑架行为. ...

  3. “删库跑路”重现江湖,技术和制度如何保障数据安全?

    摘要:近日,一则来自微盟官网的消息在业内引起轩然大波,"删库跑路"重现江湖--由此,关于如何从技术和制度两方面进行数据安全防范的关注和讨论广泛展开. 近日,一则来自微盟官网的消息在 ...

  4. 代码投毒、删库跑路,开源生态链安全该如何保证?

    [CSDN 编者按]这两天node-ipc作者往开源代码投毒一事引起热议,在此之前出现了Log4j2事件,与Marak Squires删库事件,一时间大家都议论纷纷.热议之后,我们不妨品读一下开源社理 ...

  5. 删库不跑路-详解MySQL备份策略

    原文链接:https://segmentfault.com/a/1190000019955399 手抖.写错条件.写错表名.错连生产库造成的误删库表和数据总有听说,那么删库之后除了跑路,还能做什么呢, ...

  6. GitHub 著名开源项目作者删库跑路,神秘 Bug 影响超 20000 个项目!

    点击上方"Java精选",选择"设为星标" 别问别人为什么,多问自己凭什么! 下方有惊喜留言必回,有问必答! 每天 08:15 更新文章,每天进步一点点... ...

  7. 程序员变高危职位!又一个删库跑路进去了

    上一篇:中国各城市首轮感染高峰期预测! 最近又有一个同行为了泄私愤,又删库跑路了.(我为什么要加个"又"?) 一提到「删库跑路」,大众肯定最新会想到程序员群体. 没错,我们手上握着 ...

  8. 暴力拒绝白嫖,开源项目作者直接删库跑路,这下大家都不要用了 !

    编辑:好困,转载自:新智元 [导读]程序突然乱码,开发者紧急「修复」!然而-- 这两天,一些开发者感觉有点懵-- 一觉醒来发现,自己程序跑出来的全都是「乱码」. 说起来,这些开发者的共同点就是都使用了 ...

  9. 暴力拒绝白嫖,著名开源项目作者删库跑路,数千个应用程序无限输出乱码

    往期热门文章: 1.两天两夜,1M图片优化到100kb! 2.12 个顶级 Bug 跟踪工具 3.1个人6种变现途径收入130万美金在2020年 4."阿里味" PUA 编程语言火 ...

最新文章

  1. 若依前后端分离如何写移动端接口_前后端分离实践的架构设计
  2. 重磅!2020年放假安排公布啦!五一休5天,国庆中秋连休8天
  3. “你要是有这个功能就好了!”
  4. Thymeleaf + Spring中的验证
  5. diabetes影响因子2017_Journal of Diabetes
  6. 怀俄明州议员Cynthia Lummis:加密监管需要为创新留有空间
  7. go语言和java比_python与java、php、go的优势对比,各语言不要引起恐慌哈
  8. opencv_找cv::Mat中的最大值和最小值
  9. AE插件:TV Distortion Bundle mac(画面像素破损信号干扰失真插件)支持ae2021(2.6.0)
  10. 手机直播app制作大揭秘之视频直播系统方案
  11. 人人商城小程序消息服务器配置,人人商城小程序订阅消息设置方法和几个坑!...
  12. Java HashMap底层原理解析
  13. 中国眼镜市场销售前景分析与运营效益研究报告2021-2026年
  14. sysbench--实践--02--CPU测试
  15. 请写一个java冒泡算法
  16. pyecharts源码解读(10)渲染包render之templates目录:渲染模板
  17. 389-MySQL数据库代码封装
  18. 2022生化原理I复习资料汇总
  19. vs2008编译QT开源项目--太阳神三国杀源码分析(四) 动画
  20. 远程控制软件– 向日葵使用教程

热门文章

  1. 专利申请成功后已超过4年,如何延长专利保护期?
  2. qq浏览器HTML5在哪,qq浏览器wifi助手功能在哪里?
  3. php中.=是什么意思,javascript中$符号是什么意思?
  4. Android双波浪自定义控件(DoubleWaveView)
  5. 玩转高并发,17年开发经验架构师,历时三年编写Java高并发三部曲
  6. 牛客算法笔记【second week】
  7. 2021-09-22 小米通信软开二面
  8. 《脱颖而出——成功网店经营之道》一2.2 进货攻略
  9. 《达利之梦》推出APP,带你走进VR超现实画作
  10. 触摸液晶屏技术原理及分类