
近期,一名英國的15歲黑客Saleem Rashid爆出,Ledger Nano S這款比特幣硬件錢包有嚴重的安全性漏洞,它可能會被黑客控制,成為黑客安插在你身邊的“間諜”,偷走你的比特幣。
什么是Ledger Nano S?這可是硬件錢包市場上的明星產品。
此后,Rashid將他的破解教程發布在個人博客之中,經區塊鏈大本營整理如下。害人之心不可有,防人之心不可無。希望這篇文章,能讓你多一些警惕吧。
作者 | Saleem Rashid
編譯 | Guoxi
編輯 | 小西
在這篇文章中,我將討論我在Ledger硬件錢包中發現的一個漏洞。Ledger公司使用自己開發的體系架構來解決比特幣硬件錢包安全性上的限制,因此,這個安全體系難免會有一些漏洞。
?
?
Ledger Nano S比特幣硬件錢包
因為這個漏洞,Ledger硬件錢包變得極其不安全。黑客不僅可以在用戶拿到Ledger硬件錢包之前黑掉它,還以物理方式甚至在某些場景下可以遠程從硬件錢包中竊取用戶的私鑰,也就意味著,黑客可以輕而易舉地偷走你的比特幣。
那么,黑客到底是怎么實現的呢?
如何偷走比特幣
1.在設置種子之前進行物理訪問
本文中我們將用到供應鏈攻擊,軟件供應鏈是指由軟件源碼編寫,源碼編譯,軟件分發,軟件下載,軟件更新環節組成的流水線。軟件供應鏈攻擊則是在軟件供應鏈中的各個環節利用不同的技術對軟件進行攻擊。使用供應鏈攻擊并不需要目標計算機上的惡意軟件,甚至不需要用戶對交易確認。我已經在Ledger的Nano S型比特幣硬件錢包上實現了這種攻擊,此外,為了維護系統的安全性,我在幾個月前就將源碼發給了Ledger,以便Ledger修復此漏洞。
從上面的視頻中可以看出,我們可以輕而易舉地執行供應鏈攻擊修改生成的用于恢復的種子。由于所有的私鑰都來自于恢復種子,所以,黑客可以盜取所有加載到硬件錢包上的數字資產。
2.安裝后的物理訪問
這通常被稱為邪惡女傭攻擊。攻擊后你可以提取到硬件錢包上的PIN,恢復種子和任何使用的BIP-39口令。
如前所述,這并不需要計算機上的惡意軟件,也不需要用戶確認任何交易。它只需要黑客安裝一個自定義的MCU(Microcontroller Unit,微控制單元,又稱微控制器或者單片機,下文使用微控制器)固件,用戶下次使用比特幣硬件錢包時,私鑰就會在他們不知情的情況下泄露出去。
3.惡意軟件(帶一些社交工程學)
這種攻擊方式會要求用戶在中病毒的計算機上升級MCU固件。這可以通過顯示一條系統錯誤信息誤導用戶,要求用戶按住左鍵并重新連接比特幣硬件錢包(以進入MCU的引導加載程序)來實現。然后惡意軟件可以用惡意代碼更新MCU固件,從而允許惡意軟件控制比特幣硬件錢包的顯示屏和確認按鈕。
這種攻擊以發生過多起,常常是在官方進行固件更新時出現。
概念驗證
如果你不想錯過創建一個漏洞的機會,你可以來Github上找到我的概念證明。
如果你按照說明進行操作并把它安裝在運行固件版本為1.3.1及以下的Ledger Nano S比特幣硬件錢包上,你可以實現剛才視頻中的攻擊。但是,因為這只是為了教育目的,我故意讓你復原出的攻擊不可靠。
比特幣硬件錢包的前世今生
像比特幣這樣的加密貨幣使用公鑰密碼學(又稱非對稱密碼學,是使用一對公鑰和私鑰的密碼學)來保障資金安全,只有你擁有私鑰,才能使用這筆資金。
這給用戶造成了一個問題,用戶應該如何保護自己的私鑰?通常,人們在記憶密碼方面的表現都十分糟糕,即使安全專家也不例外。
為了解決這個問題,出現了一種新的設備叫做“比特幣硬件錢包”。顧名思義,這種硬件設備可以存儲用戶的私鑰以防范惡意軟件,這種設備一般都可以通過USB端口連接到電腦上,但是并不會在電腦上泄露私鑰,就像硬件安全模塊(hardware security module,HSM,可以理解為銀行卡配套的U盾)一樣。
然而,獲取私鑰并不是黑客竊取你心愛的比特幣的唯一方式,攻擊比特幣硬件錢包的黑客可以輕而易舉地更改你交易的對象和交易的金額,從而把你的錢轉到他的賬戶上。這是秘密完成的,許多用戶都沒有意識到自己受到了黑客的攻擊,發現時已為時已晚,自己的比特幣就這么丟失了。
因此,一個比特幣硬件錢包應該有以下幾個功能,從而和笨拙的硬件安全模塊區分開來。
比特幣硬件錢包也需要防范各種各樣的攻擊:
我們可以進一步將最后一個攻擊的程序分為兩步:竊取比特幣硬件錢包和實行邪惡女巫攻擊,如果黑客可以竊取設備,那么他會有更長的時間來執行攻擊,甚至可能使用到實驗室中昂貴但高性能的破解設備。但是,在此期間用戶可能會意識到比特幣硬件錢包的丟失并將錢轉出。
安全功能,比如未存儲在比特幣硬件錢包中的密碼數據可以防止攻擊者竊取你的資金,因為僅僅一個比特幣硬件錢包并不包含恢復用戶私鑰所必要的完整信息。
另一方面,在邪惡女仆攻擊中,黑客只能在有限的時間里執行攻擊,而且沒有了實驗室中高性能設備的加持。但是這種攻擊方式可能更加危險,因為它可用于多種場景中:
還有一種場景,我們要關注供應鏈攻擊的可能。即:當你從經銷商或第三方購買比特幣硬件錢包時,你拿到的設備是否可信?正如我最開始說的那樣,你的比特幣硬件錢包可能已經遭受了攻擊。
入侵比特幣硬件錢包
2014年9月,Ledger發布了HW.1比特幣硬件錢包。這款錢包基于微控制器ST23YT66,含有一張智能卡,支持USB連接。不幸的是,這個設計有嚴重的局限性:這款錢包沒有一個可信任的顯示或按鈕,這使得錢包用起來很危險。
2016年7月,Ledger宣布推出名為Nano S的新款比特幣錢包,這款錢包基于安全元件(Secure Element,通常以芯片形式提供。為防止外部惡意解析攻擊,保護數據安全,在芯片中具有加密/解密邏輯電路。)ST31H320,含有確認按鈕,可信任的顯示屏,支持USB連接。
2017年11月,我決定仔細研究Nano S的安全性。
來看看Nano S的雙芯片架構。
盡管ST31H320沒有可用的公共數據表,僅僅查看數據摘要我們發現此款安全元件并不支持顯示!實際上,它甚至不支持USB連接,它支持的唯一接口是低吞吐量的UART(Universal Asynchronous Receiver/Transmitter,通用異步收發傳輸器,是一種異步收發傳輸器,是電腦硬件的一部分)。
什么鬼?那顯示屏是怎么工作的呢?
碰巧,Ledger開發了一個新的架構來解決這個問題,Nano S增加了一個非安全的微控制器STM32F042K6,由它來充當安全元件的代理。該微控制器驅動顯示器,按鈕和USB接口。兩芯片各有分工,安全元件存儲私鑰,非安全的微控制器充當安全元件的接口。
為了描述簡便,我們將把ST31H320安全元件稱為SE,將STM32F042K6微控制器稱為MCU。架構如下圖所示。
?
?? Ledger Nano S的架構
長話短說,安全元件只能與微控制器直接通信,但是,微控制器可以代表安全元件與外設進行通信。
安全元件的一個重要特性就是我們可以執行密碼學驗證證明它是否正在運行Ledger官方固件,這實際上也是Ledger的一個賣點:實際上,Ledger認為這個安全功能十分強大,以至于Ledger比特幣硬件錢包都不需要貼防開封標簽,正如商品隨附的說明中所述:
?
?
?
?
?
其他公司的硬件錢包都貼了防開封標簽
?
?
商品隨附的說明
(你是否發現,我們的產品上并貼沒有防開封標簽。別擔心,Ledger的密碼機制會在每次開機時檢查固件的完整性,安全元件芯片可以防止各種入侵和物理破壞,我們的產品十分安全)
Ledger的首席技術官甚至告訴用戶Ledger比特幣硬件錢包十分安全,不用擔心購買的來源,可以放心大膽地從第三方平臺如eBay上購買Ledger比特幣硬件錢包。
這帶來了一個很關鍵的問題,相信你也想到了,安全元件上的軟件被證明是安全的,但是微控制器并不是一個安全的芯片,并且,如我們下面的教程所示,微控制器的固件可以被黑客篡改。
這里存在的問題是:要實現Ledger的安全保證,必須把信任鏈錨定在安全元件中,這意味著安全元件必須要驗證不安全的微控制器上的固件。
如何篡改硬件?
雖然本文將著重介紹軟件篡改,但是需要注意的是,如果沒有軟件漏洞,你仍然可以通過篡改硬件來入侵設備。
注意到這點很重要,為了使這些比特幣硬件錢包安全,必須完整地驗證設備硬件。
由于Ledger的比特幣硬件錢包及包裝都沒有做防開封措施,因此黑客可以輕而易舉地篡改設備,我不禁要再重復一遍:如果你不驗證物理硬件,那么你的資產處于危險之中!
當有人未經你授權使用了你的設備時,一定要再次驗證,否則你很容易受到邪惡女傭攻擊。
Ledger提供了驗證物理硬件的說明,但我注意到其中的兩個問題。
網上圖片的清晰度各不相同,Ledger需要提供能清晰顯示每個組件的高分辨率圖像。
設備的背面完全沒有顯示。
驗證設備的背面是十分重要的,因為這是微控制器的JTAG頭(一個調試接口)所在的地方。
即使解決了這兩個問題,我認為如果黑客使用了一個具有額外內存但引腳數與STM32F042K6相同的微控制器假冒STM32F042K6,還是可以黑掉比特幣硬件錢包。
這里我們論證了很多硬件上黑掉比特幣硬件錢包的可能性,現在我們回到軟件破解比特幣硬件錢包上來。
Ledger的防范措施——驗證微控制器固件
假如你已經仔細檢查了硬件,并且確實沒有更改,如果攻擊者只是修改微控制器的固件會發生什么?
Ledger考慮到了這種攻擊,為了防止出現這種情況,微控制器固件要經安全元件驗證。
但事實證明,在非安全的微控制器上驗證固件并不是那么簡單,安全元件只是一個智能卡,這意味著與微控制器通信的唯一方法就是通過一個低吞吐量的UART,又不能直接訪問微控制器上的RAM或內存,安全元件如何驗證其固件?
Ledger的解決方案是:安全元件要求微控制器傳遞其內存的全部內容,如下所述。
?
安全元件驗證過程
乍一看這似乎有問題,原則上,我們是在要求一個(很可能已經被篡改了的)微控制器證明自己正在運行Ledger的官方固件。但是,如果微控制器已經被篡改了,它依然可以發送Ledger的官方固件,怎樣才能確保它發送的是自己現在正在運行的固件呢?這是Ledger面臨的挑戰。
Ledger采用的解決方案基于這樣一個事實,即微控制器的內存大小是有限的。如果要讓微控制器運行惡意固件,黑客還需要存儲一份Ledger官方固件以便于應對安全元件的檢查。因此,Ledger的解決方案是限制內存大小,是這種攻擊行為變得困難。
具體而言,通過驗證整個內存(并用隨機數據填充空白區域),Ledger試圖修復這種存有惡意固件但是能通過安全元件檢查的漏洞。
這是一個很了不起的想法,也許想法可能會實現。但是,我完全不同意這個解決方案。
我的獨家攻擊方式
雖然可以采用一些直接的方法攻擊這種架構,例如可以通過電腦的USB端口為比特幣錢包軟件植入惡意代碼,但嘗試獨立開發一種攻擊方式(比如使用供應鏈攻擊來攻破比特幣硬件錢包)顯得更有趣些。
我最開始使用的方法是壓縮代碼,綜合考慮執行時間,內存使用量和代碼大小,使用諸如DEFLATE或LZMA之類的壓縮算法是行不通的。因為如果用戶花了20秒才啟動了錢包,那么他一定會考慮是否發生了異常。
更不用說,雖然壓縮整個內存的結果令人滿意,微控制器的結果也讓我欣喜若狂,但我不想更換已經存在內存中的微控制器的引導程序,因為有兩種方法都可以用來在比特幣硬件錢包中安裝新固件。
使用JTAG,這個調試接口是為嵌入式固件開發人員上傳新固件設計的。
使用引導程序,通常Ledger的用戶都是用這種方法來升級固件,你可以在Github中找到Ledger為此設計的Python工具。
我使用了第二種方法,因為我不喜歡焊接東西。如果我在更換引導程序時出錯,這個方法就會失效,除非使用JTAG接口修復,否則設備也會變磚。
因此,更換引導程序并不是最佳選擇,我們需要排除壓縮這個選項。
但還有另一種方法。在編譯C程序時,工具鏈(編譯程序的軟件套件)會執行許多魔術一樣的操作,從而保證編譯的成功。例如,許多處理器并沒有關于大數除法的指令,編譯器通過插入除法操作的軟件來解決這個問題。另一個例子是關于對函數中定義的變量聲明初始值。當函數被調用時,編譯器會在最開始插入額外的代碼將該初始值復制到堆棧中。
編譯器為執行這些任務而插入的額外函數被稱為“編譯器內聯函數”。由于微控制器同時具有引導程序和固件,并且他們是完全獨立的程序,所以這些內聯函數將在內存中出現兩次(每個程序中只出現一次)。
這樣做的結果就是我們可以插入我們的惡意代碼來取代編譯器內聯函數例程的一個冗余副本(特別是,固件中的副本),因此我們保存了引導程序的完整副本。
由于引導程序中的固有內容與固件中的內容完全相同,因此當安全元件向微控制器詢問其內存內容時,我們可以通過剔除惡意代碼并從引導程序中發送該段代碼,從而“拼湊”出正確的映像,當固件需要使用固有內容時,我們可以跳轉到引導程序中的固有內容。
在從源代碼構建引導程序和固件后,你可以通過這個命令查詢到目標。
nm -S --size-sort -t d bin/token | grep -i " t "
這里命令包含了一些在引導程序和固件中相同的有趣符號,不要驚訝,這三個符號都是編譯器的內聯函數。
134228637 00000124 T memcpy
134228761 00000140 T memset
134228357 00000266 T __udivsi3
要使用我們隱藏起來的惡意代碼,我們必須掛鉤(hook,可以理解為是一種通過更改程序的數據結構或代碼結構從而改變程序運行路線的一種方法)到其他函數。我們通過在我們想要定位的函數中插入有我們惡意代碼的分支來實現這一點。我們需要掛鉤到發送內存內容給安全元件檢查的函數,從而讓它發送正確的引導函數而不是我們的惡意代碼。
我也會選擇掛鉤到屏幕顯示函數,從而我們可以實現各種有趣且令人興奮的功能。我稍后將要講述這個漏洞。
用這兩個掛鉤和__udivsi3做為我們的攻擊向量(attack vector,指的是黑客用來攻擊計算機或者網絡服務器的一種手段),我們使用的漏洞有點像這樣:
?
作者使用的漏洞示意圖
這種方法可以釋放258個字節的有效載荷,那么即使我們將memcpy函數和memset函數放入載荷中,我們也必須對代碼占用的空間進行優化。
執行攻擊
我們的有效載荷需要兩個部分:
1.修改發送給安全元件內存內容的代碼,用以欺騙驗證過程。
2.對鍵盤生成器和密鑰生成后門的攻擊,對我而言,我更偏向于添加后門。
我們利用的漏洞并不能騙過安全元件,那么我們該如何添加后門呢?
Ledger的安全元件固件含有一個管理設置的用戶界面程序,供配置信息的進程(生成恢復種子的地方)調用。
如果能修改這個用戶界面,我們就可以在配置信息的進程中篡改恢復種子,這種操作十分簡單,因為用戶界面是開源的,并且在Ledger的架構設計中,你是可以修改它的。
在正常情況下,設備會顯示一個“用戶界面不是官方的”的警告,細心的用戶會注意到這個警告。
但回想一下,我剛才說過我們還可以篡改顯示器控制函數,這樣我們就可以輕而易舉地隱藏這個警告。
為了更好地講解原理,我并不會介紹黑客常用的一些手段,比如控制設備產生一個看起來是隨機的,但完全可預測的恢復種子。我會講一些更具體的操作。

如果你熟悉C語言,你會注意到我把隨機數生成函數換成了一個信息熵為0的隨機數生成函數。
正如你在開始視頻中看到的那樣,它會生成一個恢復種子,其中前23個字被丟棄(最后一個字不同,因為它是校驗和)。
由于私鑰來源于恢復種子,那么只要你控制了恢復種子,你就掌控了比特幣硬件錢包所生成的所有比特幣賬戶。
如果我們把上述內容放在一起,我們會得到下面這個我認為很簡潔的攻擊。
?
作者使用的攻擊方法示意圖
當然,由于安全元件誤以為微控制器正在運行官方固件,檢查是通過的。正如我之前提到的,這個過程完全不需要篡改硬件。
?
?
由于黑客控制了可信任的顯示和按鈕,從比特幣硬件錢包中發現并刪除我們的惡意代碼十分困難。
Ledger該如何修復漏洞
Ledger設計的體系架構帶來很大的問題,只有改變體系架構,才能修復這個漏洞。
Ledger試圖采用多種阻斷措施來阻止黑客使用此漏洞攻擊。
首先,Ledger優化并重新設計了微控制器的固件。具體來說,新的固件調用引導程序中的函數,而不是之前的直接復制,雖然這樣可以防范特定的攻擊方式,但據我所知,這個改動并不是天衣無縫的,還有很多攻擊方法可以攻破微控制器。
其次,在安全固件要求檢查微控制器的內存內容時,會為其定時。這是為了防止惡意代碼使用壓縮算法而設計的。它還可以防止計算機通過USB接口提供代碼。
但是,值得注意的是,安全固件運行的頻率為28MHz,而它要監控的對象——微控制器運行速度高達80MHz,這引發一個問題,一個較慢的芯片是否能對一個較快的芯片準確計時,以防止它執行額外的代碼,尤其是考慮到他們之間僅靠慢速的UART通信。
Ledger拒絕向我提供更新的固件,所以我不能去驗證這些阻斷措施如何解決問題,但是這里有一個很重要的問題。
是否真的可能通過使用計時策略和“難以進行壓縮”的固件組合來確保模型中的安全性呢?
小插曲:我與Ledger的互動
在計劃披露此漏洞之前,我曾和ledger的首席執行官進行過一些交流。你可以在這里找到我們交流的歸檔副本。
在這些評論中,我和Ledger的CEO爭辯這些攻擊是否至關重要,一些來自Ledger的評論十分主觀,也有一些很客觀,下面我將討論一些評論。
我第一個想談到的評論是,使用這個漏洞需要滿足一系列苛刻的看似不可能的條件。
Saleem(作者本人)報告的漏洞需要在設置恢復種子前物理訪問比特幣硬件錢包,安裝一個篡改后的微控制器固件,還需要在用戶的計算機上安裝惡意軟件并由用戶確認交易。
我很困惑這條評論來自哪里?從后來與Ledger的聯系中,我被告知,當他們在Reddit上發表這些評論時,CEO對漏洞根本不知情。
正如我在文章開頭中所說的那樣,有三種方法可以利用這個漏洞,沒有哪種方法需要滿足那些極其苛刻的條件。
我之前提到的惡意軟件攻擊很好的引出了我和Ledger的CEO交流的過程。
我們并沒有把這個漏洞認定為“重要安全更新”,并且決定對他的觀點不予理睬時,Saleem明顯感到不安。
實際上,當你解決嚴重的安全問題時,你有以下兩種選擇:
這是一種避免引起黑客關注的有效方法,尤其是Ledger現在面對的產品并沒有開源的情況。
但這有個缺點,大多數用戶不會去更新。就拿windows 10來說,有多少人千方百計地去關閉自動更新,更何況是更新比特幣硬件錢包。
這通常用于開源軟件,或者是當開發商發現嚴重漏洞已經危害到系統安全時。
然而,這樣做也有缺點,因為開發商對漏洞的預警會引起黑客的關注。因此,用戶必須立即更新與黑客爭分奪秒以搶占“先機”。
而Ledger使用了并不穩妥的做法,它集合了這兩種方法的缺點。Ledger把注意力集中在開發修復漏洞的固件安全性更新,但是他們并不提醒用戶更新,用戶也就失去了與黑客競爭的“先機”。
Ledger的做法給了黑客充足的時間來研究并利用漏洞,從而增加了用戶被惡意攻擊的風險。
我的擔憂并不是多余的,我已經聯系了多位獨立的白帽,他們都從Ledger發布的固件更新說明中實行逆向工程,發現了這個漏洞。
附錄:漏洞披露時間表
2017年11月11日:我正式向Ledger的CEO報告漏洞,然而Ledger方面并沒有采納我的報告。
2017年11月14日:我用代碼實現了用篡改的微控制器固件和用戶界面來實現供應鏈攻擊,并將源碼發給了Ledger的CEO。
2017年12月30日:通過篡改Ledger Nano S比特幣硬件錢包的固件,我黑掉了Nano S。
2018年3月6日:Ledger發布Nano S的固件更新。
2018年3月20日:我正式發布本文,披露漏洞。
截至發文時,Ledger Blue的固件更新還沒有發布。