新聞中心
本篇將系統(tǒng)性介紹終端設(shè)備固件仿真的概念、技術(shù)、工具和框架,以及手動固件仿真的過程和技巧。

0x01 背景
在漏洞研究過程中,我們會遇到若干不可控的因素影響實體設(shè)備的使用,比如:
- 目標(biāo)設(shè)備比較昂貴,采購預(yù)算不足
- 國外設(shè)備不易采購,缺乏采購渠道
- 調(diào)試過程中的設(shè)備損耗導(dǎo)致設(shè)備數(shù)量不足
固件仿真就可以很好解決以上問題,原因如下:
- 無需采購,零成本
- 調(diào)試更加靈活可控
- 突破數(shù)量限制,可無限制仿真設(shè)備
當(dāng)然,固件仿真也有不少缺點,比如:
- 固件運行環(huán)境碎片化,仿真成功率低
- 仿真設(shè)備在某些方面無法完美模擬真實設(shè)備
- 部分固件的仿真配置比較繁瑣,有一定的技術(shù)門檻
無論如何,固件仿真與實體設(shè)備之間是相輔相成、互為補充的關(guān)系,都是物聯(lián)網(wǎng)漏洞挖掘的基礎(chǔ)環(huán)境。( ps:如果不差錢,還是實體設(shè)備香?。?/p>
0x02 應(yīng)用場景
固件仿真技術(shù)可應(yīng)用于:
- 漏洞研究
- 模糊測試
- 漏洞靶場
- IoT蜜罐
0x03 概念介紹
本章梳理了仿真技術(shù)的分類分級、仿真工具和仿真框架,便于讀者系統(tǒng)性了解仿真技術(shù)的概念。
3.1 仿真概念
首先,什么是仿真?仿真是利用模型復(fù)現(xiàn)實際系統(tǒng)中發(fā)生的本質(zhì)過程,并通過對系統(tǒng)模型的實驗來研究存在的或設(shè)計中的系統(tǒng),又稱模擬。而固件仿真其實就是固件模擬運行。
那么,固件仿真可以達(dá)到什么樣的效果呢?
利用成熟的仿真工具/框架,模擬運行固件中的全部或特定服務(wù),提供與真實設(shè)備服務(wù)盡可能相似或無差別的體驗,支撐漏洞研究、靶場、蜜罐應(yīng)用。
固件仿真技術(shù)的分類有哪些呢?
目前固件仿真是主要技術(shù)分為用戶態(tài)仿真和系統(tǒng)級仿真 (將會在3.2.1 和3.2.2分別展開講解)。
在此之上,還有人提出了一些仿真技術(shù)的思想:
應(yīng)用級仿真——指并不執(zhí)行程序,而是僅僅加載網(wǎng)絡(luò)應(yīng)用對應(yīng)頁面的方式。最簡單的應(yīng)用級仿真是直接用對應(yīng)架構(gòu)的操作系統(tǒng)系統(tǒng),將網(wǎng)頁文件復(fù)制出來,使用常用的網(wǎng)絡(luò)服務(wù)啟動。
代碼片段仿真——只執(zhí)行二進(jìn)制文件中的一部分代碼,使用Patch、預(yù)設(shè)數(shù)據(jù)等方式使得代碼可以正常執(zhí)行
3.1.1 用戶態(tài)仿真技術(shù)
用戶態(tài)仿真是在宿主機(jī)上主要針對單個可執(zhí)行程序進(jìn)行的仿真,調(diào)試和運行方便,無需配置其他的環(huán)境,如內(nèi)核、磁盤映像以及虛擬網(wǎng)橋等。例如,在x86架構(gòu)宿主機(jī)上運行一個arm架構(gòu)的程序,同時可提供該arm程序的gdb調(diào)試入口。
3.1.2 系統(tǒng)級仿真技術(shù)
系統(tǒng)仿真是在宿主機(jī)上對指定架構(gòu)的操作系統(tǒng)的模擬運行(包括CPU和其他周邊設(shè)備),既可以讓單個可執(zhí)行程序正常運行,也可以支持多個可執(zhí)行程序并行。
例如,在x86架構(gòu)宿主機(jī)上模擬出arm架構(gòu)的操作系統(tǒng)環(huán)境,運行固件解包后得文件系統(tǒng)中的啟動腳本/etc/rcS(其內(nèi)部執(zhí)行了多個程序)。
3.2 仿真工具
以下講述了常用的2種固件仿真工具的相關(guān)介紹
3.2.1 QEMU
QEMU是一個通用的開源機(jī)器仿真器和虛擬化器。當(dāng)用作機(jī)器仿真器時,QEMU可以在另一臺機(jī)器(例如自己的PC)上運行為一臺機(jī)器(例如ARM架構(gòu)的操作系統(tǒng)和程序)。通過使用動態(tài)翻譯,它實現(xiàn)了非常好的性能。用作虛擬化器時,用其他VMM(Xen,KVM,etc)來使用硬件提供的虛擬化支持,創(chuàng)建接近于主機(jī)性能的虛擬機(jī)。QEMU 在 Xen 虛擬機(jī)管理程序下執(zhí)行或在 Linux 中使用 KVM 內(nèi)核模塊時支持虛擬化。使用 KVM 時,QEMU 可以虛擬化 x86、服務(wù)器和嵌入式 PowerPC、64 位 POWER、S390、32 位和 64 位 ARM 以及 MIPS 客戶機(jī)。QEMU仿真 主要使用的兩種運作模式如下:
- qemu-user:啟動不同CPU架構(gòu)的linux程序,模擬程序運行
- qemu-system:模擬包括CPU及其它外設(shè)的整個操作系統(tǒng),支持對應(yīng)架構(gòu)的多個程序在其中同時運行
3.2.2 Unicorn
Unicorn是基于qemu的CPU仿真跨平臺架構(gòu)框架,主要目的就是在QEMU之上構(gòu)建自己的工具。Unicorn 只關(guān)注 CPU 操作,可以在沒有上下文的情況下模擬原始代碼。使用Unicorn可以從 CPU 執(zhí)行到內(nèi)存訪問的各種事件注冊自定義處理程序,為程序員提供了在仿真環(huán)境下監(jiān)視和分析代碼所需的所有功能。QEMU 不能同時處理多個 CPU。相比之下,Unicorn被設(shè)計和實現(xiàn)為一個框架,以便一個程序可以在一瞬間模擬不同類型CPU的多個代碼。
3.3 仿真框架
為什么要使用仿真框架?手動仿真時需要對錯誤逐一修復(fù),耗時耗力。而仿真框架封裝并融合了仿真工具和周邊配套系統(tǒng)的能力,對已知錯誤做了內(nèi)部處理,并且進(jìn)行了仿真自動化的工程建設(shè),自動化程度比較成熟,極大提高了仿真的效率。下表列舉了一些常見或經(jīng)典的仿真框架,并對各個框架進(jìn)行了簡單的介紹。
|
框架名稱 |
底層依賴 |
框架介紹 |
|
??Firmadyne?? |
qemu |
以系統(tǒng)級仿真為基礎(chǔ),使用定制動態(tài)鏈接庫完成庫函數(shù)劫持支撐NVRAM設(shè)備調(diào)用,基于定制內(nèi)核完成操作系統(tǒng)啟動、探測網(wǎng)絡(luò)結(jié)構(gòu)、虛擬硬件,通過系統(tǒng)配置完成網(wǎng)絡(luò)構(gòu)建,調(diào)用QEMU仿真異架構(gòu)操作系統(tǒng)完成仿真 |
|
??Firmware Analysis Toolkit?? |
簡化firmadyne執(zhí)行流程的腳本 (??AttifyOS??已集成) | |
|
??FirmAE?? |
基于Firmadyne:但相比Firmadyne,提高了仿真成功率 | |
|
??Firmware Analysis Plus?? |
基于Firmadyne、Firmware Analysis Toolkit:精簡不必要組件,優(yōu)化仿真流程,優(yōu)化網(wǎng)絡(luò)環(huán)境大幅壓縮安裝時間,提高了仿真成功率 | |
|
??qiling?? |
unicorn |
由國內(nèi)京東牧者安全實驗室在2019年Defcon首次推出, 以用戶態(tài)仿真為思想,相比qemu支持更多平臺,包括Windows,MacOS,Linux和BSD的一款分析框架。(由于一直在更新,對應(yīng)demo無法運行且缺少對應(yīng)版本固件仿真說明文檔,不適合入門使用) |
0x04 仿真邏輯
本章分別講解qemu-user和qemu-system固件仿真邏輯
4.1 用戶態(tài)仿真邏輯
在宿主機(jī)環(huán)境內(nèi),chroot改變根目錄到固件文件系統(tǒng)(一個正常固件通常包含uboot、kernel和文件系統(tǒng)3部分,對固件解包就可以獲取到文件系統(tǒng))的目錄下,使用qemu-user執(zhí)行待仿真程序。
4.2 系統(tǒng)仿真邏輯
首先,在宿主機(jī)環(huán)境內(nèi)架設(shè)虛擬網(wǎng)橋,然后使用qemu-system加載內(nèi)核和磁盤鏡像啟動仿真系統(tǒng),此時宿主機(jī)與仿真系統(tǒng)間能夠進(jìn)行正常的網(wǎng)絡(luò)通信。接下來,將固件解包后提取的文件系統(tǒng)拷貝到仿真系統(tǒng)中,掛載文件系統(tǒng)到指定目錄。最后,使用chroot命令改變根目錄到固件文件系統(tǒng)目錄,運行目標(biāo)程序或腳本文件,比如 httpd服務(wù)程序、/etc/rcS啟動腳本等。
0x05 仿真實踐
本章以D-link DIR-816A2_v1.10CNB03_D77137.img固件為例,手動模擬啟動固件中的web服務(wù)goahead。注:部分仿真框架(如Firmadyne、FirmAE、FAT等)無法自動化仿真上述固件的web服務(wù)。
5.1 環(huán)境安裝
宿主機(jī)系統(tǒng):kali-linux-2022.2-amd64 工具:
- binwalk (kali已集成)
- qemu 安裝
sudo apt install qemu-user
sudo apt install qemu-user-static
sudo apt install qemu-system
網(wǎng)橋工具
sudo apt install bridge-utils uml-utilities
5.2 仿真示例
5.2.1 用戶態(tài)模擬
下圖描述的固件中的二進(jìn)制程序的架構(gòu)是mipsel32架構(gòu),所以需要使用適配mips架構(gòu)的qemu-mipsel-static程序進(jìn)行仿真。
將qemu-mipsel-static拷貝到當(dāng)前固件的文件系統(tǒng)目錄中。
接下來,使用chroot切換根目錄,使用qemu-mipsel-static工具翻譯執(zhí)行程序goahead。我們使用chroot命令的原因是為了程序查找相對路徑下的動態(tài)鏈接庫。
如上圖所示,程序執(zhí)行出現(xiàn)錯誤:"cannot open pid file"。根據(jù)錯誤信息,在ida中對字符串調(diào)用定位報錯點,發(fā)現(xiàn)報錯原因:無法打開 /var/run/goahead.pid。查看文件系統(tǒng)內(nèi)并沒有此文件,通過touch ./var/run/goahead.pid命令創(chuàng)建該文件可以解決該錯誤。
完成第一個報錯修復(fù)后重新仿真程序,程序繼續(xù)執(zhí)行時出現(xiàn)錯誤:"waiting for nvram_daemon",如下圖所示。
如下圖,根據(jù)字符串定位在ida中發(fā)現(xiàn)了報錯原因:無法打開/var/run/nvramd.pid。查看文件系統(tǒng)內(nèi)并沒有此文件,通過touch ./var/run/nvramd.pid命令創(chuàng)建該文件可以解決該錯誤。
已經(jīng)修復(fù)了2處報錯點。再次重新運行程序,出現(xiàn)了第三個報錯:"failed to convert to binary ip data",如下圖所示。
如下圖所示,ida中提示報錯原因:nvram_bufget函數(shù)無法讀取lan_ipaddr,而nvram_bufget是從/dev/nvram中讀取數(shù)據(jù)。在Linux操作系統(tǒng)中,硬件設(shè)備也被看做文件來處理,/dev/nvram是非易失性存儲器nvram設(shè)備(具體概念在5.3.2章節(jié)進(jìn)行介紹)。為此,我們將分別講解劫持動態(tài)鏈接庫和patch共2種方法來解決仿真過程中設(shè)備缺失的問題。
5.2 .1.1 使用LD_PRELOAD方式劫持動態(tài)鏈接庫實現(xiàn)nvram設(shè)備的模擬
劫持動態(tài)鏈接庫是什么意思呢?例如,程序nvram_xxx函數(shù)都是通過動態(tài)鏈接方式來鏈接libnvram-0.9.28.so這個函數(shù)庫的,我們只要在加載libnvram-0.9.28.so之前加載我們自己的so文件就可以劫持這些函數(shù),所以我們需要實現(xiàn)一個自己的so文件。FirmAE提供的libnvram庫(https://github.com/pr0v3rbs/FirmAE/tree/master/sources/libnvram)已經(jīng)寫好了最關(guān)鍵的nvram_bufget函數(shù),如下圖所示。并且libnvram目錄下中的config.h中已經(jīng)提供了一部分nvram中的初始數(shù)據(jù)。
為了適配我們的環(huán)境,需要對config.h做一下修改:
設(shè)置nvram讀取掛載點 (創(chuàng)建目錄存放nvram數(shù)據(jù)),為此我們需要在文件系統(tǒng)中創(chuàng)建目錄mkdir ./mnt/libnvram.
config.h —— 修改啟動web IP地址 為eth0網(wǎng)卡 IP。
修改完成后,進(jìn)行動態(tài)鏈接庫libnvram.so的編譯。
mipsel-linux-gnu-gcc -c -O2 -fPIC -Wall nvram.c -o nvram.o
mipsel-linux-gnu-gcc -shared -nostdlib nvram.o -o libnvram.so
手動加載修改后的libnvram.so再次運行,如下圖所示,仍然遇到報錯,發(fā)現(xiàn)還是缺少相關(guān)鍵值對!
根據(jù)報錯信息提示,利用ida進(jìn)行字符串定位,簡易分析獲取鍵值,在config.h添加對應(yīng)數(shù)據(jù),再次編譯。這個過程需要耐心。由于每個人分析方法不同,填入的值不同,最終面臨的報錯就不同。以下是修復(fù)后的config.h (65-68行的IP根據(jù)個人環(huán)境修改)。
#ifndef INCLUDE_CONFIG_H
#define INCLUDE_CONFIG_H
// Determines whether debugging information should be printed to stderr.
#define DEBUG 1
// Determines the size of the internal buffer, used for manipulating and storing key values, etc.
#define BUFFER_SIZE 256
// Determines the size of the "emulated" NVRAM, used by nvram_get_nvramspace().
#define NVRAM_SIZE 2048
// Determines the maximum size of the user-supplied output buffer when a length is not supplied.
#define USER_BUFFER_SIZE 64
// Determines the unique separator character (as string) used for the list implementation. Do not use "\0".
#define LIST_SEP "\xff"
// Special argument used to change the semantics of the nvram_list_exist() function.
#define LIST_MAGIC 0xdeadbeef
// Identifier value used to generate IPC key in ftok()
#define IPC_KEY 'A'
// Timeout for the semaphore
#define IPC_TIMEOUT 1000
// Mount point of the base NVRAM implementation.
#define MOUNT_POINT "/mnt/libnvram/"
// Location of NVRAM override values that are copied into the base NVRAM implementation.
#define OVERRIDE_POINT "/mnt/libnvram.override/"
// Define the semantics for success and failure error codes.
#define E_FAILURE 0
#define E_SUCCESS 1
// Default paths for NVRAM default values.
#define NVRAM_DEFAULTS_PATH \
/* "DIR-505L_FIRMWARE_1.01.ZIP" (10497) */ \
PATH("/var/etc/nvram.default") \
/* "DIR-615_REVE_FIRMWARE_5.11.ZIP" (9753) */ \
PATH("/etc/nvram.default") \
/* "DGL-5500_REVA_FIRMWARE_1.12B05.ZIP" (9469) */ \
TABLE(router_defaults) \
PATH("/etc/nvram.conf") \
PATH("/etc/nvram.deft") \
PATH("/etc/nvram.update") \
TABLE(Nvrams) \
PATH("/etc/wlan/nvram_params") \
PATH("/etc/system_nvram_defaults") \
FIRMAE_PATH("/image/mnt/nvram_ap.default") \
/* "DCS-931L_FIRMWARE_1.04B1.ZIP" by SR */\
FIRMAE_PATH("/etc_ro/Wireless/RT2860AP/RT2860_default_vlan") \
FIRMAE_PATH("/etc_ro/Wireless/RT2860AP/RT2860_default_novlan") \
/* "DGN3500-V1.1.00.30_NA.zip" */\
FIRMAE_PATH2("/usr/etc/default") \
/* "JR6150-R6050-V1.0.0.22.zip" by SR */ \
FIRMAE_PATH("/image/mnt/nvram_whp.default") \
FIRMAE_PATH("/image/mnt/nvram_rt.default") \
FIRMAE_PATH("/image/mnt/nvram_rpt.default") \
FIRMAE_PATH("/image/mnt/nvram.default")
// Default values for NVRAM.
#define NVRAM_DEFAULTS \
/* Linux kernel log level, used by "WRT54G3G_2.11.05_ETSI_code.bin" (305) */ \
ENTRY("console_loglevel", nvram_set, "7") \
/* Reset NVRAM to default at bootup, used by "WNR3500v2-V1.0.2.10_23.0.70NA.chk" (1018) */ \
ENTRY("restore_defaults", nvram_set, "1") \
ENTRY("sku_name", nvram_set, "") \
ENTRY("wla_wlanstate", nvram_set, "") \
ENTRY("lan_if", nvram_set, "br0") \
/* eth0 IP */\
ENTRY("lan_ipaddr", nvram_set, "192.168.0.128")\
ENTRY("lan_bipaddr", nvram_set, "192.168.0.255")\
ENTRY("oldlan_ipaddr", nvram_set, "192.168.0.50")\
ENTRY("lan_netmask", nvram_set, "255.255.255.0") \
/* Set default timezone, required by multiple images */ \
ENTRY("time_zone", nvram_set, "PST8PDT") \
/* Set default WAN MAC address, used by "NBG-416N_V1.00(USA.7)C0.zip" (12786) */ \
ENTRY("wan_hwaddr_def", nvram_set, "01:23:45:67:89:ab") \
/* Attempt to define LAN/WAN interfaces */ \
ENTRY("wan_ifname", nvram_set, "eth0") \
ENTRY("lan_ifnames", nvram_set, "eth1 eth2 eth3 eth4") \
/* Used by "TEW-638v2%201.1.5.zip" (12898) to prevent crash in 'goahead' */ \
ENTRY("ethConver", nvram_set, "1") \
/* Used by "Firmware_TEW-411BRPplus_2.07_EU.zip" (13649) to prevent crash in 'init' */ \
ENTRY("lan_proto", nvram_set, "dhcp") \
ENTRY("wan_ipaddr", nvram_set, "0.0.0.0") \
ENTRY("wan_netmask", nvram_set, "255.255.255.0") \
ENTRY("wanif", nvram_set, "eth0") \
/* Used by "DGND3700 Firmware Version 1.0.0.17(NA).zip" (3425) to prevent crashes */ \
ENTRY("time_zone_x", nvram_set, "0") \
ENTRY("rip_multicast", nvram_set, "0") \
ENTRY("bs_trustedip_enable", nvram_set, "0") \
/* Set default MAC address, used by "linux-lzma(550A)" by SR */ \
FIRMAE_ENTRY("et0macaddr", nvram_set, "01:23:45:67:89:ab")\
/* Used by "AC1450-V1.0.0.34_10.0.16.zip" to prevent crashes by SR */ \
FIRMAE_ENTRY("filter_rule_tbl", nvram_set, "") \
/* Used by Netgear "R6200V2-V1.0.1.14_1.0.14.zip" by SR */ \
FIRMAE_ENTRY("pppoe2_schedule_config", nvram_set, "127:0:0:23:59") \
FIRMAE_ENTRY("schedule_config", nvram_set, "127:0:0:23:59") \
/* Used by Netgear WNDR3400v3, WNDR3500v3 "WNR3500L-V1.2.0.18_40.0.67" to prevent crashes due to following "atoi" func by SR */ \
FIRMAE_ENTRY("access_control_mode", nvram_set, "0") \
FIRMAE_ENTRY("fwpt_df_count", nvram_set, "0") \
FIRMAE_ENTRY("static_if_status", nvram_set, "1") \
/* R8500 patch to prevent crashes in httpd */ \
FIRMAE_ENTRY("www_relocation", nvram_set, "") \
FIRMAE_FOR_ENTRY("usb_info_dev%d", nvram_set, "A200396E0402FF83@[email protected]@U@1@USB_Storage;U:;0;0@", 0, 101) \
/* R6200V2, R6250-V1, R6300v2, R6400, R6700-V1, R7000-V1, R7900, R8000, R8500 patch to prevent crashes in httpd */ \
FIRMAE_FOR_ENTRY("wla_ap_isolate_%d", nvram_set, "", 1, 5) \
/* R6200V1 patch to prevent crashes in httpd */ \
FIRMAE_FOR_ENTRY("wlg_ap_isolate_%d", nvram_set, "", 1, 5) \
FIRMAE_FOR_ENTRY("wlg_allow_access_%d", nvram_set, "", 1, 5) \
/* R6400-V1, R7900-V1, R8000, R8500 patch to prevent crashes in httpd */ \
FIRMAE_FOR_ENTRY("%d:macaddr", nvram_set, "01:23:45:67:89:ab", 0, 3) \
FIRMAE_FOR_ENTRY("lan%d_ifnames", nvram_set, "", 1, 10)\
ENTRY("portal_manage_enable", nvram_set, "0") \
ENTRY("TZ", nvram_set, "EST5EDT") \
ENTRY("OperationMode", nvram_set, "2") \
ENTRY("wanConnectionMode", nvram_set, "DHCP") \
ENTRY("AuthMode", nvram_set, "0") \
ENTRY("IEEE8021X", nvram_set, "0") \
ENTRY("BssidNum", nvram_set, "11") \
ENTRY("WscModeOption", nvram_set, "7") \
ENTRY("WscConfMethods", nvram_set, "0x680") \
ENTRY("WscConfigured", nvram_set, "0")\
ENTRY("telnetEnabled", nvram_set, "0")\
ENTRY("Language", nvram_set, "EN")\
ENTRY("Login", nvram_set, "admin")\
ENTRY("Password", nvram_set, "")\
ENTRY("ProductModemVersion", nvram_set, "")\
ENTRY("HardwareVersion", nvram_set, "A2")\
ENTRY("Login_encode", nvram_set, "")\
ENTRY("FirmwareVersion", nvram_set, "")\
ENTRY("IPPortFilterRules", nvram_set, "0")\
ENTRY("IPPortFilterRules0", nvram_set, "0")\
ENTRY("acl_rules", nvram_set, "web")\
ENTRY("portal_addr", nvram_set, "")\
ENTRY("HostName", nvram_set, "")\
ENTRY("NTPEnable", nvram_set, "")\
ENTRY("NTPServerIP", nvram_set, "")\
ENTRY("NTPSync", nvram_set, "1")
#endif
手動加載修改后的libnvram.so再次運行,web界面已經(jīng)可以正常打開了。
使用提前設(shè)置好的用戶名密碼也可以正常登錄進(jìn)入后臺啦~
5.2.1.2 使用patch方式實現(xiàn)關(guān)鍵跳轉(zhuǎn)的繞過
使用qemu并將程序掛載在23946端口,等待調(diào)試。
在報錯跳轉(zhuǎn)處地址0x45cdbc下斷點。
ida遠(yuǎn)程連接調(diào)試端口,按F9運行 (調(diào)試連接IP為eth0網(wǎng)卡 IP)。
斷點斷下來后,將V0寄存器原值0xFFFFFFFF 修改為非-1值后可跳過報錯,然后繼續(xù)執(zhí)行程序。
輸入eth0 本機(jī)IP 192.168.0.128 可以跳轉(zhuǎn),無法正常對頁面加載。
由于缺少nvram中l(wèi)an_ipaddr值,所以只能手動補全url:192.168.0.128/dir_login.asp 可以正常訪問登錄網(wǎng)頁,但輸入用戶名和密碼登錄依然進(jìn)行報錯。
問題出在登錄檢驗。由于缺失nvram,無法讀取相關(guān)數(shù)據(jù),必須強(qiáng)行修改跳轉(zhuǎn)。在地址0x4570fc和0x457118下斷點。
重復(fù)之前的步驟,成功打開登錄界面后,輸入用戶名密碼點擊登錄后會在斷點斷下,將V0寄存器值都修改為0跳過報錯,繼續(xù)運行。
發(fā)現(xiàn)可以成功跳轉(zhuǎn)到后臺頁面。
手動補全url后:192.168.0.128/index.asp 可以正常訪問后臺界面了。
注:此固件是mipsel架構(gòu)的,熟悉此架構(gòu)的小伙伴可以通過ida在之前的跳轉(zhuǎn)處修改opcode保存,再次運行時可以不用再重復(fù)以上的調(diào)試步驟。
5.2.2 系統(tǒng)級模擬
5.2.2.1 配置網(wǎng)絡(luò)
首先根據(jù)下表依次操作:
#0.安裝網(wǎng)橋
sudo apt-get install bridge-utils uml-utilities
#1.配置橋接網(wǎng)卡
sudo gedit /etc/network/interfaces
#追加寫入以下內(nèi)容
auto br0
iface br0 inet dhcp
bridge_ports eth0
bridge_maxwait 0
#2.創(chuàng)建QEMU的網(wǎng)絡(luò)接口啟動腳本
sudo gedit /etc/qemu-ifup
#追加在最后寫入以下內(nèi)容:
#!/bin/sh
echo "Executing /etc/qemu-ifup"
echo "Bringig $1 for bridged mode..."
sudo /sbin/ifconfig $1 0.0.0.0 promisc up
echo "Adding $1 to br0..."
sudo /sbin/brctl addif br0 $1
sleep 3
#3.重啟網(wǎng)絡(luò)
sudo ifup br0
sudo /etc/init.d/networking restart
完成上述操作后,如果發(fā)現(xiàn)eth0 IP地址與br0 IP地址一樣,需要手動修改:ifconfig eth0 192.168.0.200/24,否則會影響到與qemu虛擬機(jī)的通信。
5.2.2.2 啟動qemu虛擬機(jī)
- 下載對應(yīng)架構(gòu)內(nèi)核和硬盤鏡像
wget https://people.debian.org/~aurel32/qemu/mipsel/debian_squeeze_mipsel_standard.qcow2
wget https://people.debian.org/~aurel32/qemu/mipsel/vmlinux-2.6.32-5-4kc-malta
- 打包文件系統(tǒng)
tar -czvf DIR-816.tar ./squashfs-root/
- 啟動虛擬機(jī) 用戶名和密碼都是 root
sudo qemu-system-mipsel -M malta -kernel vmlinux-2.6.32-5-4kc-malta -hda debian_squeeze_mipsel_standard.qcow2 -append "root=/dev/sda1 console=tty0" -net nic -net tap -nographic
- 此時狀態(tài),互相之間都可以正常通信
kali br0:192.168.0.128
kali eth0:192.168.0.200
qemu eth0 : 192.168.0.121
5.2.2.3 移植修改文件系統(tǒng)
- 將kali中打包的文件系統(tǒng)tar包以及之前修改好的libnvram.so 上傳到qemu虛擬機(jī)中
scp DIR-816.tar libnvram.so [email protected]:/root/
- 在qemu虛擬機(jī)中解壓
tar xzvf DIR-816.tar
- 切換根目錄固件文件系統(tǒng)
mount -o bind /dev ./squashfs-root/dev/
mount -t proc /proc/ ./squashfs-root/proc/
chroot squashfs-root sh
創(chuàng)建目錄防止報錯
mkdir /var/run
touch /var/run/goahead.pid
touch /var/run/nvramd.pid
mkdir /mnt/libnvram
5.2.2.4 運行待仿真程序
手動加載修改的libnvram.so 運行程序。
LD_PRELOAD="./libnvram.so" /bin/goahead
如下圖,運行過程仍然遇到了報錯:缺少wscd命令。
發(fā)現(xiàn)固件中本身缺少相關(guān)程序,本著缺什么補什么的思想,從D-link其他型號固件中找到了相同架構(gòu)的wscd程序并提取其依賴動態(tài)庫上傳至qemu虛擬機(jī)中。
測試wscd程序并運行,發(fā)現(xiàn)依然報錯,暫時無法解決報錯。
在實體設(shè)備中利用漏洞獲取shell后,發(fā)現(xiàn)也并沒有wscd程序。遂更換思路,發(fā)現(xiàn)只需要nvram中 OperationMode設(shè)置為2(滿足!='3' && !='0' && != '1'條件),即可避免執(zhí)行wscd相關(guān)命令。
config.h 中修改OperationMode值。并修改lan_ipaddr值,重新編譯(注:qemu eth0要與kali br0進(jìn)行通信,IP重復(fù)沖突的話會導(dǎo)致qemu中程序運行起來而kali虛擬機(jī)無法訪問)。
重新上傳libnvram.so到qemu虛擬機(jī)中,并掛載運行,能正常訪問登陸界面,且輸入用戶名密碼也能正常登錄后臺。
5.3 仿真問題匯總
本章講述仿真過程中在文件、設(shè)備中出現(xiàn)的問題以及解決方案
5.3.1 文件
進(jìn)程在執(zhí)行時需要進(jìn)程本身的可執(zhí)行文件、可執(zhí)行文件依賴的動態(tài)鏈接庫文件、用于配置程序的配置文件,以及用于寫入臨時文件、日志文件、進(jìn)程當(dāng)前信息的目錄等文件與目錄環(huán)境。在仿真時通常會通過加載原本固件的文件系統(tǒng)的方式來構(gòu)建文件系統(tǒng)的運行環(huán)境,但是設(shè)備固件并不遵循統(tǒng)一的標(biāo)準(zhǔn),提取出的文件系統(tǒng)可能并不完整,會存在部分文件無法找到的情況。另外,有的文件是設(shè)備在運行時動態(tài)創(chuàng)建的,簡單的文件系統(tǒng)提取并不能獲取對應(yīng)的文件。
我們總結(jié)了問題的解決方法,其中最關(guān)鍵的方法就是根據(jù)報錯信息定位報錯點,再一步步修復(fù)即可。以下是幾個常見的案例:
如下圖中缺失文件,只需要對應(yīng)路徑創(chuàng)建文件。
從文件讀取的內(nèi)容不匹配無法完成正常的跳轉(zhuǎn),此時需要手動修改文件內(nèi)容填入正確的值。
5.3.2 設(shè)備
物聯(lián)網(wǎng)設(shè)備通常需要大量的外部硬件設(shè)備參與運行,主要是運算與控制設(shè)備、網(wǎng)絡(luò)設(shè)備、存儲設(shè)備與輸入輸出設(shè)備。模擬器僅對常見的硬件設(shè)備進(jìn)行了支持,其中包含了運算與控制設(shè)備、部分內(nèi)存與磁盤設(shè)備、部分輸入輸出設(shè)備。但是物聯(lián)網(wǎng)設(shè)備中存在著大量的定制外部設(shè)備,如定制的NVRAM、Flash存儲設(shè)備、網(wǎng)絡(luò)設(shè)備等,在執(zhí)行到和這些設(shè)備相關(guān)的系統(tǒng)調(diào)用時,可能會面臨缺少輸入輸出設(shè)備與網(wǎng)絡(luò)設(shè)備,設(shè)備的硬件調(diào)用得不到宿主機(jī)支持等問題。
下圖是程序與nvram的交互流程:程序加載動態(tài)鏈接庫,動態(tài)鏈接庫根據(jù)標(biāo)準(zhǔn)用戶庫中的標(biāo)準(zhǔn)輸入輸出相關(guān)的函數(shù)構(gòu)造對應(yīng)的系統(tǒng)調(diào)用轉(zhuǎn)發(fā)到內(nèi)核層,內(nèi)核根據(jù)系統(tǒng)調(diào)用對應(yīng)執(zhí)行設(shè)備驅(qū)動中的代碼。
對于缺少nvram的問題,有以下幾種解決方案:
- 自定義動態(tài)鏈接庫在軟件層劫持相關(guān)的調(diào)用,通過預(yù)加載的方式通過該鏈接庫控制對硬件的調(diào)用,當(dāng)程序調(diào)用對應(yīng)函數(shù)的時候,會優(yōu)先調(diào)用自定義的動態(tài)鏈接庫,從而模擬NVRAM功能,使仿真程序正常運行
- 通過調(diào)試的方式:
在nvram相關(guān)函數(shù)返回數(shù)據(jù)后,手動修改寄存器,給與正常的數(shù)據(jù)使仿真程序正常運行
強(qiáng)行修改跳轉(zhuǎn),使仿真程序繼續(xù)運行
- 自定義內(nèi)核模塊的方式來實現(xiàn)虛擬的設(shè)備:在Linux操作系統(tǒng)中,硬件設(shè)備也被看做文件來處理,有對應(yīng)的文件標(biāo)準(zhǔn)操作。根據(jù)驅(qū)動定義標(biāo)準(zhǔn)設(shè)計內(nèi)核模塊,對于每一種設(shè)備,以內(nèi)核驅(qū)動的方式,模擬實現(xiàn)文件的標(biāo)準(zhǔn)操作,通過定制內(nèi)核模塊完成外部設(shè)備的軟件形式實現(xiàn)
當(dāng)然,解決方案不恒定,需要根據(jù)實際情況思考并使用。
0x06 總結(jié)
本文系統(tǒng)性講解了固件仿真的概念、技術(shù)、工具和框架,并從用戶態(tài)、系統(tǒng)級2個角度進(jìn)行了實際的手動仿真實踐。仿真過程中會遇到一些文件、設(shè)備等方面的問題和錯誤,本文也給出了相應(yīng)的解決方案。
希望各位讀者朋友讀完此文能有所收獲!
0x07 參考文章
[1]https://blog.lyle.ac.cn/2021/07/09/uemu/
[2] https://www.freebuf.com/sectool/264053.html
[3] https://www.ics-cert.org.cn/portal/page/121/8b078dd28bcf42dfaf894e585d880cea.html
[4] https://www.freebuf.com/sectool/264053.html?
本文題目:物聯(lián)網(wǎng)終端安全入門與實踐之玩轉(zhuǎn)物聯(lián)網(wǎng)固件
文章起源:http://m.fisionsoft.com.cn/article/djhohso.html


咨詢
建站咨詢
