区块链智能合约:ATN被增发?神特么的ERC223,神特么的custom_fallback!

今天看到了一则快讯蛮有意思

以太坊再现漏洞或使Token供应量增发
近日,黑客利用了一个ERC223合约与DS-AUTH库的混合漏洞,重设了owner权限,进行了ATN Token 的增发。ATN技术人员收到异常监控警示,介入后确定TOKEN合约受到黑客攻击并发现了相关漏洞,随后对漏洞进行了修复,并冻结了增发的Token。
另据慢雾区透露,ATN基金会将销毁1100万个ATN,并恢复ATN总量,同时将在主链上线映射时对黑客地址内的资产予以剔除,确保原固定总量不变。

这个漏洞蛮有意思哇!于是我搜了下原文想看看到底怎么回事,没想到是篇通稿= =
https://medium.com/@atnio/erc223-smart-contract-breach-and-resolution-vulnerability-relating-to-the-concurrent-9a402495f382
原文是英文的,除了大致介绍了漏洞的关键词,就在吹自己面对黑客的攻击如何临危不惧,如何跟著名的安全公司合作解决问题,帮助升级了不安全的ERC223标准。值得技术人员的留意的地方只有:

  1. 黑客通过一些手段窃取了ATN代币合约的控制权限
  2. 黑客使用控制权限增发了代币
  3. 黑客返还了控制权限,当作什么事情都没有发生
  4. 技术人员发现后暗不吭声,直到黑客想把增发的代币充值到交易所交易的时候立刻封锁了黑客的账户

这个“大致介绍”和“一些手段”真是耐人寻味……于是,轮到名侦探辰分出场啦!

黑客的攻击手段

原文里提供了个证明黑客想把增发的代币充值交易所的交易hash证明https://etherscan.io/tx/0x18bd80b810f6a6b6d397901d677657d39f8471069bcb7cfbf490c1946dfd617d ,多亏了这条链接,我准确定位到了黑客的攻击源地址是0x2eca25e9e19b31633db106341a1ba78accba7d0f
,在时间点May-11-2018 03:45:03 PM +UTC,这哥们实施了如下的交易攻击代码:

Function: transferFrom(address _from, address _to, uint256 _amount, bytes _data, string _custom_fallback)

MethodID: 0x4e2ab933
[0]:  0000000000000000000000002eca25e9e19b31633db106341a1ba78accba7d0f
[1]:  000000000000000000000000461733c17b0755ca5649b6db08b3e213fcf22546
[2]:  0000000000000000000000000000000000000000000000000000000000000000
[3]:  00000000000000000000000000000000000000000000000000000000000000a0
[4]:  00000000000000000000000000000000000000000000000000000000000000e0
[5]:  0000000000000000000000000000000000000000000000000000000000000000
[6]:  0000000000000000000000000000000000000000000000000000000000000000
[7]:  0000000000000000000000000000000000000000000000000000000000000011
[8]:  7365744f776e6572286164647265737329000000000000000000000000000000

如果对我之前的博文有所关注区块链智能合约:EVM封装bytes _extraData的一个BUG,那么看到这个就很容易得知黑客是通过封装一个看似合法的交易(transferFrom)对ATN合约进行权限改写的。我尝试把这个攻击交易复原成代码,得到了:

transferFrom("0x2eca25e9e19b31633db106341a1ba78accba7d0f",
             "0x461733c17b0755ca5649b6db08b3e213fcf22546",
              0,
             ["0x0"],
             "setOwner(address)")

看到setOwner这种危险词,是不是就开始感觉不妙了?黑客就是故意越权引发了setOwner(address)函数,把代币增发权拿到了自己手里!

攻击代码的执行流程

我们稍微把攻击代码翻译一下成为人的自然语言:请从帐号"0x2eca25e9e19b31633db106341a1ba78accba7d0f"转帐0个ATN代币到地址"0x461733c17b0755ca5649b6db08b3e213fcf22546",附加信息是 ["0x0"],需要被执行的额外函数是"setOwner(address)"

注:"0x2eca25e9e19b31633db106341a1ba78accba7d0f"是黑客的以太坊地址,"0x461733c17b0755ca5649b6db08b3e213fcf22546"正是ATN的代币合约地址。

黑客在发送了攻击交易后,下面的代码就会被激活:

    /*
     * ERC 223
     * Added support for the ERC 223 "tokenFallback" method in a "transfer" function with a payload.
     */
    function transferFrom(address _from, address _to, uint256 _amount, bytes _data, string _custom_fallback)
        public returns (bool success)
    {
        // Alerts the token controller of the transfer
        if (isContract(controller)) {
            if (!TokenController(controller).onTransfer(_from, _to, _amount))
               throw;
        }

        require(super.transferFrom(_from, _to, _amount));

        if (isContract(_to)) {
            ERC223ReceivingContract receiver = ERC223ReceivingContract(_to);
            receiver.call.value(0)(bytes4(keccak256(_custom_fallback)), _from, _amount, _data);
        }

        ERC223Transfer(_from, _to, _amount, _data);

        return true;
    }

可以看到这个函数的代码也就三部分,第一部分是一个权限控制,可以通过额外设定TokenController冻结某些帐号,在这里阻止被封的帐号移动资金; 第二部分就是require()那行,执行真正的转帐操作;第三部分则是提供附加函数支持的。
我还是通过上面的攻击代码解说具体流程,由于攻击交易只要求转帐0个ATN,所以交易在前三分之二都很合法,到了后三分之一部分,该代码首先把"0x461733c17b0755ca5649b6db08b3e213fcf22546"变成了一个可操作的ERC223ReceivingContract对象,这个对象其实在ATN代币合约里就有所定义:

