小葱APP 8月11日讯,作者:殷耀平,转载请注明出处。
小葱APP新开原创专栏——「小葱话安全」。本栏目由小葱APP与安比(SECBIT)实验室联合出品,将为大家深度解读币圈与链圈各项重大安全事件,热点项目中的安全风险,新型骗术及防御手段,同时定期推出安全科普文章。
近日,一种新型蜜罐合约正在泛滥。这类合约利用区块链浏览器 Etherscan 显示特性,蓄意隐藏特定合约调用记录,布局欺骗游戏参与者。且该类蜜罐合约的设计者具有较强的技术积累并能很好把握玩家心理,针对目标多为具备一定区块链专业素养的人员。当前市场上的同类合约数已达48个,其中近一半合约已有玩家受骗。
出于好奇,我参与了一款猜答案游戏
Martin Derka是加拿大滑铁卢大学的一名博士,拥有10余年计算机软件相关的科研与工作经历,今年6月份,他加入了知名安全团队Quantstamp,现担任QSP高级软件研发工程师一职。
7月的一个周末,Martin Derka在家中闲来无事,便开始浏览区块链浏览器(Etherscan)上新增的ICO项目及游戏项目,其中一份名为QUESTION的合约勾起了他的兴趣,合约地址为0xcEA86636608BaCB632DfD1606A0dC1728b625387
这份合约写的是一个游戏,大致规则是:
合约创建者会设置一个问题;
任何玩家都可以通过向合约打入不低于1ETH的手续费参与作答;
若猜中答案,将得到合约里所有的ETH作为奖励;
若猜不中,无任何奖励,且事先支付的ETH会转入该合约
Martin Derka看到合约时,里面有1.03个ETH。
Martin Derka初次见到的QUESTION合约状态
一个以太币的金额不少,只需要回答一个问题就能到手?Martin Derka隐约觉得这个游戏有猫腻,于是他开始查看合约的构造逻辑。
一番浏览后,他发现合约的设计似乎存在很多不得当之处。例如,Solidity编译器版本老旧,标注不规范,合约方案设计既费力又浪费以太坊GAS,不过他把这些都视作以太坊“初学者的失误”。
“我的第一印象是,这份合约肯定是刚接触Solidity 和以太坊的初期开发者撰写的”Martin Derka事后回忆时表示。
他进一步分析代码,发现了更多疑点:
合约存在一些怪异、低效的构造;
合约想要隐藏一些私有的数据;
存在一些低级错误:玩家能通过在以太坊浏览器上查看交易记录准确破解出答案。
至此,Martin Derka基本确定这份合同是个骗局,合约中的以太坊余额大概是个诱饵,很大可能会让玩家损失其加入游戏时支付的ETH,因为他觉得这个合约的设计实在有太多无法解释的地方。
带着种种猜测与疑惑,Martin Derka加入了游戏,试图摸清骗局真相。
我十分谨慎,但我被骗了1.05个ETH
Martin Derka十分谨慎地留意合约创建者所进行的每一个动作:
首先合约创建者在5873826区块高度上通过一笔交易创建了一个智能合约;
其次,合约创建者启动游戏,将问题“Imagine you are swimming in the sea and a bunch of hungry sharks surround you. How do you get out alive?”和答案“Stop Imagining”以及1.03个ETH写入了高度为5873943的区块,1.03个ETH顺利打入其创建的智能合约;
除此之外Etherscan上未见到任何其他交易记录。
启动游戏的交易记录:包括问题和答案(答案是明文显示的)
Martin Derka首先对正确答案进行了判断。
QUESTION游戏中与设置问题和答案相关的接口只有两个(一个是启动游戏,一个是更新问题)。启动游戏接口只在最开始时调用才有效,一旦启动了下次再调就无效;更新问题接口要在游戏启动后才能调。游戏启动以后,若调用了更新问题接口,则最后一次更新设置的问题和答案才是游戏当前真正的问题和答案,若没有调用更新问题,则第一次启动游戏的时候设置的问题和答案就是正确的问题和答案。
从etherscan上的交易记录来看,该合约只调用了一次启动游戏,所以Martin Derka判断这条交易记录中记录的就是正确答案,而由于合约设计者的“失误”,答案是以明文传输的,交易记录中直接就能获取到。
Martin Derka随后转了一些ETH到自己的Metamask钱包账户里。
不过谨慎的Martin Derka第一次回答这个问题时没打ETH进合约,因为他想创建个交易验证一下,创建者提交的正确答案是不是能够被准确破解;如果是,SHA256应该产生相同结果;他调用合约方法并进行一番验证后,觉得没什么问题。
第二次,他将1.05个ETH连同正确答案一同提交参与作答,然后等待答题结果。
当他的交易被挖掘出来时,预料中的骗局出现了:游戏合约的余额增加到超过2.08个ETH,而Martin Derka钱包里的1.05个ETH不见了。
按照游戏规则,Martin Derka提交了正确答案、且事先支付了1.05个ETH,他理应赢得合约里所有以太坊余额的,但他却赔了。以太坊浏览器上也真实记录了他的1.05个ETH转入游戏合约的记录。
图中Etherscan记录的最近2笔交易正是Martin Derka创建的
一时间,Martin Derka 有点不相信自己的眼睛。他一直在检查代码和交易,丝毫没有放松过,但骗子就在他眼皮底下骗走了他的以太币。他开始重新梳理这个过程,交易的排序是正确的,代码也看不出任何蹊跷,他在本地部署了代码,并进行测试验证,一切都好像没什么问题。
而就在这时,游戏合约的余额突然降到了0,问题创建者终止了游戏,此时距离Martin Derka 答题结束大约1个小时。
我看到的一切,都只是对方想让我看到的
恰恰是合约创建者急忙提走2.08个ETH的这笔交易揭开了谜底。
Martin Derka注意到,合约余额(2.08ETH)并未被转移到某个钱包,而是被转入了另一个专用源码合约。并且他在交易历史中,发现有一笔指向游戏合约的内部交易并未被以太坊浏览器记录。
经过一番查证分析,他发现之前他所看到的并非全貌,其实游戏合约创建者实际的行动顺序是:
(1)合约创建者先创建了一份中间合约,合约地址为:
0x4B2838d9326bD5126F0573D9b5c71C0626Ab28f2
(2)合约创建者创建当前的游戏合约,合约地址为:
(3)合约创建者向中间合约发起一笔交易。这笔交易使得中间合约向游戏合约发起两次调用,这两次调用在 Etherscan 的交易历史中都不会显示,但可以在交易的Trace中查看到,两次调用及其参数皆可通过合约的 ABI 解码得出,从解码结果来看:
第一次是调用了 启动游戏接口,传入了问题和答案两个参数,其中问题为“Imagine you are swimming in the sea and a bunch of hungry sharks surround you. How do you get out alive? ”答案为“sZs”(明文显示的)。
第二次是调用了更新问题接口,更新了问题和答案,传入的问题与上一次调用时是一致的,而答案则是一串哈希值。
第一次调用详情
第二次调用详情
也就是说,在启动游戏并设置好问题和答案之后,合约创建者又迅速更改了一次问题和答案,而第二次调用时设置的答案才是问题的真正答案,但这笔交易记录被隐藏了。
(4)合约创建者又向游戏合约发起了一笔交易,调用启动游戏接口,传入问题“Imagine you are swimming in the sea and a bunch of hungry sharks surround you. How do you get out alive?”和答案“Stop Imagining”,而由于启动游戏只有第一次调用有效,本次调用实际上不会改变合约的任何状态,答案自然也不是正确答案。但设计者故意让玩家看到这笔交易记录。
因此Martin Derka将“Stop Imagining” 作为正确答案输入,结果必定错误。
“调查之后,我才发现这是一段精心编写的代码,他们只是在假装天真。”Martin Derka在事后的回忆文章中这样评价QUESTION合约,并表示“十分钦佩这份合约的设计”。
我们再简要回顾一下这个高明的骗局。
合约设计者抛出游戏规则并在合约中打入一定的ETH,吸引玩家缴费进场答题赚ETH;同时设局让玩家自认为能通过交易历史破解答案,然后不声不响地赚取ETH。而实际上是螳螂捕蝉、黄雀在后,合约创建者让你边窃喜边发现的答案并非真实答案,技术帝们凭借“机智”最终不仅赚不到合约中的ETH,还会赔光预先缴纳的手续费。
安全专家:已“缴获”48个同类蜜罐合约
上述玩法是典型的蜜罐合约,陷阱设计精巧娴熟,往往让人防不胜防,这不连QSP团队的安全大神Martin Derka也没能幸免。
“设计该类蜜罐合约需要一定的技术积累和对玩家心理的把握,而受骗者大部分都是具备一定专业知识的技术人员,且这些人员往往也更容易参与到DAPP游戏中”安比实验创始人郭宇向小葱表示。
“这类蜜罐合约就是这样,让玩家以为发现了游戏的漏洞,而实际上只是游戏设计者的圈套,我们调查统计了当前市场上的同类合约,发现这一诈骗手段屡试不爽”,他补充道。
据安比实验室智能合约风险监控平台显示,同类合约的数量已高达48个,最近的部署为3天前。其中,已有玩家受骗的合约逾21份,累计受骗金额超过 25 ETH。
以下是部分成功套取ETH的蜜罐合约地址:
小葱APP特此提醒各位DApp 游戏爱好者提高警惕,切勿参与到上述合约地址的游戏中,也不要参与各种安全性不明的游戏合约。
“该类蜜罐合约通常都在有玩家受骗后短时间内迅速结束套利,受骗群体较小,金额较少,不会造成大范围的影响,故而也比较容易被忽视”安比实验室安全专家p0n1告诉小葱。
不过,他提醒说“3天前还有一份刚部署的合约,目前尚无玩家受骗,可见这种诈骗手段还在继续。”合约地址是:0x3fAb284a3cD0A6d88d18D0fdA4bc1a76cdacd68A。
此外,p0n1指出,由于合约中终止游戏接口的实际功能是使问题提出者取走合约中所有 ETH,并不是真正终止合约。简言之,即使问题提出者成功套取利益,游戏也并未真正结束,玩家还是有继续掉入合约陷阱中的风险。
小葱小结
不得不感叹骗子水平的提升,不仅积极钻研代码技术,还懂得参悟人性心理。
不过除了惊讶于骗子的高明外,我们也应该看到,区块链浏览器作为一种工具,其产品特性存在着一定的针对性和局限性。本文QUESTION合约的设计者正是利用以太坊浏览器中部分交易记录不显示的特点成功欺骗玩家。
因此实际应用中,广大用户或开发者不能完全依赖于某一款区块链浏览器所提供的数据。当然,各类区块链浏览器网站也应在用户界面上作出改进,尽可能降低被利用风险以及由此导致的用户损失。
作为一个爆发式增长的领域,智能合约技术和应用的革新离不开大量涌入的专业人员的贡献,但这其中也不免掺杂了诸多不和谐的因素,诸如本文所提到的合约以及不久前爆出的另一种蜜罐合约。不过,也正因这些因素的存在,才促使行业不断寻找新的解决方案,促进技术和社区进步,整个过程需要包括安全团队在内的更多专业人士共同努力。
文末,附上安比实验室提供的QUESTION合约源码分析详情,对该合约的详细功能实现做了完美梳理,保证看完你也会写了。
游戏合约的设计:埋坑的基础实践
QUESTION合约的源码中包含5个接口:启动游戏,玩家猜答案,终止游戏,更新问题以及空的回落函数。
启动游戏
由问题提出者启动游戏(StartGame()),设置问题和答案,传入的答案以哈希的形式保存在合约中。而游戏启动仅第一次操作有效。
玩家猜答案
任何人都可调用Play() 接口,参与游戏猜答案,游戏玩家需支付 1 ETH 以上的费用(否则即使猜中也无奖励)。
若猜测错误,无法任何奖励,且事先支付的ETH会转入该合约。若猜测正确,将得到合约中所有的ETH作为奖励。
另外,问题发布者还具有两个权限:终止游戏和更新问题。
终止游戏
问题提出者有权终止游戏(StopGame()),但终止游戏并非将游戏彻底终结,而是由问题提出者转出合约中的所有 ETH ,但后续玩家依旧能继续参与游戏。也就是说,问题创建者能随时取走合约中所有的ETH。
更新问题
问题提出者可将问题和答案换掉(NewQuestion()),玩家后续针对新问题进行作答。
这是ERC 20 Token 中的经典问题——reApproval,依赖交易顺序的漏洞进行作恶。
一个玩家猜中答案,并发起一笔交易来提交正确答案时,该笔交易会等待被打包;
而同时,问题提出者也提交一笔交易来更改问题,若更改问题的交易先被矿工打包,则玩家即使先猜中了答案也拿不到奖励。
这里,虽然都是传入问题和答案,但StartGame() 和 NewQuestion() 接口传入的参数却有所区别。StartGame() 函数传入的第二个参数是问题答案的明文。然而,以太坊上接口调用的参数是可以查询到的。简单说,只要找到启动游戏的那笔交易,就能找到问题的答案。
当然,合约中那些特殊权限的隐患只是障眼法,其实套路才刚刚开始。接下来我们看看游戏陷阱是如何设置的。
蜜罐陷阱的实现:巧借 Etherscan 缺陷
由于 Etherscan 上仅涉及ETH转账或 Token 转账的交易,部分交易不会显示,合约创建者利用这一特性来隐藏设置答案的交易,将假的答案暴露在Etherscan 上。让聪明且有心者误以为发现了问题答案。
首先,合约创建者创建一份中间合约;
其次,合约创建者创建当前的游戏合约;
然后,合约创建者向中间合约发起一笔交易。这笔交易使得中间合约向游戏合约发起两次调用。但这两次调用在 Etherscan 的交易历史中都不会显示出来。我们可以在交易的Trace中查看到,两次调用及其参数又可以通过合约的 ABI解码得出。
从解码后结果来看,第一次是调用了StartGame() 接口,传入了问题“Imagine you are swimming in the sea and a bunch of hungry sharks surround you. How do you get out alive? ”和答案“sZs”。第二次调用了 NewQuestion() 接口,传入的问题与上一次调用一致,答案则是一串哈希。至此,游戏的真实问题和答案偷偷设置完成,第二次调用的参数中的答案才是问题真正答案。
最后,合约创建者又向游戏合约发起了一笔交易。调用StartGame() 接口,传入的问题与之前一致,答案正是Martin Derka看到的“Stop Imagining”。而由于启动游戏只有第一次调用有效,本次调用根本不会改变合约的任何状态,自然也不是问题的正确答案。
安比实验室在另一个区块链浏览器上进行查询,也证实了这一问题。
在Martin Derka转入1.05 个 ETH 到 QUESTION 合约不久后,合约创建者立刻就终止了合约,并取走合约中所有的ETH,至此游戏提出者成功得骗取ETH,一轮流程结束。
领取专属 10元无门槛券
私享最新 技术干货