根據ethernodes最新資料顯示:以太坊parity客戶端在整個以太坊網路中佔30%,Geth客戶端佔40%。
在今年2月3日時,這款客戶端官方發表公告稱修復了一個遠端拒絕服務的嚴重漏洞,這個漏洞影響2.2.9之前的版本和2.3.2-beta之前的版本,而2.2.9和2.3.2-beta已經是最新版。從官方的通告來看,可理解為:目前這個漏洞通殺漏洞修復前的所有版本。
雖然該漏洞影響版本很多,但影響範圍有限。原因便是該漏洞需要攻擊者能夠訪問目標Parity客戶端的JSONRPC,而Parity預設是不對外開放JSONRPC埠。
該漏洞具體影響範圍可以透過FOFA統計出結果:
從上圖,我們可以看到目前公網上有1195個parity節點開放了JSONRPC埠,故該漏洞影響版本多,但影響範圍有限。
二、UTF-8編碼是什麼?
我們在研究這個漏洞之前需要了解一下UTF-8編碼,來幫助我們更好為漏洞研究做準備。
Unicode是一種字元編碼,是目前計算機行業內比較通用的一個編碼,因為Unicode把所有語言都統一到一套編碼裡,解決了行業內由於語言不一致而導致的亂碼問題。
而UTF-8(8-bit Unicode Transformation Format)是一種針對Unicode的可變長度字元編碼,又稱萬國碼。
在這篇漏洞分析中,你只需要知道以下知識點就夠了:UTF-8編碼中,一個英文字元佔一個位元組,一箇中文(含繁體)佔三個位元組。
三、Rust危險的字串切片
在上個章節中介紹了UTF-8編碼的原因是:Rust就是使用的UTF-8編碼,以太坊Parity客戶端使用的程式語言是Rust。
字串切片很好理解,就是擷取出字串中的某一段字串,不過Rust的字串切片有一個毛病:
切的是位元組,不是字元
筆者簡單來測試一下,如下圖:
透過圖片內容顯示,我們可以看到當切片str1字串的0-3個元素的時候,切出來了”DVP”3個字元,但是當切片3-6個元素的時候,如果按字元切的話應該切出來“是最棒”,但是並沒有。
為什麼會出現這種情況?
原因是Rust按位元組切片。在文章此部分之前提到過:在UTF-8中英文佔1個位元組,中文佔3個位元組,所以我們切3-6就只切出來了“是”這一個字。
這是正好3個位元組切片切到了一個完整中文字元的情況。設想一下:假如切片切的是2個位元組呢?
— 會顯示半個中文嗎?
— 答案是:當然不會了。
當切片切出來不是一個完整字元的時候,Rust不會給你切出來任何字元,而是報錯。
簡單測試一下
透過圖片我們可以看到,當切片3-5的時候程式報錯了,因為切到的不是一個完整的中文字元。
以太坊Parity客戶端正是犯了這個錯誤,這也是我們今天本文中漏洞分析的關鍵所在。
四、漏洞分析
DVP安全團隊在編寫本文時,官網沒有披露任何漏洞詳情,可能是因為一些節點還未更新到新版修復漏洞的緣故,而且檢索一番之後發現網路上也沒見到有人在討論這個漏洞,於是只能去Parity的github中翻查commit記錄,試圖找到關於這個漏洞的修復補丁,透過補丁來分析漏洞,最終我們看到了這個commit:https://github.com/paritytech/parity-ethereum/commit/3b23c2e86d09a8a8b8cd99dfa02390177498e6b7
大概看了一下,基本可以確認這就是修復補丁了,補丁中多處把字串切片換成了starts_with函式:
透過上圖,可以看到,在之前的寫法中是先把字串的0至2個元素切出來,並判斷是不是以”0x”開頭,如果長度小於2並且前兩個元素的字串不是”0x”的話就返回一個error.本文上面我們瞭解了Rust的切片是存在一定危險性的,如果被切片的字串可控的話就會導致程式報錯。
那麼,這些使用了字串切片的地方是否能被遠端利用呢?
仔細看圖可以發現,圖中被修改的兩個檔案都在rpc目錄的types目錄下,我們猜測應該是為JSONRPC介面傳來的資料定義的一些型別,圖中就有hash和uint。
再去翻查以下官方的RPC文件:
原來官方文件其實都有說明,由於json裡面只有字串和數值兩個型別,所以像integers、byte、hashes這些資料型別都是透過以0x為字首的字串形式編碼傳輸的。
根據官方文件的描述,我們測試漏洞就很方便了。在文件給的請求樣例中任意找一個引數中有0x字首的,省去了看函式呼叫鏈的時間。
這裡找了一個比較常見的eth_getTransactionByHash介面,請求方式如下:
curl --data '{"method":"eth_getTransactionByHash","params":["交易hash"],"id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST localhost:8545
利用的話也很簡單,將”交易hash”替換為中文字串就行了,例如:
curl --data '{"method":"eth_getTransactionByHash","params":["你好DVP"],"id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST localhost:8545
實際演示一下:
可以看到在請求介面後節點確實發生了異常並崩潰了。
五、修復方案和總結
官方的修復方案前面有提到,就是將字串[a..b]這種切片寫法全部修改掉。
不過這只是一時的修補方案,若想長久的預防此類漏洞,我們認為公鏈開發者應該要比傳統軟體開發者更瞭解語言的特性,因為很多程式碼用常規程式設計思維去看問題不大,但是語言本身可能存在一些開發者並不瞭解的特性,在特性的輔助下漏洞就產生了,之前就有公鏈使用go語言濫用make函式,而且引數控制不當,然後產生由OOM導致的拒絕服務漏洞。
故DVP安全團隊透過本期漏洞分析希望能夠藉此給大家警示,區塊鏈開發者在未來的開發之路上,需要更加了解語言的特性,這樣才能讓區塊鏈生態更加穩固、安全。
更多數字貨幣資訊:www.qukuaiwang.com.cn/news