作者:lylemi
原文鏈接:https://blog.lyle.ac.cn/2021/07/09/uemu/
0. 引言
對物聯網設備中的應用程序進行模糊測試時,直接使用實體設備進行測試是一種比較直接的方法,但是實體測試會帶來較高的測試成本,也無法自動化地對待測目標進行測試。考慮到實體設備測試面臨的限制,使用虛擬化技術對設備進行測試是一種方案,但是直接使用QEMU仿真并不能保證成功測試目標程序,本文嘗試對其中的原因進行分析,并提出一種相對通用的解決方案模型。
物聯網設備分為多種類型,本文的測試目標主要考慮使用通用操作系統的設備,即擁有輕量級用戶空間環境如busybox、uClibc等的Linux類設備環境。在這類設備的環境中,與定制硬件進行的交互大部分是通過特定的設備驅動進行的。
本文分為幾個部分,可以按需閱讀,第一部分介紹了當前工作,說明在有firmadyne、qiling等強大的工具下為什么還需要有新的仿真工具;第二部分說明了本文解決問題的思路;第三部分對具體實現的一些細節進行說明;最后一部分基于實現完成了一些小規模的實驗,說明了本文的仿真能力。如果只是想對本文思路有簡單的了解,可以閱讀 TL;DR 部分。
TL;DR
本文提出的方法在用戶層對物聯網設備中的網絡服務進行仿真用于測試,通過對系統調用分類并在驅動層建立設備模型的思路,實現了成功率較高、相對泛用且易擴展的一種仿真方案。
1. 當前工作
1.1 仿真類型
仿真的方法可以分為四種類型:全系統仿真、用戶態仿真、應用級仿真、代碼片段仿真。全系統仿真對整個設備的操作系統進行仿真,運行操作系統的所有組件。用戶態仿真,也可以稱作進程級仿真,最常見的仿真方式就是使用chroot改變根目錄到固件文件系統的目錄下,并使用仿真工具的用戶模式執行待測程序。
應用級仿真是指并不執行程序,而是僅僅加載網絡應用對應頁面的方式。最簡單的應用級仿真是直接用對應架構的操作系統系統,將網頁文件復制出來,使用常用的網絡服務啟動。但是這種方式會丟失過多的細節,另外很多固件使用了自定義的腳本語言函數來獲取硬件配置的信息,因而通過這種方式只能對HTTP服務進行仿真,且只能檢測相當有限的漏洞類型,例如命令注入、跨站腳本攻擊等。
代碼片段仿真則只執行二進制文件中的一部分代碼,使用Patch、預設數據等方式使得代碼可以正常執行。
1.2 仿真工具
在目前,需要仿真這類設備時,通常使用的工具為QEMU、Unicorn等,在這些工具之上有Firmadyne、Qiling等相對完善的框架。QEMU提供用戶模式和系統模式兩種運行方式,用戶模式主要用于執行不同處理器的Linux程序,系統模式用于模擬整個系統運行環境,包括CPU及其他設備,使得系統級的測試更為方便。
在QEMU的基礎上,Firmadyne傾向于對整個系統進行仿真,主要考慮解決QEMU在仿真物聯網設備時遇到的難點。Firmadyne以系統級仿真為基礎,使用定制動態鏈接庫完成庫函數劫持支撐NVRAM設備調用,基于定制內核完成操作系統啟動、探測網絡結構、虛擬硬件,通過系統配置完成網絡構建,最后調用QEMU仿真異架構操作系統完成仿真。
但是Firmadyne的方法存在一定的局限性,在Firmadyne獲取的23035個固件中,其中8617個固件可以成功解包,在解包成功的固件中有8591個固件能夠成功啟動系統,成功啟動系統的固件中只有2797個可以成功配置網絡,最后只有1971個固件可以訪問網絡。在所有能解包的固件中,僅有22.9%的固件可以通過網絡訪問,即可以對其進行測試。根據Firmadyne論文中的解釋,不能成功仿真主要是因為提取固件失敗、NVRAM仿真失敗、網絡設備仿真失敗等原因。
Qiling提供了非常強大的跨平臺與跨架構的二進制仿真能力,可以對二進制文件或者代碼片段進行仿真,可以進行自動化patch。但是并不是物聯網設備專用的工具,在仿真設備時仍需要一定的手動分析。
雖然當前工具已經解決了很多問題,但是但是在測試目標上仍然有局限性。如果要對型號多樣的物聯網設備進行測試,需要找到一種較為合適的仿真方式。在已有工具的基礎上,本文嘗試提出一種仿真成功率高、更容易調試與擴展的方案,可以更簡單的對物聯網設備中的二進制文件進行仿真,從而進行測試。
2. 問題分析與解決
2.1 面臨挑戰
比較泛泛的講,物聯網設備難以仿真的主要原因是運行環境復雜,設備由很多不同廠商生產,僅路由設備常見的廠家就超過四十余家。而各個廠商會提供不同系列和型號的產品,不同產品又使用各種不同的硬件、指令集架構、操作系統、網絡協議。其中部分產品依賴自研的外部設備,部分產品會對操作系統進行深度自定制,網絡協議可能會有自研的通信格式,最后衍生出復雜的軟硬件依賴問題。尤其是物聯網設備的自研部分往往是閉源的,各個廠商對協議、外部設備有不同標準和實現,這些非標準的協議和設備實現多不公開,繼續加大了仿真的困難程度。
更具體來說,可以把二進制程序的執行分為兩部分,用戶態和內核態。用戶態的指令可以由通用的仿真工具來翻譯執行,而最終進入內核態的系統調用需要進一步構建執行環境解決。也就是說,仿真要解決的問題實際是如何執行系統調用的問題。
而在具體的仿真方案選擇上,全系統仿真引入了不必要的復雜性,應用級仿真缺少細節,代碼片段仿真更適合測試一部分功能或調試漏洞,因此本文的目標是通過構建合適的系統調用模型來在用戶態執行物聯網設備中的二進制程序。
2.2 解決模型
系統調用有很多種分類方式,其中一種分類方式是將系統調用分為進程控制、文件管理、設備管理、信息維護、通信、保護六大類,本文在這個分類的基礎上繼續對問題進行解決。
進程控制類系統調用主要用于完成創建進程、終止進程、載入與執行進程、獲取進程屬性、等待時間事件與信號、申請與釋放內存等功能。文件管理類系統調用主要用于完成創建刪除文件、打開關閉文件、讀寫文件、讀取或設置文件屬性等功能。設備管理類系統調用主要用于完成獲取與釋放設備實例、讀取或設置設備屬性、掛載或卸載設備等功能。信息維護類系統調用主要用于傳遞信息,例如當前的事件、日期、用戶數、操作系統版本、內存或磁盤信息等。通信類系統調用負責進程間通信,實現常用的消息傳遞模型和共享內存模型等功能。保護類系統調用負責設置資源權限,用于允許和拒絕用戶訪問特定資源。
其中信息維護、通信、保護間通信三類系統調用宿主機可以較為容易的支撐,而其他幾類系統調用在從模擬器環境向宿主機環境轉發時則存在如下圖所示的幾個需要解決的問題。

