FPGA編譯內(nèi)核實現(xiàn)BadUSB

硬件安全導論
筆者認為硬件安全,主要可分為兩大類。其一是外設安全,二是CPU安全(也叫可信執(zhí)行環(huán)境)。其中外設安全主要討論的是,類似鍵盤、鼠標、打印機、串口、網(wǎng)卡、內(nèi)存、這類掛件對CPU指令程序流的一個影響。而CPU安全的核心目標,就是想辦法通過用戶層通殺現(xiàn)有操作系統(tǒng)和協(xié)議造成危害,通殺這個前提非常重要,如果你不牢記CPU安全研究的目標,很容易懵逼,不知道討論這些的意義為何。
實驗環(huán)境選擇
主推的實驗環(huán)境是使用fpga作為核心版,配合“集成電子模塊”和“稀疏飛線”外設電路來進行實驗。不推薦使用仿真軟件,仿真軟件會對復雜高速硬件進行大幅度抽象,偏離其實際功能,就比如在Proteus中CPU的代碼無需引導就可以直接編寫到內(nèi)存里,與事實嚴重不符。
也不推薦繪制PCB打板進行實驗,打板多用于投入生產(chǎn)的專項電路,打板后電路可塑性很低,主要優(yōu)勢是結實耐用,體積小,這些都不是實驗階段需要解決的問題。
雖然fpga核心電路設計總是比外設電路更加復雜,但軟件定義網(wǎng)絡總是會省很多事兒,因此要焊接外設電路所需要的裝備比核心板多的多,清單如下:
焊接工具:電焊槍、焊錫、剝線鉗、吸錫器(可選)、熱風槍(多用于焊PCB,可選)
調(diào)試工具:直流可調(diào)電源、萬用表、示波器(可暫時用fpga替代)
串接原件:導線、排針、接線端子、杜邦線、面包板
電子原件:電容、電阻、電感、三極管、二極管
集成原件:整流電路、數(shù)模轉換芯片、關鍵接口底座
上面的原件在淘寶搜索【面包板電路】進入店鋪一般都可以買到,工具設備都比較貴只能單獨購買。不推薦一股腦全部購買,剛入門時只靠一個FPGA就足夠了,購買的fpga就自帶一套豐富的外設資源,加上豐富的IP核與片內(nèi)資源,足夠玩一段時間了。集成arm核和基本外設的zynq開發(fā)板在社區(qū)豐富性、最小系統(tǒng)編譯速度上都有巨大優(yōu)勢,適合新手入門,只是隨著研究的深入,zynq上的PS端口有的時候就顯得不夠靈活,然而這本質(zhì)上還是資源瓶頸的問題,所有fpga都會有,fpga+arm的組合還是最為靈活的版本答案。
外設后門
主流PC機下,外設之間無法脫離CPU的控制直接通信,直白點說,最敏感的外設莫過于內(nèi)存,其他任何外設都不能直接影響內(nèi)存數(shù)據(jù)。如果想通過外設來設計硬件后門,最直接的辦法是設計一個芯片來直連內(nèi)存,但這會造成幾個問題:
不那么致命的問題是外設電路相對簡單,稍微學過點電路的人都能發(fā)現(xiàn)你在搞鬼。
另一個不那么致命的問題是存在總線競爭,你只能在CPU與內(nèi)存交互的空隙進行數(shù)據(jù)修改
最致命的問題還是,由于CPU保護模式的存在,你無法通過用戶層直接訪問到你的后門設備,這意味著你的設備必須基于現(xiàn)有協(xié)議進行操作,綜合來看是個吃力不討好的事兒。
數(shù)據(jù)存儲器逆向
外設里有三個扛把子非常特殊,分別是RAM、ROM和非易失存儲器,從外設角度來看改變這三個角來影響CPU的指令執(zhí)行是最靠譜的,雖然直接在外設上做手腳很容易被發(fā)現(xiàn),但是如果能拿到硬件系統(tǒng)本身,分析這三者將有助黑客挖掘系統(tǒng)漏洞,保護模式造成的虛擬地址機制和掉電易失性使得RAM的分析相比其他兩位更加困難且低效。AXI4-Slave接口使得內(nèi)存映射和管理存在可能,封裝一個操作系統(tǒng)來高仿內(nèi)存不再是什么難事兒,其基本架構如圖所示:

通過一個自定義Chip芯片對總線協(xié)議進行轉義兼容AXI4協(xié)議,通過Control總線實現(xiàn)Chip與ARM的控制通信,防止AXI4協(xié)議訪問到內(nèi)核地址,造成操作系統(tǒng)崩潰。其最終實現(xiàn)的效果很類似于內(nèi)核VT中的EPT內(nèi)存管理,通過ARM對原操作系統(tǒng)的內(nèi)存進行管理,當然這只是個理論上可行的系統(tǒng),到了硬件層面體積、速度、時序約束都是很重要的問題,如何將該高仿系統(tǒng)連接到原始系統(tǒng)上是個比較頭疼的問題。因此多數(shù)情況下,還是選擇直接拆ROM和存儲器芯片逆向里面的程序文件比較方便。
外設交互漏洞利用
這部分主要是針對現(xiàn)有通信協(xié)議進行攻擊,最經(jīng)典的案例就是hid(Human Interface Devices)偽裝攻擊,通過將USB-Slave接口偽造成一個鍵盤或鼠標操作設備,編寫預制腳本短時間內(nèi)在操作系統(tǒng)內(nèi)執(zhí)行大量操作。至于能否突破系統(tǒng)權限,其本質(zhì)還是與軟件安全息息相關,正常情況下用戶也只有r3的權限,想要通過操作提權至r0,那么必須在軟件層面具備條件,也就是存在漏洞。
可信執(zhí)行環(huán)境
“處理器安全”的前身是“處理器開發(fā)”,我們常說的開源CPU就是公開了其電路設計思想的CPU,為了方便流通他們往往用硬件描述語言來定義CPU結構,可以理解為直接提供電路設計的原理圖,可以根據(jù)自己的需求增刪改,比如RISC-V就是開源處理器架構中的一員。
CPU開發(fā)的上下限很大,從簡單內(nèi)存讀寫、中斷處理、浮點運算、順序執(zhí)行、亂序執(zhí)行、預測執(zhí)行、cache緩存涉及到CPU虛擬化等等,難度層層遞增,非一日之功,筆者目前只做過極簡CPU的開發(fā),因此只能簡單聊聊CPU后門的實現(xiàn)思路,具體到技術細節(jié)還有很多問題需要解決,比如CPU性能問題、電路時序問題、電磁干擾問題等等。
首先要理解處理器安全的攻擊目標是“用戶層通殺操作系統(tǒng)”,你絕對不能指望3環(huán)利用漏洞驅或是3環(huán)利用內(nèi)核漏洞,雖然他們在安全攻擊上可行,但本質(zhì)上都屬于軟件安全,一個補丁就可以解決,處理器安全突破的是cpu保護模式,通殺一切操作系統(tǒng),其目標本身就是在得不到內(nèi)核權限的前提下突破操作系統(tǒng)保護,且這個漏洞無法通過軟件修復。
當我們通過設計處理器后門實現(xiàn)的安全攻擊時,其攻擊流程看似和普通軟件病毒或利用普通外設漏洞很像,無非是【投放釣魚木馬】、【在服務器交互端口注入payload】、【制作bad usb這種惡意外設】此類種種。
然而這其中卻存在本質(zhì)區(qū)別,處理器后門實現(xiàn)的核心思路是觸發(fā)cpu內(nèi)部潛在的“指令集”(而不是利用軟件漏洞),從而改變cpu運行狀態(tài)。最樸素的想法當然就是設計一些隱藏“指令”,然而這種做法還是容易被懂行的大佬們測試出來,早在幾年之前就有人提出了針對cpu隱藏指令模糊測試方法,無需逆向電路即可通過黑盒測試爆破出后門指令。
然機緣巧合之下提出的硬件木馬電路就改變了這一格局,一種基于【時序信號電荷累計】而進行狀態(tài)切換的電路。這使得輸如電流必須滿足特定時序,且持續(xù)累進到目標閾值時才會觸發(fā)狀態(tài)改變,所達成的效果就類似于在游戲機上按【上下上下左右左BABA】就可以開掛一樣。
換句話說cpu指令必須在特定輸入組合配合之下才能造成系統(tǒng)異常。試想一下你隨便在用戶層寫幾個push,mov,and指令(按照既定順序執(zhí)行)就可以觸發(fā)后門威脅操作系統(tǒng),不滿足目標順序就無法觸發(fā)后門,跟一個密碼一樣,這才是比較實用的hack方案。
這種方案導致在黑盒測試在概率意義上很難測試出這種后門,只能通過電路逆向來定位后門位置,配合上電路混淆技術可進一步提升后門的隱蔽性。

FPGA上搭建Linux內(nèi)核調(diào)試環(huán)境
arm linux不同于x86下的操作系統(tǒng),arm操作系統(tǒng)的定制化需求較高,CPU外設不能通過總線遍歷自動獲取,必須要手動配置設備樹,因此很多參數(shù)不能夠通用。
Vivado設計FPGA外設電路
開發(fā)板型號:Xilinx Zynq-7010
首先通過Vivado 來連接好arm cpu外設,并導出hdf硬件描述文件包,如何組織fpga電路以實現(xiàn)PS&PL端協(xié)同工作可以參考。

這里的hdf實際上是一個壓縮文件,可用winrar打開,其中保存了PL端的硬件布局文件bitstream、c語言代碼文件以及tcl腳本等

petalinux編譯環(huán)境配置
下載并解壓petalinux安裝文件petalinux-v2018.3-final-installer.run。運行如下命令安裝依賴工具
執(zhí)行如下命令安裝petalinux文件夾
運 行 sudo ?dpkg-reconfigure dash 命令,將默認終端解釋器設置為bash
執(zhí)行文件夾下的source settings.sh 初始化編譯環(huán)境
運行如下命令設置終端別名
創(chuàng)建一個petalinux項目
使用 petalinux-config -c u-boot
初始化u-boot源碼,并配置內(nèi)核引導參數(shù)為:

上述步驟等價于在uboot命令行中執(zhí)行如下命令(需根據(jù)自己的開發(fā)板進行定制):
詳細配置原理可參考
。在項目根目錄搜索 “env_default.h”文件定位U-boot源碼位置,拷貝源碼文件夾到任意目錄如/home/benson/petalinux/v2018.3/MyZynqBoard/uboot。使用 petalinux-config -c kernel
初始化內(nèi)核源碼。初始化linux kgdb調(diào)試參數(shù),使用串口模式調(diào)試Linux內(nèi)核:
Kernel hacking ?--->
Compile-time checks and compiler options ?--->
[*] Compile the kernel with debug info
[*] KGDB: kernel debugger ?---> ?
<*> ? KGDB: use kgdb over the serial console

