EOS遊戲中的“無限讀檔”坐等大獎:RAM消耗漏洞及回滾交易漏洞
引子: 千淘萬漉雖辛苦,吹盡狂沙始到金 —— 《浪淘沙》劉禹錫
前情提要
上回書說到,DApp假幣魚目混珠,轉賬函式檢測疏漏馬虎
對於製造偽EOS以次充好,其實只需要檢查發行方是否為eosio,或者呼叫相關合約檢視代幣資訊,但是檢查代幣操作依然不夠嚴謹的情況下又會產生更多的變體漏洞,導致遭受變體攻擊的風險,所以EOS智慧合約中的程式碼非黑即白,切不可模稜兩可。看來,要做到完備的漏洞防禦,必須先透徹理解EOS業務邏輯特性以及規則限制。本期我們就由EOS業務邏輯特性為切入點,解析RAM消耗及回滾交易漏洞。
本期話題
陌生轉賬RAM被吞,交易回滾大獎送人
每一位遊戲玩家都曾在遊戲中體驗過一馬當先,萬夫莫開的暢快淋漓,也體驗過心驚膽戰,如臨大敵的徹骨寒意。但遊戲終究是遊戲,大多數情況下,都有許多嘗試的機會,尤其是單機遊戲,可以適時存檔後,重新讀檔不斷嘗試“從跌倒的地方爬起來”。
在EOS遊戲和DApp不斷湧現的今天,還沒有出現與傳統單機遊戲結合的機制。倒是有很多競猜類的遊戲大受歡迎,但是競猜類遊戲以公平競猜為遊戲理念,不能允許玩家以不斷嘗試的方式獲取獎勵。但是不斷嘗試確實是增加獲取獎勵機率很有效的方式,於是黑客們找到了一種零成本不斷嘗試競猜的方式,試圖在EOS DApp中輕而易舉拔得頭籌。介紹這種攻擊手段之前,讓我們來了解一下EOS特殊的業務邏輯。
基礎知識
EOS智慧合約業務邏輯特性
原理
在EOS智慧合約交易情景中,合約常常需要根據收到EOS token的情況來執行相關業務邏輯,這主要是通過eosio.token合約中transfer函式的通知回執來實現的:
當用戶A向用戶B轉賬時,使用者B會接收到這個通知,並可以進行相應的函式處理,這是由require_recipient的特殊機制產生的結果。
require_recipient在這裡的實現邏輯是: 將原本的action receiver修改為傳入的賬戶,再發起一次action呼叫,相當於帶著同樣的引數又呼叫了一次A和B賬戶的transfer函式。
關於這個特殊的機制,EOS官方給出了相關的解釋:
那麼,如果在B賬戶部署一個智慧合約,定義一個transfer函式就可以進行相應的業務邏輯處理,示例如下:
注意,這裡的transfer函式使用了上一期提到的if (from == _self || to != _self)防禦手段,驗證收到轉賬的是自己來預防變體轉賬攻擊。
當然,除了transfer,require_recipient(account_name 合約賬戶XXX)也可以呼叫XXX合約中的其他同名函式。
漏洞如影隨形
RAM消耗漏洞
按照上面B賬戶裡面的智慧合約實現業務邏輯,是沒有什麼問題的,但是如果按照如下合約實現的話,問題就會出現了:
這個智慧合約中,komo::transfer中的for迴圈用賬戶from的授權寫了很多無用的記錄到state.db,而這個操作使用者在eosio::transfer時是不知情的。
有關方面給官方寫出了這個情況的修改建議:
在require_recipient觸發action handler 執行時, 禁止被觸發的handler 使用當前action 的授權。
如果被觸發的 action handler 有儲存要求,可以使用inline actions 來解決, inline action 被執行時就不會用到原來action 的授權了。
但是,使用inline action如果不加註意,又會產生另一個漏洞。
回滾交易漏洞
歷史事件
eos.win在2月9日被攻擊者利用inline action漏洞的回滾交易攻擊通關過,交易細節如下:
原理:
EOS合約內部的action呼叫分為inline action和deferred action,用於合約對其他action的呼叫,這兩種呼叫方式是有一定區別的:
1. inline action與原來的action是同一個事務,如果inline action失敗了,整個事務會回滾;
2. deferred action 與原來的action不屬於同一個事務,並且不保證deferred action 能夠成功執行,如果失敗了,也不會引起原有action的事務回滾。
在早期,很多EOS遊戲合約都是使用inline action這種方式來實現的,從下注、開獎、發獎、通知,一系列操作雖然寫在不同的action中,但是執行的時候都是通過inline action的方式來聯動,達到使用者下注後自動開獎發獎的效果。
在這種情況下,如果合約通過require_recipient來向用戶賬戶傳送開獎通知,那麼使用者賬戶就可以通過接收require_recipient的通知來判斷是否成功贏取獎勵,如果失敗,那麼呼叫eos_assert(0)來使action執行失敗,由於所有action都是inline action,這將會導致整個transaction失敗,使用者下注的EOS會退回。
如果合約沒有傳送require_recipient通知,攻擊者也能通過自己組裝inline action,然後通過對自身餘額或者合約資料庫資料的判斷來實現回滾攻擊。
這樣,攻擊者製造action執行失敗後,就能將每次投注的EOS退回,從而無成本重新加入遊戲,直到獲獎為止,模擬了單機遊戲中“無限讀檔”,直到通關的遊戲方式。
漏洞修復
在實現自動開獎發獎的一系列動作中,不要慣性思維的使用inline action,適時使用deferred action可以預防整個一套交易流程回滾到下注之前,規避攻擊者零成本再次參與遊戲的風險。
黑客尚可鍥而不捨,安全怎能鬆懈怠惰
EOS與以太坊相比,以其吞吐量大,處理速度快,以及交易成本低等優勢佔據了開發DApp的有利地位,與初期的以太坊相比,低階錯誤導致得安全漏洞發生率似乎有所降低,但是由於遊戲以及DApp的業務邏輯性比單純的數字貨幣智慧合約要複雜許多,黑客依然能夠在業務邏輯中找到開發者不曾設想過的“套路”,作為迅速獲利的墊腳石。
本期的回滾交易攻擊說明,即使是攻擊者,也想到用不斷嘗試,不斷努力的方式達到自己贏得遊戲的目標。作為區塊鏈安全生態的支持者和建設者,我們每一個人更應該以鍥而不捨的精神,從底層程式碼做起,維護區塊鏈相關應用的安全,穩步發展。
引用:
[1]: 警惕!EOS惡意合約可吞噬使用者RAM漏洞分析
ofollow,noindex" target="_blank">http://www.cocoachina.com/cms/wap.php?action=article&id=24425
[2]: https://eosflare.io/tx/e28fa9fbd6008edc1a66e01ea4e443265eb9bacce0b423351d178dcb6928de3b
[3]: Inline action to external contract
https://developers.eos.io/eosio-home/docs/sending-an-inline-transaction-to-external-contract