2.2.1 文件管理
進程在執行時,會需要進程本身的可執行文件、可執行文件對應的動態鏈接庫文件、用于配置程序的配置文件,以及用于寫入臨時文件、日志文件、進程當前信息的目錄等文件與目錄環境。在仿真時通常會通過加載原本固件的文件系統的方式來構建文件系統的運行環境,但是在由于設備固件并不遵循統一的標準,提取出的文件系統可能并不完整,會存在部分文件無法找到的情況。另外,有的文件由設備在運行時動態創建,簡單的文件系統提取并不能獲取對應的文件。
2.2.2 設備管理
物聯網設備通常需要大量的外部硬件設備參與運行,主要是運算與控制設備、網絡設備、存儲設備與輸入輸出設備。模擬器僅對常見的硬件設備進行了支持,其中包含了運算與控制設備、部分內存與磁盤設備、部分輸入輸出設備。但是物聯網設備中存在著大量的定制外部設備,如定制的NVRAM、Flash存儲設備、網絡設備等,在執行到和這些設備相關的系統調用時,可能會面臨缺少輸入輸出設備與網絡設備,設備的硬件調用宿主機不支持等問題。
2.2.3 進程控制
待測的可執行程序和宿主機大多是不同架構的,需要通過模擬器執行。而在通過用戶態模擬執行新的程序時,由于系統調用被轉發到了宿主機,宿主機將以正常的進程加載方式加載程序,但是不同架構的程序在默認場景下并不受宿主機支持,此時程序無法被執行,父進程報錯終止。
3. 具體實現
3.1 系統調用劫持
系統調用劫持主要是基于ptrace控制系統調用,在一些檢查環境的系統調用處實現控制,獲取相關信息的同時屏蔽一些不重要的報錯,使得程序可以正常運行。

基于ptrace的方案的缺點在于性能消耗較高,每次系統調用都需要有對應的邏輯判斷。為了減少這種消耗,在長期測試時可以根據收集到的信息生成對應的內核模塊代碼,編譯為內核模塊,在后續需要屏蔽、修改部分系統調用或用戶態調用的情況下,使用基于Linux內核模塊控制系統調用的方案完成持久化。
3.2 設備文件系統重建
進程運行所需要的文件主要是進程本身的可執行文件與對應的鏈接庫文件,系統的設備與配置文件,進程的配置文件與進程在運行時產生的進程信息、日志文件、臨時文件幾種類型的文件。其中從固件提取出的文件系統包含有可執行文件、動態鏈接庫文件、操作系統的配置文件,正常情況下,操作系統在啟動后會創建系統的設備文件、用于寫入日志文件的目錄與各個程序的配置文件。
滿足文件依賴從下至上分為四個層次來對缺失的文件進行補全,第一層掛載固件文件系統,這一層是執行的基礎;第二層根據運行時信息動態創建缺失的文件,這一層在可執行文件的基礎上創建部分所需的文件;第三層覆蓋特定的系統配置文件,這一層用于對配置進行歸一化方便進行后續的測試;第四層是根據對指紋、配置文件的解析創建應用對應的配置文件,這一層是在之前的基礎上進行細節的修正,保證待測程序可以正常運行。
用于掛載的文件系統來自于之前通過解包固件獲取的文件系統,主要包括可執行的二進制文件與對應的動態鏈接庫。
動態創建的文件主要是本應在Linux系統啟動時創建的文件,主要是 var 目錄下的多個子目錄與文件,proc、sys、dev等目錄,這些文件與目錄在待測程序啟動前進行通過宿主機進行創建或掛載。
之后覆蓋系統基本的配置文件,這類文件可能存在于固件中或不存在,但是格式都是已知的。系統基本的配置文件包括passwd、shadow等用戶相關的配置、DNS服務器等網絡相關的配置,還有TZ、localtime等時間相關配置。因為固件生態的多樣性,這些文件可能存在自定義的部分,為了測試環境的統一化,本文使用預置的系統配置文件對這些文件進行覆蓋。
最后一部分是動態運行所需要的內容,主要是不同類型的服務需要不同的配置文件,同一類型不同實現的服務也需要不同的配置文件,這些配置文件往往是根據設備狀態動態創建出來的,并不存在于固件中。不同類型的服務器例如DNS服務啟動所需要的dnsmasq.conf,PPTP服務啟動所需要的pptdp.conf,SMB服務啟動所需要的smb.conf。同一類型的服務也存在不同實現,以HTTP協議為例,存在lighttpd、mini_httpd、mathopd等多個大類的實現,不同應用所需要的配置類型和位置是不同的。
對于同一類型不同實現的服務,本文根據程序的類型和當前環境動態創建配置文件,執行文件并進行測試。如果程序執行成功則保留該配置文件,如果執行失敗則嘗試其他參數與配置文件。如果預置的配置文件不能成功,則分析固件中的系統腳本,主要是初始化文件,從中找出配置文件的生成方式與程序的執行參數,并進行相應的執行來創建配置文件。
3.4 基于定制內核模塊的硬件模擬
用戶進程和硬件的交互過程如下圖所示,用戶態程序加載動態鏈接庫,動態鏈接庫根據標準用戶庫中的標準輸入輸出相關的函數構造對應的系統調用轉發到內核層,內核根據系統調用對應執行設備驅動中的代碼。