項目根目錄搜索 “hid.c”文件定位內(nèi)核源碼位置,拷貝源碼文件夾到任意目錄如/home/benson/petalinux/v2018.3/MyZynqBoard/kernel-source。
執(zhí)行 petalinux-config
設置U-boot與內(nèi)核源碼到指定文件夾,同時設置跟文件系統(tǒng)存儲類型為SD Card。
Linux Components Selection ?---> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
u-boot (ext-local-src) ?---> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
External u-boot local source settings ?---> ? ? ? ? ? ? ?
linux-kernel (ext-local-src) ?---> ?
External linux-kernel local source settings ?---> Image Packaging Configuration ?---> Root filesystem type (SD card) ?--->
內(nèi)核編譯與調(diào)試
運行如下命令編譯內(nèi)核
進入項目輸出目錄/images/linux下,通過如下命令,打包系統(tǒng)鏡像
在輸出目錄下,執(zhí)行調(diào)試命令加載符號,準備使用target命令連接并調(diào)試客戶機
開發(fā)板上電進入系統(tǒng),在終端執(zhí)行,觸發(fā)進入kgdb調(diào)試模式:
gdb調(diào)試器上執(zhí)行如下命令進行斷點測試,更多調(diào)試命令可參考
:
修復調(diào)試器寄存器交互協(xié)議bug
使用gdb調(diào)試內(nèi)核時出現(xiàn):
這是由于寄存器傳輸數(shù)量與調(diào)試器接受數(shù)量不匹配導致的,需要更改內(nèi)核中kgdb的源碼并重新編譯,更改如下,原來程序使用的是DBG_MAX_REG_NUM作為最大寄存器數(shù)量,我們需要將其更改為GDB_MAX_REGS這個GDB的最大寄存器數(shù)量:
FPGA編譯內(nèi)核實現(xiàn)BadUSB
USB工作模式使能
通過查看
原理圖可知,USB Slave端口與host共用一個OTG接口,并通過ID引腳進行USB工作模式使能,也就是說【Host】和【Slave】端口只能活一個,從電路接線方式不難看出【Slave】端口的優(yōu)先級高于【Host】,同時接入兩個端口的話,只有【Slave】會工作。這還是比較坑的。

因為參考《核心版電路圖》可知,這個USB芯片驅動端口都是跑在PS端口上的,好歹放一個口到PL上啊,這樣靈活性高一些,這樣連的話想研究usb協(xié)議就得單獨焊外設電路了,有點麻煩。

不過好在隔壁【領航者】更逆天,四個【Host】接口全都公用一個PS端的USB芯片,答案很明顯“PL端不配擁有自己的USB口”。
參照芯片手冊編址設備樹
改寫./MyZynqBoard/project-spec/meta-user/recipes-bsp/device-tree/files路徑下的system-user.dtsi文件,以otg模式使能USB設備,可同時兼容USB Slave與USB Host。配置方法可參考Xilinx官方指導文檔
Linux內(nèi)核代碼修改
執(zhí)行如下命令修改linux內(nèi)核配置
petalinux-config -c kernel
通過如下路徑,開啟”HID Gadget”功能,按下‘M’鍵設置內(nèi)核模塊化編譯g_hid.ko驅動
[*] USB support ?---> ?
? ?<*> ? USB Gadget Support ?---> ?
? ?<*> ? USB Gadget Drivers (HID Gadget) ?---> ? ?
修改linux內(nèi)核代碼“kernel/drivers/usb/gadget/hid.c”, 在文件中增加以下代碼后,重新編譯內(nèi)核,將內(nèi)核鏡像下載到設備中,在/dev目錄下我們會看到設備節(jié)點”/dev/hidg0”,這個新的設備節(jié)點名就是我們剛剛加入的hid模擬鍵盤設備節(jié)點,接下來我們就可以針對該節(jié)點進行讀寫,就可以模擬HID鍵盤輸出了。
USB OTG接口測試
重新編譯內(nèi)核后,運行如下命令,加載g_hid.ko驅動
使用arm-linux-gnueabihf-gcc編譯測試程序hid_gadget_test,并執(zhí)行如下命令,調(diào)用鍵盤設備實現(xiàn)按鍵輸出
hid_gadget_test 的核心測試代碼如下,詳細代碼可參考linux官方文檔《Linux USB HID gadget driver》(https://www.kernel.org/doc/html/next/usb/gadget_hid.html):
接下來就是傳統(tǒng)的c語言開發(fā)了,將測試代碼改寫為自動輸入腳本即可實現(xiàn)bad usb效果。USB協(xié)議的詳細數(shù)據(jù)流,可使用Bus Hound軟件進行調(diào)試。
使用configfs實現(xiàn)靈活hid
現(xiàn)在主流配置usb gadget都是采用configfs通過用戶空間進行配置,而不是像之前使用hardcode方式專門有個內(nèi)核模塊來配置,因為每次注冊設備都要更改內(nèi)核源碼很不方便。然筆者個人認為改代碼配置設備還是比較快的,配置文件需要改寫的屬性也很多,不見得方便,筆者自己也沒用這套方案,如果想實現(xiàn)該效果可參考
??