區塊鏈中“雞肋”的RPC漏洞
*本文原創作者:kmsrussian,本文屬於FreeBuf原創獎勵計劃,未經許可禁止轉載
一、前言——NEO RPC漏洞之爭
12月1日下午16:34,騰訊湛盧實驗室宣佈發現NEO的RPC漏洞。官微發文如下:
而NEO官方微博,在四個小時之後迅速回應騰訊,迴應如下。
誰對誰錯?公鏈RPC模組安全情況到底如何?
二、RPC 和RPC漏洞介紹
首先介紹下RPC。遠端過程呼叫(Remote Procedure Call)是一個計算機通訊協議。該協議允許運行於一臺計算機的程式呼叫另一臺計算機的子程式,而程式設計師無需額外地為這個互動作用程式設計。如果涉及的軟體採用面向物件程式設計,那麼遠端過程呼叫亦可稱作遠端呼叫或遠端方法呼叫。
古老的如微軟的一些RPC漏洞,通過畸形的RPC請求,觸發C/C++的字串拷貝連線之類的問題,造成記憶體覆蓋,引發安全漏洞。因為漏洞的表現方式是與程式語言密切相關的。微軟的很多問題元件基本都是使用C/C++語言開發,所以存在記憶體覆蓋這樣的安全問題。並且伴隨著SDL的推廣,類似當年的MS08-067的“盛況”很難再現。
2.1 公鏈和代幣使用的程式語言多樣
在區塊鏈上面,由於代幣和公鏈的開發語言多樣,如比特幣、EOS、XRP、XLM、DASH、XMR的主流客戶端使用C/C++開發,ethereum、bytom等的主流客戶端使用的是記憶體安全的Go語言實現。而很多志在構建基於分片、並行、分散式區塊鏈網路的公鏈,從一開始就選擇的是函數語言程式設計語言。如Rchain使用Scala語言開發,Aeternity使用Erlang語言開發。使用函式式語言開發的公鏈,除去邏輯類漏洞,語言層面就杜絕了過程式語言存在的一些安全隱患。
2.2 同一條公鏈存在不同語言的客戶端實現
一條公鏈存在各種語言實現的不同版本。比特幣節點的主流客戶端使用C/C++開發,如satoshi客戶端,但是同時還存在對開發者友好的客戶端。如java語言開發的bcoin,go語言開發的btcd。以太坊方面,主流的以太坊客戶端Geth使用Go語言實現,大概佔所有節點的80%。基於Rust語言實現的Parity-ethereum佔所有節點的20%,剩下的CPP-ethereum、Python-ethereum、Java-ethereum一般只存在研究價值,即使存在漏洞也不容易引發實際的安全問題。而此次騰訊號稱“存在問題”的Neo主流客戶端是.Net的實現,一般執行在windows系統上。
以上幾點造成了RPC漏洞在區塊鏈上的表現方式差異極大。
三、 區塊鏈上的RPC和雞肋的區塊鏈RPC漏洞
首先介紹下區塊鏈中RPC介面使用的流程和場景。以比特幣舉例,交易所如何判斷使用者的比特幣的確充值成功了呢?一般會在內網中做網段和環境隔離,然後使用docker部署一個對應的全節點客戶端,如比特幣可以部署bcoin的全節點客戶端。然後對RPC介面呼叫許可權進行設定,一般來說公鏈都會使用username和password的方式來確認呼叫者有許可權呼叫RPC介面。此時程式鑑權成功後,通過呼叫bcoin客戶端提供的rpc api介面Getblock by height,輪詢新區塊中是否有使用者充值的交易,然後等待對應的確認數後,返回給使用者成功充值的訊息。
在這個RPC呼叫的過程中,重要的一點是鑑權,鑑權成功後才有許可權呼叫對應的RPC介面。一般公鏈的都會提供CLI工具給使用者,用來配置RPC是否開放和開放後的鑑權方式,預設RPC介面在被本地呼叫的時候是不需要鑑權的,在被遠端IP呼叫的時候,即使對應的RPC介面存在漏洞,由於鑑權無法通過或者該RPC介面根本沒有配置開放,攻擊者也是沒有辦法觸發RPC漏洞的。
BTC/DASH/XMR等Coin一般存在2個模組,RPC模組和P2P模組。公鏈由於需要執行合約、通常圖靈完備,一般比Coin多兩個模組,虛擬機器和編譯器。而不管在Coin還是公鏈中都存在的RPC漏洞都很雞肋,原因就是RPC需要鑑權後才可呼叫,很難在真實環境中產生安全影響。
下面介紹下區塊鏈中曾經的或者還是“0day”的RPC漏洞
3.1 RPC 鑑權設計引發的安全漏洞
目前來看,該類漏洞危害最大,但幾乎沒有。暫時也還沒有發生類似於路由器後門萬能密碼的漏洞。目前只在bitcoind and Bitcoin-Qt早期版本有一個可以猜密碼的漏洞,CVE-2013-4165(注意此漏洞隻影響這兩個版本的比特幣實現,並不影響go版本的btcd和java版本的bcoin)。
bitcoind 0.8.1中bitcoinrpc.cpp中的HTTPAuthorized函式在檢測到密碼的第一個錯誤位元組時提供有關身份驗證失敗的資訊,這使遠端攻擊者更容易通過猜測爆破攻擊來確定密碼。
3.2 Post 過程中,觸發特定語言版本公鏈的RPC漏洞
表現的比較典型的就是cppethereum的CVE-2017-12119。前面已經說過,cppethereum是以太坊一個研究性版本,實際中幾無影響,並且rpc類漏洞,攻擊者必須鑑權後才能呼叫,更加大大削弱了該漏洞的實際影響。該漏洞由思科的talos團隊上報發現。https://www.talosintelligence.com/vulnerability_reports/TALOS-2017-0471
在呼叫cppethereum的rpc介面的時候,攻擊者可以Post傳遞一個畸形型別的引數,使得型別檢查不通過,可以直接導致cpp ethereum崩潰。
注意此類漏洞完全不影響以太坊主流客戶端geth和Parity-ethereum。
3.3 RPC 設計引發的邏輯類盜幣漏洞
目前來看以太坊和EOS都有類似問題。以以太坊舉例。
以太坊對於賬戶的RPC呼叫支援unlockaccount api。
https://github.com/ethereum/go-ethereum/wiki/Managing-your-accounts
可以看到,需要提供地址,密碼和解鎖時間。問題就出在解鎖時間上面,一旦解鎖,該錢包若還暴露在公網上,在duration期間的錢包,任何人在duration這段期間都有許可權將錢包中的eth轉走。
整個攻擊流程如下:攻擊者預先掃描 8545 埠(HTTP JSON RPC API)、8546 埠(WebSocket JSON RPC API)等開放的以太坊節點,遍歷區塊高度、錢包地址及餘額,一旦有餘額的地址處於unlock duration,重複呼叫 eth_sendTransaction 將餘額轉空。
EOS也支援賬戶解鎖函式,見https://developers.eos.io/eosio-nodeos/v1.1.0/reference#wallet_unlock。邏輯和攻擊手法相同,不再分析。
3.4 配置安全引發的問題
前面已經說過RPC呼叫是要鑑權的。如比特幣的bcoin客戶端,要遠端呼叫rpc介面必須提供使用者名稱和密碼。很多公鏈,如bytom,預設配置檔案即是127.0.0.1,也即本地發起的rpc呼叫是不需要認證的,通過遠端IP發起的rpc呼叫必須提供使用者名稱和密碼,否則無法進行rpc呼叫。但是如果使用者錯誤配置rpc,如弱密碼或者取消鑑權此時就會帶來安全隱患。
3.5 介面實現邏輯不嚴謹引發的漏洞
這裡我們以Go語言實現的bytom舉例,其他公鏈若有類似邏輯請自行查證。
一般來說公鏈中都會支援錢包配置檔案的備份和恢復,備份一般不會產生問題,但是此時的恢復,恢復本質上是接收外界的post引數,然後公鏈的程序要往所在的作業系統或者docker中的系統寫入一個檔案,如果在post傳遞引數上傳遞的是跨目錄覆蓋掉系統關鍵檔案的引數,結果如何呢?Bytom的早期的版本就存在這樣的一個漏洞,呼叫restore-wallet,傳遞畸形的post引數,在恢復錢包檔案的時候可以引發系統關鍵檔案被覆蓋,造成遠端程式碼執行。但是注意,攻擊者想利用該漏洞也得通過RPC的鑑權,才有許可權呼叫該介面。
修復起來就相對簡單。敏感性介面,邏輯實現上一定要禁止跨目錄的操作。
四、總結
RPC模組作為支付類幣種和公鏈都共有的模組,會存在一些安全問題。但是由於RPC呼叫需要鑑權,使得RPC模組即使存在漏洞,也是較難觸發利用的。此次的neo的rpc介面安全問題,影響相對有限,北京鏈安在此也提醒相關使用者,注意RPC的安全配置,避免產生RPC配置漏洞。