USB Fuzzing基礎(chǔ)知識:從漏洞挖掘到漏洞報告
最近,我開始使用基于Facedancer的一種工具來挖掘USB主機(jī)堆棧中的漏洞。本文首先介紹我的Fuzzing測試方法,然后給出完整更新的Windows 8.1 x64中的漏洞的實際示例。本文的目的不是重新定義USB Fuzzing測試,也不是對我的Fuzzing測試架構(gòu)進(jìn)行完整描述,而是要敘述從Fuzzing測試到漏洞報告的完整步驟。
0x01 Fuzzing 方法
我的Fuzzing結(jié)構(gòu)基于Facedancer和Umap工具,并向其中添加了一些功能:
- · 在PCAP中為仿真設(shè)備捕獲流量;
- · 從已記錄的PCAP重放流量;
- · 基于Radamsa的數(shù)據(jù)包變異。
0x02 USB基礎(chǔ)
本文的目的不是要詳細(xì)描述USB的工作原理,但仍需要一些知識才能更好地理解USB Fuzzing。連接設(shè)備后,主機(jī)會向該設(shè)備發(fā)出標(biāo)準(zhǔn)請求,以檢索有關(guān)該設(shè)備的信息(供應(yīng)商ID,產(chǎn)品ID,可用功能等),這樣做是為了對其進(jìn)行配置并將適當(dāng)?shù)尿?qū)動程序加載到OS中,此信息稱為 描述符。這些請求/描述符在特殊端點上交換:每個連接的新標(biāo)準(zhǔn)設(shè)備都必須響應(yīng)發(fā)送給它的請求。端點是設(shè)備接口之間的邏輯鏈接和USB主機(jī)堆棧,接口由一個或多個端點組成,并提供類功能(HID,大容量存儲等)或特定功能。
0x03 Fuzzing的實例示例
我模擬了USB大容量存儲設(shè)備,并丟棄了交換的流量,然后,我決定Fuzzing配置描述符,尤其是bNumEndpoints字段。
變異只是將這個字節(jié)替換為一個隨機(jī)字節(jié)。一段時間后,我在Windows 8.1 x64上觸發(fā)了BSOD。在這里,我的變異描述符以紅色框的形式發(fā)送到主機(jī)。在使用變異描述符對數(shù)據(jù)包序列重放了幾次之后,我推測主機(jī)在以橙色框發(fā)送設(shè)置配置請求后立即觸發(fā)了BSOD 。
在Wireshark中,變異的描述符如下所示:
崩潰轉(zhuǎn)儲分析幾乎沒有用,因為內(nèi)核池內(nèi)存已被損壞:每次崩潰都在另一個位置。我繼續(xù)注入數(shù)據(jù)包,并且在某個時候Windows BSOD給了我以下問題的位置:USBSTOR.sys。
驅(qū)動程序名稱是顯式的:它是大容量存儲驅(qū)動程序。
0x04 逆向大容量存儲驅(qū)動程序
下載完USBSTOR.sys的符號后,我將其加載到IDA Pro中,幸運的是,這些符號很容易理解,我很快找到了有趣的函數(shù): USBSTOR_SelectConfiguration()
第一個基本塊顯示了對usbd.sys導(dǎo)出的調(diào)用: USBD_CreateConfigurationRequestEx(),該輸出返回指向URB_FUNCTION_SELECT_CONFIGURATION結(jié)構(gòu)的指針 。根據(jù)MSDN [6],此“例程分配并格式化URB以選擇USB設(shè)備的配置”。URB是客戶端驅(qū)動程序用來描述其要發(fā)送到設(shè)備的請求的結(jié)構(gòu)[7]。
第二個基本塊調(diào)用USBSTOR_SyncSendUsbRequest(),并將先前創(chuàng)建的URB作為第一個參數(shù)。調(diào)用此函數(shù)后,請求將通過USB堆棧發(fā)送,然后從主機(jī)控制器物理發(fā)送到設(shè)備。如果我中斷USBSTOR_SyncSendUsbRequest()調(diào)用,則會觀察到不是此調(diào)用導(dǎo)致系統(tǒng)崩潰。
USBD_CreateConfigurationRequestEx()函數(shù)中,我看到它復(fù)制 bNumEndpoints(我設(shè)置為0的Fuzzing 空間)從USB_INTERFACE_DESCRIPTOR結(jié)構(gòu)的 NumberOfPipes基于USBD_INTERFACE_INFORMATION結(jié)構(gòu)。該USB_INTERFACE_DESCRIPTOR枚舉過程結(jié)構(gòu)初始化,并且不會在本文中進(jìn)行研究。
現(xiàn)在,在調(diào)用USBD_CreateConfigurationRequestEx()之后,我回到USBSTOR.sys ,RDI指向:
- struct _URB_SELECT_CONFIGURATION {
- struct URB_HEADER Hdr;
- PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
- USBD_CONFIGURATION_HANDLE ConfigurationHandle;
- USBD_INTERFACE_INFORMATION Interface;
- };
R14指向:
- USHORT Length;
- UCHAR InterfaceNumber;
- UCHAR AlternateSetting;
- UCHAR Class;
- UCHAR SubClass;
- UCHAR Protocol;
- UCHAR Reserved;
- USBD_INTERFACE_HANDLE InterfaceHandle;
- ULONG NumberOfPipes; // Our bNumEndpoints = 0 is here !
- USBD_PIPE_INFORMATION Pipes[1];
- } USBD_INTERFACE_INFORMATION, *PUSBD_INTERFACE_INFORMATION;[object Object]
現(xiàn)在,將_USBD_INTERFACE_INFORMATION結(jié)構(gòu)復(fù)制到RCX,我將此指針放回RAX中。
這些指令的偽代碼為:
- ECX <- endpoint number If the number of endpoint is zero
- ECX <- ECX-1 ECX <- 0-1 = 0xffffffff
- R8 (0xffffffff*3*8)+80
- memset(@dest, 0x0, R8) memset(@dest, 0x0, 0x1800000038)
在這里,有一個memset,其大小等于0x1800000038,導(dǎo)致不可利用的內(nèi)核池溢出。
Windows 8.1 32位
我看到了在64位模式下發(fā)生的情況,但沒有看到32位模式下發(fā)生的情況。我將不再詳細(xì)說明指令流,因為是完全相同的。
以下代碼段對應(yīng)于先前代碼段的32位等效:
在偽代碼中,memset()的大小如下:
- EAX <- endpoint number If the number of endpoint is zero
- EAX <- EAX-1 EAX <- 0-1 = 0xffffffff
- EAX (0xffffffff*0x14)+0x38 = 0x24
- memset(@dest, 0x0, EAX) memset(@dest, 0x0, 0x24)
此處,由于結(jié)構(gòu)中的指針大小不同,因此大小計算也不同。因為EAX只有32位長,所以結(jié)果0x1400000024不適合它,因此存儲了0x00000024。_URB_SELECT_CONFIGURATION的大小為0x38字節(jié),因此未初始化分配結(jié)構(gòu)的20個字節(jié),如果分配的空間緊隨其后沒有正確地用memcpy()填充,則在特定條件下可以利用該漏洞。
0x05 參考文獻(xiàn)
- [1] http://goodfet.sourceforge.net/hardware/facedancer21/
- [2] https://github.com/nccgroup/umap
- [3] https://code.google.com/p/ouspg/wiki/Radamsa
- [4] Universal Serial Bus Specification 2.0 page 250
- [5] Universal Serial Bus Specification 2.0 page 260
- [6] http://msdn.microsoft.com/en-us/library/
- [7] http://msdn.microsoft.com/en-us/library/windows/hardware/ff538923%28v=vs.85%29.aspx
本文翻譯自:https://blog.quarkslab.com/usb-fuzzing-basics-from-fuzzing-to-bug-reporting.html如若轉(zhuǎn)載,請注明原文地址: