USB Fuzzing基礎知識:從漏洞挖掘到漏洞報告
最近,我開始使用基于Facedancer的一種工具來挖掘USB主機堆棧中的漏洞。本文首先介紹我的Fuzzing測試方法,然后給出完整更新的Windows 8.1 x64中的漏洞的實際示例。本文的目的不是重新定義USB Fuzzing測試,也不是對我的Fuzzing測試架構進行完整描述,而是要敘述從Fuzzing測試到漏洞報告的完整步驟。
0x01 Fuzzing 方法
我的Fuzzing結構基于Facedancer和Umap工具,并向其中添加了一些功能:
- · 在PCAP中為仿真設備捕獲流量;
- · 從已記錄的PCAP重放流量;
- · 基于Radamsa的數據包變異。
0x02 USB基礎
本文的目的不是要詳細描述USB的工作原理,但仍需要一些知識才能更好地理解USB Fuzzing。連接設備后,主機會向該設備發出標準請求,以檢索有關該設備的信息(供應商ID,產品ID,可用功能等),這樣做是為了對其進行配置并將適當的驅動程序加載到OS中,此信息稱為 描述符。這些請求/描述符在特殊端點上交換:每個連接的新標準設備都必須響應發送給它的請求。端點是設備接口之間的邏輯鏈接和USB主機堆棧,接口由一個或多個端點組成,并提供類功能(HID,大容量存儲等)或特定功能。
0x03 Fuzzing的實例示例
我模擬了USB大容量存儲設備,并丟棄了交換的流量,然后,我決定Fuzzing配置描述符,尤其是bNumEndpoints字段。
變異只是將這個字節替換為一個隨機字節。一段時間后,我在Windows 8.1 x64上觸發了BSOD。在這里,我的變異描述符以紅色框的形式發送到主機。在使用變異描述符對數據包序列重放了幾次之后,我推測主機在以橙色框發送設置配置請求后立即觸發了BSOD 。
在Wireshark中,變異的描述符如下所示:
崩潰轉儲分析幾乎沒有用,因為內核池內存已被損壞:每次崩潰都在另一個位置。我繼續注入數據包,并且在某個時候Windows BSOD給了我以下問題的位置:USBSTOR.sys。
驅動程序名稱是顯式的:它是大容量存儲驅動程序。
0x04 逆向大容量存儲驅動程序
下載完USBSTOR.sys的符號后,我將其加載到IDA Pro中,幸運的是,這些符號很容易理解,我很快找到了有趣的函數: USBSTOR_SelectConfiguration()
第一個基本塊顯示了對usbd.sys導出的調用: USBD_CreateConfigurationRequestEx(),該輸出返回指向URB_FUNCTION_SELECT_CONFIGURATION結構的指針 。根據MSDN [6],此“例程分配并格式化URB以選擇USB設備的配置”。URB是客戶端驅動程序用來描述其要發送到設備的請求的結構[7]。
第二個基本塊調用USBSTOR_SyncSendUsbRequest(),并將先前創建的URB作為第一個參數。調用此函數后,請求將通過USB堆棧發送,然后從主機控制器物理發送到設備。如果我中斷USBSTOR_SyncSendUsbRequest()調用,則會觀察到不是此調用導致系統崩潰。
USBD_CreateConfigurationRequestEx()函數中,我看到它復制 bNumEndpoints(我設置為0的Fuzzing 空間)從USB_INTERFACE_DESCRIPTOR結構的 NumberOfPipes基于USBD_INTERFACE_INFORMATION結構。該USB_INTERFACE_DESCRIPTOR枚舉過程結構初始化,并且不會在本文中進行研究。
現在,在調用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]
現在,將_USBD_INTERFACE_INFORMATION結構復制到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,導致不可利用的內核池溢出。
Windows 8.1 32位
我看到了在64位模式下發生的情況,但沒有看到32位模式下發生的情況。我將不再詳細說明指令流,因為是完全相同的。
以下代碼段對應于先前代碼段的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)
此處,由于結構中的指針大小不同,因此大小計算也不同。因為EAX只有32位長,所以結果0x1400000024不適合它,因此存儲了0x00000024。_URB_SELECT_CONFIGURATION的大小為0x38字節,因此未初始化分配結構的20個字節,如果分配的空間緊隨其后沒有正確地用memcpy()填充,則在特定條件下可以利用該漏洞。
0x05 參考文獻
- [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如若轉載,請注明原文地址: