近期翻閱之前的工作,發(fā)現(xiàn)在考勤機(jī)系列的安全研究里,有一篇很早就整理好但是沒(méi)發(fā)出來(lái)的文章,考慮到相關(guān)設(shè)備的漏洞已經(jīng)提交了快兩年了,想必該修復(fù)的也修復(fù)了,設(shè)備可能都已經(jīng)不再生產(chǎn)了。這篇文章我們主要聊一下這個(gè)設(shè)備的分析過(guò)程,著重描述一下這個(gè)設(shè)備的固件解密。
2、IoT設(shè)備啟動(dòng)概述IoT設(shè)備的安全分析中,分析人員的主要工作是分析設(shè)備的邏輯功能及其代碼實(shí)現(xiàn),從而挖掘設(shè)備中的漏洞。大多數(shù)分析工作是從解析固件開(kāi)始的,如果這一步就不順利的話(huà),后續(xù)可能會(huì)更加麻煩。不巧的是,這次的設(shè)備在起步階段就很曲折:固件被加密了,并不能直接開(kāi)始分析。
在此我們?cè)俸?jiǎn)單總結(jié)一下那些常見(jiàn)IoT設(shè)備的啟動(dòng)流程,如下圖所示:
(資料圖片僅供參考)
圖2-1 IoT設(shè)備大致的啟動(dòng)流程
上圖大致可以分為4個(gè)階段:
(1)首先,芯片上電后首先運(yùn)行的是boot rom,執(zhí)行完畢后會(huì)跳轉(zhuǎn)到bootloader,如果設(shè)備啟用了固件簽名,那么此處會(huì)對(duì)固件進(jìn)行校驗(yàn);
(2)然后,bootloader的作用類(lèi)似于PC啟動(dòng)過(guò)程的引導(dǎo),主要功能就是為操作系統(tǒng)的運(yùn)行做準(zhǔn)備工作,在復(fù)雜的設(shè)備中,bootloader會(huì)進(jìn)一步分成多個(gè)階段;
(3)此時(shí),操作系統(tǒng)就開(kāi)始接管對(duì)MCU的控制,上圖中把操作系統(tǒng)和app分成了兩個(gè)部分,是為了對(duì)標(biāo)PC方便大家理解,實(shí)際上在有些設(shè)備里跑的操作系統(tǒng)和app是混合在一起的,甚至可能沒(méi)有操作系統(tǒng);
(4)最后,各個(gè)app被加載運(yùn)行,開(kāi)始執(zhí)行設(shè)備的邏輯功能,此處往往是我們想要著重分析的地方。
上圖中,bootloader、kernel和app這三個(gè)階段的代碼通常是由開(kāi)發(fā)者編寫(xiě)并燒錄到Flash中的,我們所說(shuō)的固件指的就是這部分內(nèi)容。請(qǐng)將此圖放在腦海中,后續(xù)所有工作都將以此圖為模板展開(kāi)分析和敘述。
PS:本次分享討論的是固件可以提取但是無(wú)法分析的情況,一些由于讀保護(hù)機(jī)制導(dǎo)致固件不被提取的情況,暫不在本篇的討論范疇中。
3、情況簡(jiǎn)介通過(guò)熱風(fēng)槍可以取下Flash芯片,然后通過(guò)編程器可以拿到Flash中的固件,這些基本功各位一定已經(jīng)非常熟悉了,這里就不再贅述。固件文件包含一個(gè)FAT12格式的文件系統(tǒng),可以通過(guò)7z工具直接提取出文件系統(tǒng)中的所有內(nèi)容,提取內(nèi)容截圖如下:
圖3-1 固件文件系統(tǒng)內(nèi)容
顯而易見(jiàn),上圖中的App文件夾中肯定包含了這款門(mén)禁考勤機(jī)的主程序。不過(guò),事情肯定沒(méi)有那么順利,該文件夾內(nèi)只有一個(gè)文件是可以解析的ELF格式,其他文件均不可解析,僅存在可解析文件叫main.bin,用IDA加載之后,內(nèi)容看起來(lái)也有些過(guò)于簡(jiǎn)單,截圖如下:
圖3-2 main.bin程序內(nèi)容
上圖中,雖然函數(shù)符號(hào)都還在,可以大概推斷出函數(shù)的作用,但是函數(shù)看起來(lái)很古怪,比如RT_CreateProcess函數(shù)內(nèi)容是下圖中的樣子:
圖3-3 RT_CreateProcess函數(shù)內(nèi)容
上圖中的gFuncEntryKern看起來(lái)有點(diǎn)像虛表指針,指向一個(gè)函數(shù)地址表,而這個(gè)指針在程序啟動(dòng)時(shí)被賦值。
程序main.bin很短,很快就逆完了,看起來(lái)最后創(chuàng)建了一個(gè)新的進(jìn)程,但除了main.bin程序之外,其他程序全都無(wú)法解析。即便是main.bin自身,看起來(lái)也不太正常,很多函數(shù)只有跳轉(zhuǎn)stub,缺少實(shí)質(zhì)內(nèi)容,看起來(lái)像是PC中加了保護(hù)導(dǎo)入表的殼。那么,接下來(lái)還是從頭開(kāi)始啃一下這個(gè)設(shè)備固件吧。
4、kernel分析與解密按照?qǐng)D2-1所示,我們決定先看看bootloader,在解壓獲得的完整文件系統(tǒng)中,可以看到Product.ini文件,從里面能夠找到設(shè)備的分區(qū)表,如下圖所示:
圖4-1固件分區(qū)表
我們此前解壓縮得到的FAT12文件系統(tǒng)即為0x20000偏移處,順便吐槽一下binwalk,為啥binwalk識(shí)別不出FAT12文件系統(tǒng),因?yàn)樘爬狭藛幔?/p>
結(jié)合設(shè)備上電后串口的輸出字符串,可以推斷出0x20000之前的固件內(nèi)容即為程序的bootloader,接下來(lái)用IDA載入bootloader部分代碼進(jìn)行分析,并結(jié)合串口的輸出日志,可以定位到關(guān)鍵位置,如下圖:
圖4-2 bootloader加載kernel文件的過(guò)程
上圖中,我們根據(jù)串口打印出來(lái)的字符串來(lái)定位程序的關(guān)鍵位置,找到了kernel文件其實(shí)就是rootfs中的Rtbio_3760_R4502文件,且串口打印出來(lái)的信息包含了kernel的加載基址和入口地址,根據(jù)這些信息,可以分析kernel文件了。
使用IDA加載kernel文件之后,IDA導(dǎo)航條如下圖所示:
圖4-3 直接解析Rtbio文件時(shí)的IDA導(dǎo)航條
可以看到此時(shí)kernel只被解析出了一小部分,絕大多數(shù)內(nèi)容都是unexplored狀態(tài),實(shí)際上這部分內(nèi)容還是處于加密或壓縮狀態(tài)。由于執(zhí)行流程已經(jīng)離開(kāi)bootloader而進(jìn)入kernel階段,那么kernel代碼肯定是自解密或自解壓的,這很正常,一般情況下linux kernel都是自解壓的,但我們沒(méi)辦法直接解壓就很奇怪。通過(guò)逆向分析,可以在入口點(diǎn)附近看到多處異或解密代碼,如下圖所示:
圖4-4 異或解密代碼
上圖中,0x79E1即為異或解密使用的密鑰,類(lèi)似上圖中的異或解密代碼在多個(gè)位置都有出現(xiàn),原來(lái)再自解壓之前還有一步自解密過(guò)程,所以沒(méi)法直接解壓。
耐心分析這些已經(jīng)解析的代碼,可以將kernel的啟動(dòng)流程整理為下圖所示內(nèi)容:
圖4-5 kernel文件的解密過(guò)程分析
可以看到,kernel既包含自解密部分,也包含自解壓部分。將我們?cè)赑C端脫殼的經(jīng)驗(yàn)用到此處,待程序完成自解密和自解壓之后,dump完整的內(nèi)存,就可以獲得可以逆向閱讀的kernel二進(jìn)制文件。
然而我們并沒(méi)有找到設(shè)備調(diào)試接口,寫(xiě)脫機(jī)解密腳本又太繁瑣,最終選擇用QEMU加載kernel,運(yùn)行其自解密和自解壓代碼,待所有工作完畢之后dump內(nèi)存。最后,用ida加載dump下來(lái)的內(nèi)核文件,就可以看到很多代碼和明文的字符串,如下圖:
圖4-6 載入并分析dump kernel
在眾多字符串中,我們還注意到了一個(gè)版權(quán)信息,如下圖:
圖4-7 版權(quán)信息字符串
上圖中的版權(quán)信息表明此固件可能使用了RTEMS系統(tǒng)。該系統(tǒng)一款開(kāi)源的RTOS系統(tǒng),在github上就可以找到源碼,代碼參考鏈接:https://github.com/RTEMS/rtems。
與我們此前分析云丁鹿客智能門(mén)鎖那篇很類(lèi)似,當(dāng)確定了固件使用的操作系統(tǒng),那么逆向工作就變得相對(duì)簡(jiǎn)單,畢竟有源碼可以參考。通過(guò)對(duì)比源碼,我們可以分辨出大量函數(shù),如open、close、read等。查找這些函數(shù)的交叉引用,我們發(fā)現(xiàn)了一張很大的函數(shù)表,如下圖右側(cè)所示:
圖4-8 導(dǎo)出函數(shù)表
上圖左側(cè)中,我們展示了第3章main.bin的幾個(gè)函數(shù)調(diào)用,并與右側(cè)kernel中的函數(shù)表相互對(duì)應(yīng)。還記得gFuncEntryKern指針嗎?看起來(lái)這個(gè)指針?biāo)赶虻暮瘮?shù)表就是上圖右側(cè)中的函數(shù)表。到此,依靠這張函數(shù)表,我們就可以正常分析main.bin程序中的所有函數(shù)了。
到此,bootloader和kernel部分可以告一段落了,在開(kāi)始分析APP之前,還有一點(diǎn)需要提一下,與傳統(tǒng)PC操作系統(tǒng)不同的是,該設(shè)備并不存在用戶(hù)態(tài)和內(nèi)核態(tài),kernel和app處于相同的特權(quán)級(jí)別,所以?xún)烧咧g可以直接相互調(diào)用,不需要上下文的切換。
5、app分析與解密在這個(gè)設(shè)備固件中,除了kernel需要解密解壓之外,大部分app也是需要解密解壓的。除main.bin之外的程序,我們都無(wú)法用IDA直接分析,就是因?yàn)檫@些程序尚未解密解壓,而解密解壓的關(guān)鍵就在RT_UnzipFile函數(shù)中,將該函數(shù)的關(guān)鍵位置截圖如下:
圖5-1 RT_UnzipFile函數(shù)的代碼片段
上圖中可以看到read、xor、write等幾個(gè)關(guān)鍵點(diǎn),進(jìn)一步分析可以判定RT_UnzipFile函數(shù)同樣包含解密和解壓這兩個(gè)過(guò)程,異或密鑰也沒(méi)有變化,同樣是0x79E1。
根據(jù)以上結(jié)論我們可以寫(xiě)一個(gè)用于解密和解壓每個(gè)bin文件的腳本,將這些文件恢復(fù)成可以分析的ELF格式。通過(guò)腳本,我們將Root_00.bin解密解壓,root_00.bin就是main.bin在執(zhí)行最后創(chuàng)建的新進(jìn)程,用IDA載入解密解壓后的ELF文件,截圖如下:
圖5-2 通過(guò)IDA載入解密后的Root_00.bin文件
可以看到,Root_00.bin已經(jīng)可以分析了。至此,我們已經(jīng)完全理解了這個(gè)設(shè)備和固件,可以隨意分析其中的文件了。
6、固件程序的編寫(xiě)門(mén)禁考勤機(jī)作為一個(gè)企業(yè)的門(mén)戶(hù),往往承擔(dān)了保衛(wèi)企業(yè)的任務(wù),如果門(mén)禁考勤機(jī)自身變成了打入企業(yè)內(nèi)網(wǎng)的潛伏者,想必是件很搞笑的事情。當(dāng)我們發(fā)現(xiàn)了門(mén)禁考勤機(jī)的漏洞,想植入后門(mén)時(shí),就可以來(lái)閱讀一下這第6章的內(nèi)容。
雖然與開(kāi)發(fā)傳統(tǒng)的Linux程序比較類(lèi)似,但由于我們沒(méi)有與之匹配的SDK,而只能選擇公版ARM編譯器,所以在開(kāi)發(fā)過(guò)程中,需要額外注意兩點(diǎn):
(1)系統(tǒng)調(diào)用。通過(guò)逆向分析被解密解壓的多個(gè)固件程序,我們可以確定程序是沒(méi)有導(dǎo)入表的,系統(tǒng)調(diào)用是通過(guò)gFuncEntryKern和gFuncEntryLibc等幾個(gè)指針實(shí)現(xiàn)。由于我們沒(méi)有官方SDK,這就導(dǎo)致沒(méi)辦法像常規(guī)正向開(kāi)發(fā)一樣進(jìn)行各種系統(tǒng)調(diào)用,但是按照shellcode開(kāi)發(fā)思路,直接寫(xiě)匯編肯定是沒(méi)問(wèn)題的,最終結(jié)果如下圖所示:
圖6-1 模擬系統(tǒng)調(diào)用
上圖中,我們參考IDA的逆向代碼用匯編實(shí)現(xiàn)socket、bind等系統(tǒng)調(diào)用,具體的邏輯功能代碼還是可以照常用C來(lái)編寫(xiě)。
(2)生成文件格式。通過(guò)查看其他已經(jīng)解密解壓的多個(gè)固件程序,我們可以確定ELF文件是relocatable格式,而不是executable格式的,如下圖所示:
圖6-2 查看main.bin文件格式
因此,使用gcc編譯程序時(shí),需要指定-c參數(shù),用于生成僅編譯和匯編的文件;同時(shí),使用ld鏈接程序時(shí),指定-r參數(shù),用于生成relocatable文件。
完成以上工作后,將編譯的程序,按照第三章的分析做好壓縮、加密處理后,并通過(guò)某些方式植入設(shè)備中,設(shè)備上電后即可看到程序開(kāi)始執(zhí)行,tcp回連nc監(jiān)聽(tīng)的42240端口,如下圖:
圖6-3 反彈socket通信的進(jìn)程
上圖中,我們以發(fā)送hello world字符串來(lái)說(shuō)明問(wèn)題。
當(dāng)然,我們也可以修改固件中已有的文件,例如開(kāi)機(jī)界面的圖片,更多內(nèi)容我們這里不再展示。
圖6-4 修改考勤機(jī)開(kāi)機(jī)界面
7、總結(jié)本篇我們著重討論了一款固件加密的門(mén)禁考勤機(jī)設(shè)備,并借鑒PC端app脫殼的技巧,解密解壓了固件中的kernel以及app。其實(shí),本篇分享的固件加密只是各種加密方式的一小類(lèi),更常見(jiàn)的情況應(yīng)該是固件文件完整加密,如果以后有機(jī)會(huì)我們也會(huì)分享那些完整加密的情況,感興趣的可以等我們后續(xù)的分享。
標(biāo)簽: