物聯網終端安全入門與實踐之玩轉物聯網固件之解密篇
0x01 背景
想象一下以下場景,當你跟隨我們的《物聯網終端安全入門與實踐》系列文章學會了多種獲取固件的方法,甚至忍痛將自家路由器拆了掏出了固件之后,正雄心勃勃準備繼續學習提取文件系統、仿真時,發現一向滿腹經綸的binwalk竟然啞火,它沒有輸出任何你期待的信息。別擔心這可能不是你的binwalk壞了,一般情況下是這個固件格式和內容超出了它的理解范圍,簡單理解就是固件被廠商作了加密處理。
隨著物聯網的飛速發展,越來越多的設備被曝出存在大量的安全問題,這不僅給整個網絡環境以及用戶帶來較大的安全隱患,更給廠商能否獲取較好的品牌口碑帶來足夠大的挑戰。為此,越來越多的廠商都會給自家設備發布加密固件來對抗一些存有惡意目的攻擊者的分析和研究。
0x02 固件的常見加解密方法
在正式動手對固件進行解密之前,我們需提前了解廠商一般會以怎樣的形式發布加密固件以及在設備啟動和固件升級過程中,會在哪些地方對固件進行解密,從而思考實現解密的邏輯和方法。
2.1 從固件發布場景定位解密方法
廠商發布加密固件一般有以下三種場景:
固件出廠時未加密,后續發布包含解密程序的未加密過渡版本,隨后發布加密固件
固件出廠時加密,后續發布包含新版解密程序的未加密過渡版本,隨后發布使用新加密方案加密的固件
固件出廠時加密,后續發布包含新版解密程序的加密版本(使用舊版本加密方案加密),隨后發布使用新加密方案加密的固件
2.1.1 固件出廠未加密后續發布包含解密方案的未加密固件
固件在出廠時未加密,也未包含任何解密代碼,后續為了發布加密固件,會提前發布一個包含解密程序的未加密版本作為過渡版本,這樣后續發布加密固件時可使用該解密程序進行解密,這類情況在發布時間較早的設備中比較常見。
對于此種情況,可尋找固件過渡版本v1.1,從中分析出所包含的解密邏輯和算法,從而實現對后續加密固件的解密。因為用戶無法從v1.0直接升級v1.2的固件,所以在官方的固件發布描述中,一般會存在如下圖所述的描述。
2.1.2 固件出廠加密后續發布包含新版解密方案的未加密固件
固件在出廠時加密,廠商決定更改加密方案并發布一個未加密的轉換版本v1.1,其中包含了新版本的解密程序,這樣后續發布加密固件時可使用新版本的解密程序進行解密。
以過渡版本v1.1作為分界線,我們分別對其前后版本固件的解密進行說明。
對于v2.0及更高版本的固件即過渡版本之后的固件(假設都使用同一種加密方案,無其它過渡版本):與上述場景1中描述的一致,可以通過尋找過渡版本v1.1,從中分析出v2.0的解密方法從而對v2.0固件進行解密
對于v1.0及更低版本的固件即過渡版本之前的固件(假設都使用同一種加密方案,無其它過渡版本):一是可購買實體設備,通過設備的調試接口或管理服務等直接從設備中提取解密后的固件。二是需設法獲取內容完整的固件,直接對加密的固件進行分析,尋找包含在其中的解密算法。第三種方法則比較取巧,需要歷史版本固件存在RCE漏洞可以獲取到設備的Linux Shell,從而分析其固件升級邏輯獲取解密算法。
說明:對于上述方法沒有絕對的優劣勢,需根據具體情況進行選擇,對于有條件的小伙伴,推薦購買相應實體設備,一是有幾率通過調試接口或管理服務等直接從設備上dump出解密后的固件,二是能從Flash中提取出包含解密方法的完整版固件,以便于后續的分析。
2.1.3 固件出廠加密后續發布包含新版解密方案的加密固件
固件在出廠時加密,廠商決定更改加密方案并發布一個包含新版本解密程序的加密固件,這樣后續發布加密固件時可使用新版本的解密程序進行解密。
此類場景發布的固件自始至終都是加密形態存在的,與上述場景中v1.1及之前的固件類似,常見的解密方法有3種,具體情況得具體選擇。
2.2 設備啟動流程中的加解密邏輯
接下來我們從設備啟動流程來描述下固件的加解密邏輯。
首先我們來看看設備的啟動流程:
- 設備上電后,加載芯片中的BootROM程序(芯片廠商固化在CPU中的程序)到SRAM(片內RAM,一般較小)中運行
- BootROM加載SPL程序(二級引導程序,可用于初始化片外更大的RAM以提供系統運行環境)到SRAM中運行
- SPL加載BootLoader到片外RAM中運行
- BootLoader隨即引導內核啟動
- 內核隨后完成對文件系統的加載,執行啟動腳本完成設備的最終啟動
上述的啟動過程包含BootROM、SPL、BootLoader、Kernel、FileSystem五大部分,其中BootROM是由芯片廠商固化在芯片內的程序,設備廠商一般無法自定義,其余四塊內容廠商都可進行定制,但對SPL進行加密的場景沒有見過,這里不加以贅述。下表展示了常見情況下固件中的某塊數據被加密后解密方法可能存在的位置:
類型 | 特點 | 被加密后由哪塊數據負責解密 |
FileSystem | 廠商核心數據 | 一般由BootLoader或者Kernel負責解密 |
Kernel | 開源、可定制 | 一般由BootLoader負責解密 |
BootLoader | 開源、可定制 | SPL負責解密(SPL不能過大,難以植入復雜的解密邏輯) |
2.3 固件更新流程中的加解密邏輯
接下來我們從設備固件升級流程來描述下固件的加解密邏輯。
固件更新流程如下:
- 用戶本地上傳固件或者設備聯網下載新版固件存儲到設備Flash中
- 判斷負責處理固件更新的后臺服務是否存在解密的功能a.(常見情況)如果有解密功能,則后臺服務執行解密邏輯對固件進行解密,即當前文件系統中會存在解密邏輯代碼b. 如果后臺服務不負責對固件進行解密,則會在后續重啟過程中由BootLoader或Kernel進行解密
- 設置Boot標識位后重啟設備
- 運行新版本固件
從固件的更新流程中我們知道對固件的解密有2種情況,但由后臺服務調用解密邏輯進行解密是比較常見的,所以在拿到文件系統后,如果想分析其解密邏輯以實現對其它版本固件的解密,可以從設備的固件更新功能入手來定位解密邏輯。
2.4 常見解密方法總結
從上述固件的發布場景、設備的啟動和固件升級流程中,我們發現固件的加密情況有很多種,廠商會根據設備性能、應用場景、預算等多個條件來選擇適合的加密方式,某些對安全性要求較高的產品如工控設備等往往還會采用硬件加密的形式,將解密算法存儲在單獨的芯片中,強行讀取會導致芯片損壞。(PS:在本文中我們只講述了一些常見的解密方法和技巧,大家有更好的想法或方法歡迎在評論區留言交流)
針對物聯網終端設備的固件解密,我們總結了如下五種方法和技巧:
基于老版本未加密固件中的解密程序實現新版本加密固件的解密
對于固件出廠時未加密,后續發布的固件是加密的情況,可以通過對比邊界版本,解包最后一個未加密版本逆向升級程序還原加密過程,以實現對加密固件的解密。
基于調試串口直接提取未加密固件
如果設備存在UART、JTAG等調試接口,可通過連接硬件接口獲取設備的Shell,從而dump出設備的固件。
對于可直接進入Linux Shell的情況,具體的操作可參考我們之前發布的《物聯網終端安全入門與實踐之玩轉物聯網固件(上)》一文。
但由于某些設備安全限制較高導致無法進入Linux Shell,我們可嘗試進入BootLoader Shell(最常見的是Uboot Shell)對固件進行提取。這里要說明的一點是部分設備更新固件后會將解密后的新版固件寫回Flash,這種情況下dump出的固件是未加密的,而相反的是部分設備Flash中的固件一直是加密狀態存在,只是在每次設備啟動時進行動態解密。所以此種方法提取出的固件可能也是加密的,但好處在于可以避免因拆解設備Flash去讀固件導致設備損壞的風險,并且可以獲取到較為完整的固件(官方下載的固件可能只是某塊數據的更新包)。
基于管理服務獲取設備Shell提取文件系統
對于有Telnet、SSH等服務的設備,可以通過這些服務進入設備的Linux Shell進行固件提取。服務一般在設備的web管理頁面中可手動開啟,但需要說明的一點是某些廠商會開發自家的CLI屏蔽掉底層Linux Shell,連接這些服務進入的Shell只是廠商的CLI,也無法提取文件系統,不過某些設備(光貓居多)的CLI存在可進入Linux Shell的命令,具體可自行在互聯網上搜索相應的方法。
基于低版本固件RCE漏洞獲取設備Shell分析解密邏輯實現對新版固件的解密
如果設備歷史加密版本固件出現過RCE漏洞,可將存在漏洞的固件刷入設備,通過RCE漏洞獲取設備Linux Shell,再分析其包含的解密邏輯,最終通過該解密邏輯實現對更新版本固件的解密。需要注意的是存在RCE漏洞版本的固件所使用的加密方案需要與新版本固件一致。
直接分析完整固件中包含的解密邏輯實現對固件的解密
常見情況下固件的解密邏輯肯定是存在Flash中的,當獲取到完整版固件(拆機從Flash讀取或者從BootLoader Shell中提取等)后,可以直接對整個固件進行逆向分析尋找解密邏輯代碼實現對固件的解密,但此種方法難度較大,并且這類設備安全性一般較高,很有可能分析出了解密邏輯但拿不到解密密鑰,如密鑰單獨存放在某個安全芯片中。
0x03 解密實戰
本章首先講述一些判斷固件是否被加密或壓縮的方法,之后通過兩個實例講解不同場景下如何對物聯網設備固件進行解密,由于篇幅限制,這里僅對上述解密方法中的其中2種輔以實例講解,另外兩種網上均有不錯的分析文章,文末也會推薦相應的文章供大家學習。
3.1 判斷固件是否被加密或壓縮的方法
對于存在過渡版本的固件,可以通過閱讀廠商所發布固件的Notes關鍵信息,能夠幫助我們判斷固件從哪個版本開始進行加密。
查看固件的熵值進行判斷,熵是對隨機性的一種度量,它的值在0到1之間,值越高表示隨機性越好,接近1的值被認為是高熵,反之亦然,壓縮或加密的數據具有較高的熵值。我們可以通過binwalk -E以圖形化的形式查看加密和未加密固件熵值的變化,如下圖1中未加密的固件熵值存在較大波動,而下圖2中加密的固件熵值基本都保持在1。
3.2 實例一:DrayTek Vigor2962固件解密
3.2.1 多角度嘗試解密
一般拿到一個加密固件后,我們可以先從多個角度對其進行分析,不要急于購買設備或者拆解設備,或許互聯網上就存在著你要想的那個key。
- 對官網下載的固件解壓以及使用binwalk解包均失敗,查看熵值一直保持1,遂判斷固件加密。從廠商官網和其他渠道也未發現疑似過渡版本的固件,判斷此設備出廠時固件就已是加密形態存在。
- 在互聯網上嘗試搜索公開的文章或工具也無果。
- 為了更好的進行解密,購買一臺實體設備。
- 掃描設備開放的端口,發現開啟了Telnet和SSH服務。
- Telnet連接上后,發現是個自定義的受限CLI,嘗試使用$(telnetd -l /bin/sh -p 2323)盲測失敗。SSH登錄后也是相同的情況,從Telnet、SSH獲取Linux Shell的路也被堵死。
- 互聯網搜索該設備的歷史漏洞,但也一無所獲,無法通過歷史RCE漏洞獲取Linux Shell。
- 沒辦法只能拆解設備,發現存在UART串口,連接UART串口后啟動設備進入的是一個Console Shell,無法進入Linux Shell,只能從里面獲取一些日志和進程信息,不能提取解密后的文件系統。
3.2.2 Uboot Shell提取固件
- 于是嘗試從Uboot Shell中進行固件提取,重新啟動后快速按任意鍵進入Uboot Shell。
- 查看Uboot Shell中支持的命令。
- 這里考慮將存儲分區中的文件加載到內存后,再進行讀取。使用printenv打印一下Uboot環境變量,發現了一些關鍵信息,rootfs.uboot.img存儲在eMMC的分區2中。
什么是eMMC?
eMMC ( Embedded Multi Media Card) 采用統一的MMC標準接口, 把高密度NAND Flash以及MMC Controller封裝在一顆BGA芯片中。針對Flash的特性,產品內部已經包含了Flash管理技術,包括錯誤探測和糾正,Flash平均擦寫,壞塊管理,掉電保護等技術。用戶無需擔心產品內部Flash晶圓制程和工藝的變化。同時eMMC單顆芯片為主板內部節省更多的空間。
簡單地說,eMMC=Nand Flash+控制器+標準封裝
這里介紹以下Uboot Shell中常見的操作eMMC的命令:
常見的TypeID對應的文件系統如下表:
查看所有分區中的文件內容,發現rootfs.uboot.img的確存在分區2中。
分區1 | |
分區2 | |
分區3 | |
分區4 | 交換分區,無法查看 |
分區5 | |
分區6 |
- 由于需要提取的文件系統存在于eMMC存儲(一種NAND存儲)中,所以需要先將其加載至內存中,再將數據讀取保存。
在Uboot Shell中將eMMC的某分區中的文件讀到內存中某個地址的方法如下:
從加載的地址處讀取固定大小數據的方法如下
這里有個問題就是內存中讀到了數據,如何保存?
嘗試將數據保存到U盤上,提示報了Unsupported feature metadata_csum found, not writing.Uboot下ext4分區不支持metadata_csum和64位特性。
通過記錄日志的形式:由于我們使用的是Xshell連接的串口,而Xshell自帶了日志記錄功能,所以需在使用md命令讀取內存中數據前將日志啟動,讀取完成后將日志中記錄的十六進制字符串轉為二進制程序即可。
注:由于波特率只有115200,傳輸速度較慢,需要掛機跑一晚。
- 使用上述方法,我們最終將分區6中的image.sav文件(分區5下的uffs目錄下v2962_ram_flash.bin文件無法讀進內存中)從設備中dump出來,發現固件并未加密,使用binwalk可直接進行解析。
3.2.3 固件解密邏輯的分析
這里說明下為什么拿到文件系統后還需要進一步分析其解密邏輯:
官網固件是加密的,想要分析其它版本的固件,需刷入所需版本的固件后按照上述方法進行提取
由于波特率較低傳輸速率慢,單次提取耗時較長,我們花費了幾乎1晚的時間,才完成了Vigor 2962某版本未加密固件的提取
分析出解密邏輯,可以直接使用該解密方法實現對其它版本固件的解密,這種以點帶面的解密方法的使用,節省了大量的固件解密時間/設備采購成本
- 使用Binwalk解出來的ext文件系統不全。
- 嘗試使用掛載的方式,掛載文件系統mount 0.ext ./ext-root,發現能正常獲取ext文件系統下的所有文件。
- 嘗試在文件系統下搜索字符串decrypt,發現存在一個名為decrypt_firmware的函數,該函數存在于fw_upload腳本中,根據命名推測該腳本用于處理固件更新。
- decrypt_firmware函數實現如下,分析其邏輯,發現chacha20應該就是解密程序,理論上只要按照該函數中解密的命令進行執行即可完成解密。
- 由于要執行chacha20程序,理論上由于異架構問題,需要仿真運行,而qemu-user模式不支持arm64,只能使用qemu-system模式。但是在實際操作過程中發現使用chroot切換文件系統根目錄后也可以執行。
- 最終我們對官網下載到的最新版固件也能進行解密。
3.2.4 小結
針對DrayTek Vigor2962固件的解密,首先嘗試尋找過渡版本以及互聯網搜索公開的解密方法未果,之后嘗試通過自帶的SSH、Telnet服務以及歷史RCE漏洞獲取Shell均未成功。之后,拆機連接UART串口也無法獲取到Linux Shell。最終,利用Uboot Shell dump出eMMC分區中的未加密固件,繼而分析其解密邏輯,實現了對Vigor 2962最新版本固件的解密。
3.3 實例二:飛某星VW1900設備固件解密
由于我們已有實體設備,且已掌握該設備某版本固件的RCE漏洞,所以刷入低版本固件后,通過漏洞能夠獲取設備Root Shell,進而深入分析其解密邏輯。
該實例著重講解在此種場景下定位解密程序、分析解密邏輯的方法,以實現對更高版本固件的解密。
3.3.1 定位解密程序
- 由于我們可以獲取到設備的Shell,因此我們可以通過固件升級時的一些接口信息定位后臺中用于處理固件更新的具體服務。
- 通過BurpSuite攔截設備自動升級包。
但發現固件升級失敗了。
- 嘗試攔截手動上傳的固件更新包。
發現更新固件時調用的后臺接口是一個名為manual_update.cgi程序。
- 在Shell終端中搜索該接口名,發現該接口功能在webserver程序中實現。
Ghidra加載該程序定位具體字符串,發現設備的更新功能主要在函數FUN_0001e9a8中實現。
分析該函數的具體實現邏輯,首先從NVRAM中讀取CPU_TYPE,根據不同值執行不同的腳本。
為了分析其具體執行流程,獲取設備Shell后,讀取nvram中相應的值,發現CPU_TYPE=bcm4708。
之后處理固件上傳的POST請求,將加密的固件寫入/mnt/code.bin文件中。
隨后執行如下系統命令對固件進行解密,從命令中可看出/usr/bin/rc5-update應該就是固件的解密程序。
直接在設備上測試該方法驗證我們的分析結論,發現可以成功解密。
外傳解密后的固件,使用binwalk可直接進行解包獲取完整的文件系統。
3.3.2 以點帶面解密其它版本固件
至此,我們已經知道rc5-update是解密程序以及使用方法,所以針對其它版本固件的解密,有兩種思路:
直接使用程序對固件進行解密,這種方法是最簡單的,這里需要注意程序的架構問題
分析rc5-update中的解密算法,自己編寫代碼實現。由于程序包含解密算法,需要有一定的逆向分析功底
3.3.2.1 局部仿真調用解密程序
由于該設備是arm架構的,rc5-update無法直接在除arm架構之外的主機上運行,但可以通過局部仿真的方式運行該解密程序實現對其它版本固件的解密。具體的仿真原理和方法可參考上一篇文章。
- 局部仿真解密當前版本固件成功。
- 局部仿真解密最新版本固件成功。
3.3.2.2 逆向解密算法
- 讀取內置在解密程序中的一個31字節數組數據,經過計算得出一個20字節的數組作為密鑰的第一部分。
- 該程序提供加密和解密功能,使用不同的參數進行區分。
- 讀取加密固件的前10字節數據作為密鑰的第二部分拼接在第一部分后面,最終根據這30字節的數組生成一個1056字節大小的最終密鑰數組,之后循環讀取加密固件,每8192字節作為一個block進行解密。
- 我們使用代碼還原整個解密算法,最終能成功對加密的固件實現解密。
3.3.3 小結
該實例主要講述了在拿到解密的固件后,定位解密邏輯以及分析解密算法的思路,最終通過局部仿真和自己實現解密算法2種方法實現了對其它版本固件的解密。
0x03總結
本文從設備固件的發布場景、設備的啟動流程以及固件升級流程等多方面描述了物聯網終端固件常見的加解密方案,總結了5種常見的解密方法,之后詳細講述了運用其中2種方法實現解密的實例。由于篇幅的限制,另外幾種解密方法本文沒有給出具體的例子,文末會貼出相關的參考鏈接。
參考鏈接
【1】尋找過渡版本實現解密 https://payatu.com/blog/munawwar/solving-the-problem-of-encrypted-firmware
【2】直接分析完整版固件實現解密 https://cloud.tencent.com/developer/article/1005700
【3】https://www.freebuf.com/articles/endpoint/254257.html