/// @title ERC223ReceivingContract - Standard contract implementation for compatibility with ERC223 tokens.
contract ERC223ReceivingContract {

    /// @dev Function that is called when a user or another contract wants to transfer funds.
    /// @param _from Transaction initiator, analogue of msg.sender
    /// @param _value Number of tokens to transfer.
    /// @param _data Data containig a function signature and/or parameters
    function tokenFallback(address _from, uint256 _value, bytes _data) public;


    /// @dev For ERC20 backward compatibility, same with above tokenFallback but without data.
    /// The function execution could fail, but do not influence the token transfer.
    /// @param _from Transaction initiator, analogue of msg.sender
    /// @param _value Number of tokens to transfer.
    //  function tokenFallback(address _from, uint256 _value) public;
}

可以看到,tokenFallback是个示例,真正的响应代码需要程序员后续添加编写,所以transferFrom里用了custom_fallback的形式,提供了后续开发最大的自由度:只要交易的发起人能准确指定自己想用"0x461733c17b0755ca5649b6db08b3e213fcf22546"中的哪个函数,那么这个函数就会被执行,黑客很聪明,直接调用了"setOwner(address)",把自己设定成"0x461733c17b0755ca5649b6db08b3e213fcf22546"的权限所有人。于是,他想干嘛就干嘛了(想增发就增发了)。

攻击代码暴露出的漏洞

  1. "0x461733c17b0755ca5649b6db08b3e213fcf22546"理应是一个ERC223对象实例,而不是一个ERC223ReceivingContract对象实例,黑客可以透过代码强行生成自己想要的对象实例,造成了不安全的基础(EVM和Solidity语言设计的漏洞
  2. Solidity的开发指引明确说明,尽量不要用fallback来操作合约,前几年Multisig Wallet的漏洞频发正是有利的佐证,ATN开发人员为了后续开发的方便放开了fallback函数调用的口子,提供了不安全操作的通道(开发人员的代码编写问题
  3. 黑客通过攻击交易,实际上生成了一个子交易操控了ATN合约的权限转移:
setOwner("0x2eca25e9e19b31633db106341a1ba78accba7d0f", 0, ["0x0"])

这个子交易的函数变量,明显与"setOwner(address)"的原始变量设定不同,但是它依然能运行成功,达到一样的效果,这是多!么!可!怕!的!事!情!EVM的设计真是一堆坑!!!!

mmmmmmmm……怪不得要语焉不详呢= =谁看到了这种漏洞还想用以太坊哟……

失效的攻击防御

实际上,ATN代币合约洋洋洒洒五六百行代码,是有针对"setOwner(address)"做执行的权限设定的:

function setOwner(address owner_) public auth {
        owner = owner_;
        LogSetOwner(owner);
    }

auth正是权限设定的条件,我们来看看它具体是怎么写的:

modifier auth {
        require(isAuthorized(msg.sender, msg.sig));
        _;
    }
function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
        if (src == address(this)) {
            return true;
        } else if (src == owner) {
            return true;
        } else if (authority == DSAuthority(0)) {
            return false;
        } else {
            return authority.canCall(src, this, sig);
        }
    }

auth在发现交易发起人为owner或者是合约本身的情况下就会return true批准操作……由于黑客是通过fallback机制生成代币合约的子交易,发起人转变成了合约自己,所以这个安全闸门就被绕过了。

所以我一直认为多层权限控制是智能合约里需要避免的设计,虽然说对一个程序来说最危险的是用户(因为用户啥都不懂,容易乱操作引发bug);但最安全的也是用户,特别是你的管理员层级的用户(因为他们绝对没有捣乱的心,如果程序有不可预知的bug,可以通过用户的规范操作来避免bug的发生)。你把合约的控制交给另一个合约,还不如把控制权交给你信得过的人呢。
像ATN合约这种isAuthorized,还有现行的Multisig Wallet中的onlyWallet认证,都是我觉得不太安全的。EVM坑太多了,不要以身试坑啊!

ERC223,看起来很美?

上文所述的漏洞主要是跟智能合约的权限控制和fallback机制相关。但ERC223的设计初衷非常美好,是为了避免代币被不小心发到合约地址里无法提取,从而造成损失(https://github.com/ethereum/EIPs/issues/223)。
可是,可是,可是……避免这种情况,从ATN的解决方案看,并不需要有新的代币标准啊……

    /// @notice This method can be used by the controller to extract mistakenly
    ///  sent tokens to this contract.
    /// @param _token The address of the token contract that you want to recover
    ///  set to 0 in case you want to extract ether.
    function claimTokens(address _token) onlyController {
        if (_token == 0x0) {
            controller.transfer(this.balance);
            return;
        }

        ERC20 token = ERC20(_token);
        uint balance = token.balanceOf(this);
        token.transfer(controller, balance);
        ClaimedTokens(_token, controller, balance);
    }

    event ClaimedTokens(address indexed _token, address indexed _controller, uint _amount);

这就是一个预设的代币提取函数吧?跟新的代币标准有一毛钱的关系?
本-高贵的名侦探-辰分 陷入了深深的沉思……


2cdaa8b23157fe73608c0c3746ea8f7cf800a235.jpg

本文谢绝无授权转载,转载请联系本人,谢谢!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容