對于缺少外部設備的問題,Firmadyne的解決方案是通過自定義的用戶態動態鏈接庫在軟件層劫持相關的調用來實現。Firmadyne自定義了用戶態的動態鏈接庫,通過預加載的方式通過該鏈接庫控制對硬件的調用,當用戶態應用調用對應函數的時候,會優先調用自定義的用戶態標準庫,從而實現用戶態的NVRAM功能。
但是這種方式存在幾個問題,首先,基于劫持的方式需要了解上層應用調用的函數名稱,Firmadyne僅僅通過枚舉來解決,一旦遇到沒有在枚舉列表中的函數,運行就會出現錯誤。其次,這種方式僅支持NVRAM一種設備,可擴展性差,無法適應其他的設備。另外,對于每一種架構,這種方式都要編譯一個對應的動態鏈接庫文件,需要維護多套編譯環境。
考慮到Firmadyne的缺陷,本文主要使用定制內核模塊的方式來實現虛擬的設備。在Linux操作系統中,硬件設備也被看做文件來處理,有對應的文件標準操作。除此之外,在Linux的設計中,驅動定義的標準僅有數次比較小的修改,可以較為容易的枚舉出所有的驅動操作。具體來說,POSIX的內核驅動標準中僅定義了read、write、ioctl等數種意義較為明確的硬件操作,也在一定程度上減輕了實現的難度。本文最后根據驅動定義標準設計內核模塊,對于每一種設備,以內核驅動的方式,模擬實現文件的標準操作,通過定制內核模塊完成外部設備的軟件形式實現。
根據Firmadyne的分析,52.6%的固件都通過用戶態鏈接庫訪問了NVRAM,大部分固件的核心設備也以NVRAM為主,因此本文同樣主要關注NVRAM的實現。NVRAM可以看作一個硬件實現的哈希表,用戶可以通過鍵值對的形式向NVRAM寫入需要存儲的變量,也可以通過輸入特定的KEY值來讀取之前存儲的數據。基于NVRAM的輸入輸出特點,本文在軟件層進行了一個哈希表的實現,并完成了對應的驅動,加載驅動后,設備可以按照正常的NVRAM調用方式進行運行。和Firmadyne相比,本文的實現方式更加通用,且能夠更好的處理系統調用的情況。
在本文的實現方式下,每種設備僅需要對應實現幾個驅動的函數即可,不需要適配同一設備的不同用戶態調用。另外因為本文的硬件實現最后掛載在宿主機中,系統調用的翻譯已經在用戶態模擬完成,所以這種方式并不需要對不同的架構進行適配。
除了I/O設備之外,物聯網設備可能會依賴一些特定的網絡外設,這部分本文在基于系統調用劫持獲取信息的基礎上,創建一張對應名稱和IP的網卡,并使用橋接的方式和本地網卡連接,以用于后續的測試中。
除了IO設備與網絡設備,還有類似LED等少數附加設備,這些設備通常有專門的可執行文件控制,網絡服務程序并不直接和這些設備進行交互,對于這部分設備,本文使用前文中提到的系統調用劫持直接屏蔽對應的系統調用。
3.5 進程透明啟動
如前文中提到的,部分進程在執行時會進行execve、fork等系統調用操作,而因為本文使用了轉發系統調用到宿主機的方式,在使用這些系統調用時,進程會脫離模擬器環境,由操作系統來執行程序。
操作系統加載可執行文件時,會默認按照宿主機架構加載程序代碼,進行解釋執行。顯而易見的,宿主機在默認情況下無法處理異架構的程序,對于這個問題,本文提出了一種基于內核配置的跨架構進程透明啟動技術。
無論用戶層使用什么方式創建一個新進程,最后都會通過execve等系統調用傳遞信息至操作系統,由操作系統內核尋找對應格式的處理器來執行對應的進程。本文注冊內核的執行函數,在涉及execve、fork脫離模擬器環境時調用execve時進行判斷,如果當前載入的程序并非宿主機架構的程序,則載入對應的模擬器環境加載該程序用于執行,防止程序脫離當前定制的用戶態仿真環境執行。
關于其中具體工具的使用和配置,可以參考這篇文章 。
4. 實驗數據
為了驗證仿真工具的能力,設計了一些簡單的實驗進行測試。本文主要使用網頁爬取與FTP同步的方式,基于網頁的爬蟲自動解析廠商的固件下載頁面并下載固件;基于FTP同步的方式主要同步廠商FTP中與固件相關的文件,例如后綴是zip、bin、pkg等結尾的固件。另外考慮到實驗的多樣性,也手工下載了一些品牌的固件用作實驗。
經過爬取,本文一共得到來自46個廠商的14483個固件作為測試集,用于驗證測試模式的產生效率以及實際的測試實驗。固件數據集中比較多數的是路由設備的固件,也包含一些攝像頭、NAS的固件。固件中包含i386、ARM、MIPS、PowerPC,并有對應的32位、64位、大小端等多種不同架構。由于不同廠商對固件開放的程度不同、產品數量不同,在數據庫中部分廠商如D-Link、TP-Link等廠商的固件占了較大的比例。
總計爬取了14483個固件,其中因為文件格式沒有成功識別、解壓縮或解密錯誤、固件中不包含正常可執行文件等原因,有6495個固件不能正確解包,本文對正確解包的7989個固件進行實驗。
以應用程序為維度衡量仿真能力,本文判定應用程序是否仿真成功的標準為:使用編寫好的測試程序發送對應協議的請求報文,對應端口返回了協議對應的正確響應時,認為仿真成功,否則認為仿真失敗。
基于這個標準,本文對仿真成功的程序架構與類型分別進行了統計,在仿真成功的程序中,各個架構程序的數量如下表所示。由于有大量的固件使用了同樣的可執行文件,本文在統計中分別統計了執行成功的程序數量與根據哈希去重后的程序數量。
| 架構 | 位長 | 大小端 | 程序數量 | 去重后數量 |
|---|---|---|---|---|
| arm | 32 | big | 857 | 13 |
| arm | 32 | little | 730 | 89 |
| i386 | 32 | little | 767 | 8 |
| mips | 32 | big | 19472 | 629 |
| mips | 32 | little | 9445 | 469 |
| mips64 | 64 | big | 40 | 11 |
| powerpc | 32 | big | 60 | 4 |
在仿真成功的程序中,程序數量如下表所示,因為每個固件中存在的程序數量與類型不同,所以在表中,不同程序的數量和比例有所不同。其中部分程序對應的比例較小,這是由于不是所有固件都帶有對應的功能,例如只有小部分固件存在UPnP相關的服務程序,而大部分的固件中都存在DNS相關的服務程序。
| 程序名稱 | 程序數量 | 去重后數量 |
|---|---|---|
| dnsmasq | 7610 | 147 |
| hnap | 12 | 3 |
| httpd | 6899 | 181 |
| lighttpd | 90 | 42 |
| miniupnpd | 84 | 26 |
| smbd | 866 | 120 |
| telnetd | 7728 | 399 |
| tftpd | 144 | 43 |
| udhcpd | 7894 | 245 |
| utelnetd | 44 | 17 |
沒有仿真成功的測試程序有幾種原因,一種原因是部分程序在啟動時會對系統環境做詳盡的檢查,如檢查運行進程、檢查系統各種參數,當有一些條件沒有滿足時程序會退出,由于有一部分檢查在可執行程序內部完成,不涉及到外部的調用或函數,本系統的技術不能控制,導致本系統不能成功的仿真。一種原因是部分程序依賴的設備較為特殊,是本文尚未實現的設備,在這種條件下本文也不能很好的進行仿真。
5. 后記
5.1 本文缺陷
本文通過對物聯網設備模糊測試技術的研究,實現了對物聯網設備中的網絡應用程序進行仿真的目的。但是,本文的實現總體來說比較粗糙,有很多沒有自動化或者不完善的部分,主要作為一種仿真的思路提出以供后來的研究者參考。
5.2 模糊測試工作
在完成仿真后,要繼續的工作是對仿真成功的二進制文件進行模糊測試,在仿真的基礎上,還需要解決三個問題。即如何對網絡程序進行測試、如何獲取覆蓋率反饋信息、如何對格式敏感的程序進行測試,對應的文章會在后續放出。
5.3 開源計劃
由于當前代碼結構比較混亂、缺少文檔,目前沒有開源的計劃,如果感興趣的朋友比較多,等整理好代碼后可能會通過這個 repo 開源。
6. 參考鏈接
6.1 工具
- QEMU
- Qiling Advanced Binary Emulation Framework
- Unicorn CPU emulator framework (ARM, AArch64, M68K, Mips, Sparc, X86)
- firmadyne
6.2 論文
- Towards Automated Dynamic Analysis for Linux-based Embedded Firmware
- AVATAR: A Framework to Support Dynamic Security Analysis of Embedded Systems' Firmwares
- HALucinator: Firmware Re-hosting Through Abstraction Layer Emulation
- P2IM: Scalable and Hardware-independent Firmware Testing via Automatic Peripheral Interface Modeling
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.jmbmsq.com/1634/
暫無評論