編者按:本文來自36氪戰略合作區塊鏈媒體 「Odaily星球日報」(公衆號ID:o-daily, APP下載 )
奇虎360漏洞團隊Yuki Chen和奇虎360核心安全團隊Zhiniang Peng發現EOS節點在遠程執行代碼時存在漏洞,他們在360官方博客上發佈了這一問題,以下爲博客編譯內容:
漏洞描述
在解析WASM文件時,我們發現、併成功利用了EOS緩衝區越界寫入漏洞。
通過這個漏洞,攻擊者可以把一個惡意智能合約上傳到節點服務器,之後節點服務器就會解析這個惡意合約,然後惡意合約就會在服務器上被執行,之後控制該節點服務器。
在控制了節點服務器之後,攻擊者可以將惡意合約打包到新的區塊中,繼而進一步控制EOS網絡內的所有節點。
漏洞報告時間表
2018-5-11 發現EOS越界寫入漏洞
2018-5-28 EOS超級節點完全利用演示完成
2018-5-28 漏洞詳細信息報告給供應商
2018-5-29 供應商修復了GitHub上的漏洞,並解決了問題
2018-5-29 注意到供應商修復尚未完成
下面是一些和Daniel Larimer在Telegram上的聊天截圖:
我們嘗試將漏洞報告告訴他。
他表示,他們不會在沒有修復漏洞的情況下發布EOS,並且要求我們私下發送報告,因爲有些人正在使用公共測試網。
Daniel Larimer提供了他的電子郵件,我們將漏洞報告發送給了他。
EOS修復了這個漏洞,Daniel Larimer將會給予確認。
技術細節漏洞
這是一個緩衝區越界寫入漏洞。在「 libraries/chain/webassembly/binaryen.cpp(代碼第78行),Function binaryen_runtime::instantiate_module:」
for (auto& segment : module->table.segments) {
Address offset = ConstantExpressionRunner<TrivialGlobalManager>(globals).visit(segment.offset).value.geti32();
assert(offset + segment.data.size() <= module->table.initial);
for (size_t i = 0; i != segment.data.size(); ++i) {
table[offset + i] = segment.data[i]; <= OOB write here !
}
}
這裏的表示一個std::矢量包含了功能表的「Names」。當存儲元素導入到表內,|offset|函數域將無法正確實施檢查工作。請注意,在設置該值之前,有一個asset函數,它會檢查|offset|函數,但不幸的是,assert函數只適用於Debug版本,而不適用於正式的發佈版。
在聲明之前,該表將會進行初始化:
table.resize(module->table.initial);
這裏「|module->table.initial|」將會從一個功能表的聲明部分被被讀取,該字段的有效值爲0~1024.
|offset|函數域還會從WASM文件被讀取,在數據部分,它是一個符號型32位值。
所以基本上,利用這個漏洞,我們可以在表矢量的內存之後寫入相當廣泛的range。
如何重現該漏洞
1、構建最新EOS代碼發佈版本
./eosio-build.sh
2、啓動EOS節點,按照下面鏈接裏的描述,完成所有必要的設置
https://github.com/EOSIO/eos/wiki/Tutorial-Getting-Started-With-Contracts
3、設置一個「脆弱」的節點
我們提供了一個WASM概念證明來證明這個漏洞。
在我們的概念證明中,我們只需設置|offset|函數域爲0xffffffff,這樣在越界寫入發生時,就會立刻崩潰。
測試概念證明:
cd poc
cleos set contract eosio ../poc -p eosio
如果一切都就緒,你會看到nodeos進程發生段錯誤。
崩潰信息:
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x0000000000a32f7c in eosio::chain::webassembly::binaryen::binaryen_runtime::instantiate_module(char const*, unsigned long, std::vector<unsigned char, std::allocator<unsigned char> >) ()
(gdb) x/i $pc
=> 0xa32f7c <_ZN5eosio5chain11webassembly8binaryen16binaryen_runtime18instantiate_moduleEPKcmSt6vectorIhSaIhEE+2972>: mov %rcx,(%rdx,%rax,1)
(gdb) p $rdx
$1 = 59699184
(gdb) p $rax
$2 = 34359738360
Here |rdx| points to the start of the |table| vector,
And |rax| is 0x7FFFFFFF8, which holds the value of |offset| * 8.
利用此漏洞實現遠程代碼執行
攻擊者可以利用此漏洞在nodeos進程中實現遠程代碼執行,方法是將惡意合約上傳到節點,並讓節點解析惡意合約。在實際攻擊中,攻擊者可能會向EOS主網發佈惡意合約。
EOS超級節點會首先解析惡意合約,然後觸發漏洞,之後攻擊者回控制解析了惡意合約的EOS超級節點。
接下來,攻擊者可以竊取超級節點的私鑰,或是控制新區塊的內容。更重要的是,攻擊者可以將惡意合約打包成一個新區塊併發布。這樣做的結果,就是讓這個網絡中的所有完整節點都被攻擊者控制。
我們完成了概念驗證漏洞測試,並且在64位的Ubunt操作系統的nodeos進程中進行了測試,這個漏洞是這樣工作的:
攻擊者將惡意合約上傳到nodeos服務器上;
服務器nodeos進程被解析能夠觸發漏洞的惡意合約;
在越界寫入漏洞下,我們可以重寫WASM模塊實例的WASM內存緩衝區。此外,在惡意WASM代碼的幫助下,我們最終在nodeos進程中實現了內容內存讀/寫操作,並且繞過了64位操作系統上的DEP / ASLR等常見的防惡意攻擊技術;
一旦成功利用該漏洞,就會啓動一個反向shell程序,並連接回攻擊者;
您可以參閱我們提供的視頻,以瞭解該漏洞的具體情況,稍後我們還會提供完整的漏洞利用鏈。
漏洞修復
BM在EOS的GitHub第3498個開放問題上披露了正在處理我們報告的漏洞問題:
修復的相關代碼
但是,正如Yuki對所提交修復內容做出的評論,在處理32位進程的時候仍然存在問題,因此問題還沒有被得到完美解決。