1. 首页
  2. 深度

EOS中的“钞级骗局”:伪EOS及其变种攻击

DApp假币鱼目混珠,转账函数检测疏漏马虎

说起今年比较卖座的国产电影,周润发的《无双》肯定占有一席之地,电影中美元假钞的制造技术让人惊叹,也演绎了一段残酷的“钞级骗局”。

图片1

钞票不够用,就想到自己制造印刷,以假乱真,但是像影片中那种精湛的技艺确实还是很少的。在利益面前,任何一种货币都有被伪造的风险。对于EOS也不例外,本期我们就来说说由伪EOS攻击引出的相关漏洞及其变体。

基础知识铺垫

EOS智能合约的架构

EOS智能合约是由一系列action组成的,每个action代表一条合约条款,以实现条款中的具体规则。执行一个EOS智能合约分为制作、部署、调用三个部分。

其中,在部署智能合约这一步,每个EOS智能合约必须实现一个apply()函数,作用是将action请求映射到具体的处理函数。具体的实现细节封装在EOSIO_ABI宏里面。这样的设计让开发者只需要专注业务逻辑的开发,而不必关注底层技术,起到简化开发的作用。apply函数示例:

图片2

 

伪EOS转账攻击

历史事件:

大名鼎鼎的EOSBet在9月12日损失约42,000 EOS,开始了黑客使用伪EOS token攻击的热潮,接下来就是eoswindice和去中心化交易所newdex,都沦落为黑客的“鱼肉”。

攻击分析:

在EOS链上通用代币为EOS token,EOS token是由EOSIO部署的eosio.token合约生成的,但是eosio.token代码是开源的,任何eos账户都可以自己部署eosio.token合约,并且发行缩写名为EOS的token,如图我们可以看到大量无价值的伪EOS:

图片3

如何鉴别真伪EOS呢?验钞机吗?当然不用, eosflare浏览器上会显示token的全名,真EOS和假EOS全名是有区别的:

图片4

图片5

从图中可以看到 一个是EOS且后面没有其他说明,另一个是refundwallet伪造的EOS (refundwallet)。

在浏览器中,我们可以看到交易细节来判断用来交易的EOS token是真是假,那么如果放在智能合约中呢?

比如案例合约:

void transfer(const account_name& from,

const account_name& to,

const asset& quantity,

const string& memo)`

这是一个用来接收回调的函数,在被传递假EOS时,函数是没有办法分辨真伪的。如果没有提前在apply中检测EOS真假,就会导致合约接收了假的EOS也会执行正常业务逻辑。如果恶意账户自己部署合约发布一个EOS token,就可以实现空手套白狼,用假钞换真钱。

漏洞修复:

为了验证EOS的发行方为eosio,需要在apply()中添加code == eosio.token进行判定。

还有一种修复方法,开发者可以使用extended_asset类型接收asset 然后调用其中的contract可以获取到token的合约信息,extended_asset quantity然后可以对quantity.contract验证。

变体1:对transfer函数的直接调用攻击

漏洞分析:

按照上述漏洞修复手段添加相关判定后,许多项目方长吁了一口气,但是引发EOSBet事件的漏洞代码并没有那么简单就被修复。因为,在使用上述的apply对code调用进行检测时,还存在另一种绕过的情况,检测条件如果只为:

if( code == self || code==N(eosio.token) ||action == N(onerror))

那么这个检测条件只处理两个检测:函数自身action的调用和来自eosio.token的action的调用,没有校验transfer action的调用方必须是eosio.token或自己的合约。

这样就会导致可以直接调用合约账户下的transfer。

比如,原本是用户A调用eosio.token给用户B转1 EOS,然后eosio.token发送trasfer回执调用到B合约transfer函数执行业务逻辑,现在的话就可以直接调用B合约的transfer函数,里面指定from,to,value等正确的参数,不通过转账直接执行到B合约的业务逻辑。所以进攻EOSBet的攻击者完全绕过eosio.token->transfer函数,直接以正确的参数调用eosbetdice11->transfer,在不将EOS转移到合约的情况下执行了合约的业务逻辑。

漏洞修复:

对于这一类攻击的防御方式主要是同时对action和code做检测,即当

(code == N(eosio.token) && action == N(transfer)时才执行transfer函数。形式如下图:

if (code == N(eosio.token) && action == N(transfer))

{                                                                                }

变体2 EOS假回执攻击

历史事件:

在9月14日的事件之后,EOSBet还发过官方声明提到他们对代码安全的重视程度。

图片6

但是就在一个月之后,10月15日,EOSBet又被黑客攻击,损失近14万EOS。

漏洞分析:

漏洞原因是智能合约处理逻辑的transfer函数内缺少对to的判断:如果缺少to判断,合约无法判断收到转账的是不是自己,可能在没有收到转账的情况下继续执行逻辑功能,假设攻击者拥有AB两个账户,c是游戏合约账户,攻击者可以通过A账户调用eosio.token转账EOS到B账户,然后在A或B账户部署合约,在回调transfer中再调用一次require_recipient(N(XXXXXX));将转账通知发送到游戏合约C账户,这样就可以绕过code==N(eosio.token)&&action==transfer的校验,执行相应的业务逻辑。

漏洞修复:

void transfer(const account_name& from,

const account_name& to,

const asset& quantity,

const string& memo) {

if (from == _self || to != _self) {//不能缺少to != _self判断

return;

}

代码安全非黑即白

受到攻击的游戏官方经过一系列的安全事件、代码修复才最终解决了一个看似很匪夷所思的漏洞。可以看出,区块链安全是一个异常严谨、值得考究的技术,近两年的磕磕碰碰又让它成为了一个非常沉重的话题。《无双》中有句台词,“只看到黑跟白的人,永远都是失败者。”这句话在区块链领域并不适用,不信你看电影主角的结局。

区块链项目需要做到代码层面上的逻辑严密,设计精巧。区块链安全规范和相关知识也需要理解透彻,融会贯通,在细节问题上的把握也异常重要,尤其是对于起步不久的EOS、Fabric等新平台,所以可以说区块链技术在代码安全方面非黑即白,做到安全开发、安全审计、安全部署,才能让攻击者、投机者无从下手。

图片7

 

引用:

[1]: 假EOS攻击再升级:EOSCast遭黑客“假EOS转账变种”攻击,损失超6万EOS https://www.huoxing24.com/newsdetail/20181101120201461288

[2]: BET被黑客攻击始末,实锤还原作案现场和攻击手段https://bihu.com/article/1358201

[3]: 震惊!EOSBet又被攻击了。损失高达500万。攻击手法竟是这样?https://bihu.com/article/1558677

[4]: How EOSBET attacked by aabbccddeefg https://www.reddit.com/r/eos/comments/9fpcik/how_eosbet_attacked_by_aabbccddeefg/

[5]: EOSBet Transfer Hack Statement

https://medium.com/@eosbetcasino/eosbet-transfer-hack-statement-31a3be4f5dcf

【链虎财经版权及免责声明】本文转载自成都链安科技,经授权后发布,本文仅代表作者本人观点,与链虎财经立场无关,如涉及言论、版权等问题,请原作者及时联系我们,我们将尽快处理。本站所有内容不构成投资建议,币市有风险、投资请慎重。

QR code