黑客來襲,手把手帶你深挖區塊鏈安全漏洞區塊鏈
區塊鏈行業正面臨著私鑰生成與保護、共識過程中心化、智能合約代碼漏洞等安全問題,開發者該如何應對及避免漏洞頻發呢?
目前,區塊鏈漏洞安全問題頻發。
區塊鏈行業正面臨著私鑰生成與保護、共識過程中心化、智能合約代碼漏洞、簽名過程算法漏洞、系統實現代碼漏洞等安全問題,對于以上問題,開發者該如何應對及避免漏洞頻發呢?
以下為吳家志在CSDN主辦,區塊鏈大本營、柏鏈道捷、極客幫創投協辦的技術沙龍上的發言內容,區塊鏈大本營在不改變原意的情況下作了精心整理。
我先自我介紹一下,我叫吳家志,目前在PeckShield擔任研發副總。我們是今年年初轉到區塊鏈領域的,其實創業初期我們有做過一些其他的嘗試,之前我的工作比較偏向操作系統安全方面,主要在安卓方向,像360 C0RE Team、360超級ROOT都是我在 360期間開發出來的產品。
目前,區塊鏈發展的趨勢是怎樣的?可以看一下數據,藍線代表創建智能合約數量的趨勢。
可以看出,去年9月份,智能合約數量出現了大幅下滑,年底各種ICO的出現,使智能合約數量有了很大的上升,今年2月份又出現了明顯的下降,過去的兩到三個月也都在下降,不過7月份開始又往上漲了,這其中的原因,在場的大家都知道,我就不說了。
而且,至少2017年下半年開始到今年年初,由于區塊鏈各行業DApp不斷落地,行業形勢看起來一片大好。
區塊鏈這么火,投資人會投入大量資金去買幣、炒幣...
但在我們安全研究人員眼里來看,它其實是黑客非常感興趣的目標。
從2014年的Mt.Gox的事件開始,一直到今年這個時間,出現了很多區塊鏈安全事件。比如今年4月份有關智能合約漏洞的美鏈(BEC)事件,5月份的EDU,到近期的交易所被黑,各類安全事件很多很多。
這種安全問題,它造成的結果是非常嚴重的,你的錢是真的不見了。不像是手機里面的照片、隱私被竊這種,這根本不是一個級別的。
今天我主要講兩個主題,智能合約安全和公鏈安全。
深入淺出:Fomo 3D漏洞
先講一下智能合約相關的安全問題,近期F3D十分火爆,它有很多有趣的東西,就在6天前,我們就有一個比較新的研究……
微博:https://weibo.com/ttarticle/p/show?id=2309404265433178991610
這個故事是這樣的,大概7月 23日晚上 8點多,我在微博上發現了一條關于F3D的信息,Geth客戶端開發團隊的 team leader、以太坊核心成員 Peter 發現了一個F3D的airdrop()問題,這引起了我的興趣,然后我們就去分析。
這個事情很有趣,先看右邊藍色框內,它就是F3D的智能合約之一,它其實有很多合約,今天我只講其中一個。
其中有一個環節做airdrop(),你可以理解為它利用了彩票抽獎的機制,假設你投注F3D,不管你買了多少Key,買完之后它就有一個小概率事件,會讓你中獎,然后你就會有一個額外的激勵。我覺得這個設計也挺合理的,它可以活躍用戶參與。
0.1個ETH是F3D最低的獎金,有人刻意用最低的投入去薅羊毛,他只要操作個錢,就有機會中獎。最后智能合約里面的withdraw()函數把錢取出來。
先看一下function airdrop()這個函數,有個名為seed的變量,seed是隨機數中很重要的一個概念,計算機世界中不存在一個絕對的隨機數,你只能通過seed去生成一個相對的隨機數。
一旦你可以通過某種方法預測seed值,這個隨機其實就會從小概率事件可能變成一個大概率事件。
比如說我剛開始學編程的時候,一開始學C,我用random()函數獲取隨機數,我那時候還不知道seed,我就會傳空值或者傳零進去,然后我發現每次跑都會是同一個結果。
這個黑客找到了一個方式,在每次投注的時候,預測說這里一定會開獎,百分之百會開獎。確定之后他再投這個錢,所以他每次都可以從里面拿錢出來。
說一下這個東西是怎么被預測的?其實它的實現是這樣的,可以看到seed運算里面有這么幾個關鍵點,比如說timestamp、difficulty、coinbase、gaslimit和number。
還有一個比較特別的,就是airDropTracker_,事實上這些都是合約里面的一個值,你可以隨時把它讀出來,所以你可以認為前面提到的全部都是已知的,唯一你不能預測的,就是msg.sender。
當時Peter認為F3D團隊假設認為msg.sender的隨機性是足夠的,其實 msg.sender就是你進到合約時的錢包地址,F3D團隊認為你不可能生成大量的錢包去嘗試,然后讓seed變成可預測的,但并不是只能從錢包進來,也可以從另外一個合約進來,這個其實就是關鍵。
這就又涉及到一個算法,有一個叫isHuman()的函數判斷,判斷是真人錢包還是其他合約,但問題是這個判斷有一個錯誤,就是Extcodesize()。
你可以用智能合約不停地刷airdrop(),這很像一個挖礦的過程,因為智能合約生成的新合約地址是可預測的,所以你就可以一直不停的算,直到算出一個seed結果滿足return(true) 時,就可以保證開獎。
一旦智能合約在constructor()里面去調isHuman()判斷時,它就會誤判,然后造成人為開獎的結果。
所以,就會出現這樣一個的攻擊模式——首先可以生成多個合約,然后就一直算,直到算到某一個可以搭配當下airDropTracker_的合約X時,就可以保證開獎,然后再根據合約X去投注,就可以不斷把財經池里面的財經全部都拿走。
但其實對F3D來說,這也不是一個太大的問題。因為被攻擊的財經池只是F3D整個獎金環節中的很小一塊。
所以,它就好比你玩某一個游戲,有一個外掛,你的攻擊力每次都加9,保證你可以把人砍死,大概是這樣,有點類似破壞游戲平衡吧,但其實對整個游戲的影響不會太大,比如說把所有人的個人資產都拿走。
其他智能合約相關漏洞
接下來講一些其他有關智能合約安全的問題。
有一類問題是跟allowance有關的,比如ERC20里面有一個標準的API叫transferFrom(),它允許某一個人把你的錢轉走,但前提是事先已經聲明好的,在哪里去聲明?就是在allowed[]這個數組里。
這里有一個問題,雖然它可以允許你把錢轉走,但是卻無法判斷你要轉走多少錢,它其實是僅僅把這個allowance剪掉了,這是代碼上的一個bug,EDU問題就屬于這種類型。
這是我做的一個實驗,我隱去了一些信息。
最上面那個0xd開頭的值是我的一個錢包地址,然后To指向是受我攻擊的合約的地址,攻擊完成后,我把0xa地址其中的一個EDU,就是好多0后面有1個的那個,轉到了0x6這個地址,其實0x6也是我的錢包地址。
Input Data這一塊是一些攻擊的細節,其實這個構造起來非常簡單,你只要去調transferFrom()函數,然后你就傳入from、to和value。所以,我偷了一個EDU到我的錢包,這個攻擊就是這樣的。
接下來,以batchTransfer()為例,講一下overflow相關的漏洞,它的攻擊是這樣完成的。
在調用batchTransfer()函數時,有兩個可以傳入的參數,一個是receivers,一個是value。
receivers是一個數組,它傳入了40這個數,這個數值表示偏移量,是需要傳給智能合約的。然后下面還有2或者8開頭的。
這個邏輯是這樣的,在batchTransfer()的實現上面,就是把8開頭后面全部都是0的這個值,同時轉給兩個人
如果按一般的邏輯去理解,賬號里必須有足夠的錢才能夠轉過去。但問題是,在它實現檢查時,它的實現方法是直接算兩個數的乘積。
用0去乘,結果是很明顯的,就算用最大的字節去乘,乘完之后它也會變成0。
所以,你可以在沒有任何錢的情況下把這么多錢轉給那兩個人,也就是上面紅色框部分,你會看到這個地方兩個transfer都是這么大量的Token,美鏈事件就是這樣,通過這種方式可以無中生有造出大量的假幣,然后再把假幣充到OKEx里面,然后就可以進行砸盤等各種操作。
另外一個案例和transfer還蠻像的,但稍微復雜一點,兩個address跟value都是數組。
它們溢出的方式一樣,就是說把這些值加起來或者乘起來,然后造成的結果也是一樣的,就是很大量的假幣就充進你錢包地址。
到這里,我大概簡單講了講智能合約方面的安全問題,其中一個是F3D薅羊毛的最新研究,還有一些過去我們發現的其他問題。
公鏈安全
今天的第二個主題,我講一下關于Infrastructure方面的安全問題,就是所謂的公鏈安全。
PeckShield在以太坊公鏈上做了很多研究,EOS相關的也有一些。
講到公鏈問題其實你可以這樣理解,比如說你用一個360手機衛士,可以理解為有一個客戶端在手機上運行,然后還有各種服務端,你要發送各種請求,然后它會推送一些信息給你。
而在區塊鏈里面,你可以理解為只有客戶端沒有服務端,至少以太坊上是這樣子的,每一個節點基本上長的都是一模一樣的。
所以,那時候我們開始進入區塊鏈行業、研究主鏈安全時,我們其實就是去看所有客戶端的代碼,看它實現的邏輯有沒有什么錯誤。
這邊是一個統計,Ethereum Nodes這個網站可以統計以太坊上都運行了哪些客戶端,比如說有Geth、C 和Parity,還有Python。所以,用的比較多的是Geth和Parity,今天的研究主要在Geth,因為它是官方的且用戶量大,對Parity也有一些研究。
首先講Geth這一塊,其實談到任何的安全問題,我們都需要先理解這樣一個事情,就比如說Geth是一個盒子,我們用什么方式可以攻破它?就是所謂的Attack Surface(攻擊面)的問題。
比如說可以通過一個智能合約去攻擊它,那它可能就是EVM方面的問題。
還可以通過一個RPC接口,它就可以類比成以前那種Web安全相關的這種問題。
還有一種,通過協議棧攻擊,這兩個其實是有點不一樣的。因為區塊鏈里面的每一個客戶端之間,它們會互相去同步,或者互相分享信息,所以協議棧的問題是最底層、也比較關鍵的問題,一旦出問題的話,整個系統可能就不運行了。所以,接下來我主要在協議棧這一方面進行一些探討。
這是以太坊的協議棧,大概是這樣,很多部分可能你們以前沒有聽到,像ETH、LES和Whisper是你們比較熟知的,就是以太坊的協議。然后跟它并列的還有一些其他的,它的底層其實是包含RLPx、DΞVp2p的。
假設說你運行過Parity或者Geth,你要同步一個full node其,實很花時間,我那時候剛開始弄花了可能有小一個月,就看你的帶寬怎么樣了;還有就是硬盤,我發現機械式硬盤基本沒戲,一定要SSD才有可能進行同步。
與ETH并列的協議LES,它是一個比較輕的協議,你在同步時,你不需要將所有的信息都同步,你可能只會同步一些metadata。
所以,在運行Geth時,你可以去指定運行LES mode這種模式。
接下來,詳細介紹一下我們之前發現的關于LES的安全問題。
簡單的說,就是一個越界讀的問題,問題出在上面這一行代碼,就在query.Skip這里。
我們可以自己去寫一個類似于Geth的客戶端,我只要知道你Geth的IP就ok。比如說有一個礦池,礦池總要有一個節點去同步到鏈上,我一旦知道這個IP是什么,我就可以偽造這個東西,然后讓你崩潰。
那么,如何讓它崩潰的?我把Skip值設成-1(在協議棧上你可以自由設置),-1 1就是0,就等于說我可以嘗試讓你去分配一個長度為0的數組,然后我又可以去讀這個數組的Skip值為-1的位置,那一定不再是你的位置了,它已經超過了你可以控制的內存范圍,所以它就必然會崩潰。
接下來,演示一下這個EPoD Demo,問題出現在1810版本之前,也包括1810這個版本。
在拍攝視頻時,我用的是官網上面的1810版本,對比過MD5,它是沒有經過任何修改的;還需要處于離線環境,避免遭受外界攻擊,保證所受攻擊都來自本機;運行Geth的LES mode。
然后監聽從本機發出來的30303端口,在運行攻擊代碼后, EXP后面的地址(即本機地址)是127.0.0.1,端口是30303,此時的Geth差不多就已經崩了。
index out of range,崩的理由就是這樣,一個越界讀。它在處理某一個這種LESMessages的時候,造成了一個越界讀。TCpdump就是我攻擊的錢包,我們把這個漏洞叫EPoD,我只要知道你的IP,發一個包,Geth就會崩潰,大概就是這樣。
還有一些攻擊,我應該會在9月份舉辦的ISC上講到。
比如說你新成立一個X交易所,然后有一個成立很久的Y交易所,你覺得它的交易量很大,想讓它變小,你就可以去攻擊Y交易所。
一旦你知道了Y交易所的IP以及它同步的node,就可以把信息擴散出去,就會忙死一片了。
像剛剛講的礦池,礦池最基本的一個事情就是算力,每個礦池之間都在競爭算力,那我一旦可以讓某些礦池癱瘓,這個礦池后面的算力也就沒了,這也是非常嚴重的。
但是通常我知道,礦池在使用Geth的同時,也會使用Parity,兩個客戶端會實時進行同步。一旦我們發現Geth和Parity同時存在問題的時候,就十分有趣了。
還有就是所謂的Boot Node,這個玩過的人可能會知道,一開始同步的時候你需要知道從哪邊開始同步,從哪邊開始就是所謂的Boot Node。
所以,當你癱瘓掉以太坊所有的Boot Node時,新的Geth就沒有辦法去同步,因為它根本沒有辦法啟動。
一旦找到這種涉及公鏈安全而且又是協議棧的問題,就可能會遭受這些攻擊的影響。
所以,如果Geth低于1810版本就趕緊升級吧。
1.TMT觀察網遵循行業規范,任何轉載的稿件都會明確標注作者和來源;
2.TMT觀察網的原創文章,請轉載時務必注明文章作者和"來源:TMT觀察網",不尊重原創的行為TMT觀察網或將追究責任;
3.作者投稿可能會經TMT觀察網編輯修改或補充。