💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
## 10.4 构建 Driver Fuzzer 第一步在完成 PyCommand:IOCTL-dump。 ``` #ioctl_dump.py import pickle import driverlib from immlib import * def main( args ): ioctl_list = [] device_list = [] imm = Debugger() driver = driverlib.Driver() # Grab the list of IOCTL codes and device names ioctl_list = driver.getIOCTLCodes() if not len(ioctl_list): return "[*] ERROR! Couldn't find any IOCTL codes." device_list = driver.getDeviceNames() if not len(device_list): return "[*] ERROR! Couldn't find any device names." # Now create a keyed dictionary and pickle it to a file master_list = {} master_list["ioctl_list"] = ioctl_list master_list["device_list"] = device_list filename = "%s.fuzz" % imm.getDebuggedName() fd = open( filename, "wb" ) pickle.dump( master_list, fd ) fd.close() return "[*] SUCCESS! Saved IOCTL codes and device names to %s" % filename ``` 这个 PyCommand 相当简单:检索 IOCTL 代码列表,检索设备名列表,将他们存到字 典中,然后保存到文件里。下次我们只要在 Immunity 的命令行中简单的输入 !ioctl_dump, pickle 文件就会保存到 Immunity 目录下。 万事俱备只欠 fuzzer。接下来就是 coding and coding,我们实现的这个 fuzzer 检测范围 限制在内存错误和缓冲区溢出,不过扩展也是很容易的。 ``` #my_ioctl_fuzzer.py import pickle import sys import random from ctypes import * kernel32 = windll.kernel32 # Defines for Win32 API Calls GENERIC_READ = 0x80000000 GENERIC_WRITE = 0x40000000 OPEN_EXISTING = 0x3 # Open the pickle and retrieve the dictionary fd = open(sys.argv[1], "rb") master_list = pickle.load(fd) ioctl_list = master_list["ioctl_list"] device_list = master_list["device_list"] fd.close() # Now test that we can retrieve valid handles to all # device names, any that don't pass we remove from our test cases valid_devices = [] for device_name in device_list: # Make sure the device is accessed properly device_file = u"\\\\.\\%s" % device_name.split("\\")[::-1][0] print "[*] Testing for device: %s" % device_file driver_handle = kernel32.CreateFileW(device_file,GENERIC_READGENERIC_WRITE,0,None,OPEN_EXISTI NG,0,None) if driver_handle: print "[*] Success! %s is a valid device!" if device_file not in valid_devices: valid_devices.append( device_file ) kernel32.CloseHandle( driver_handle ) else: print "[*] Failed! %s NOT a valid device." if not len(valid_devices): print "[*] No valid devices found. Exiting..." sys.exit(0) # Now let's begin feeding the driver test cases until we can't be # it anymore! CTRL-C to exit the loop and stop fuzzing while 1: # Open the log file first fd = open("my_ioctl_fuzzer.log","a") # Pick a random device name current_device = valid_devices[random.randint(0, len(valid_devices)-1 )] fd.write("[*] Fuzzing: %s\n" % current_device) # Pick a random IOCTL code current_ioctl = ioctl_list[random.randint(0, len(ioctl_list)-1)] fd.write("[*] With IOCTL: 0x%08x\n" % current_ioctl) # Choose a random length current_length = random.randint(0, 10000) fd.write("[*] Buffer length: %d\n" % current_length) # Let's test with a buffer of repeating As # Feel free to create your own test cases here in_buffer = "A" * current_length # Give the IOCTL run an out_buffer out_buf = (c_char * current_length)() bytes_returned = c_ulong(current_length) # Obtain a handle driver_handle = kernel32.CreateFileW(device_file, GENERIC_READ|GENERIC_WRITE,0,None,OPEN_EXISTING,0,None) fd.write("!!FUZZ!!\n") # Run the test case kernel32.DeviceIoControl( driver_handle, current_ioctl, in_buffer, current_length, byref(out_buf), current_length, byref(bytes_returned), None ) fd.write( "[*] Test case finished. %d bytes returned.\n\n" % bytes_returned.value ) # Close the handle and carry on! kernel32.CloseHandle( driver_handle ) fd.close() ``` 先从 pickle 文件中取出包含 IOCTL 代码和设备名的字典。从列表中找出能够获得句柄 的设备名。如果无法获取,就从列表中移除。接着随机选取一个设备名和 IOCTL 代码,创 建一个随机长度的缓冲区。最后将 IOCTL 发送给驱动。 使用如下命令进行 fuzzing。 ``` C:\>python.exe my_ioctl_fuzzer.py i2omgmt.sys.fuzz ``` 如果 fuzzer crash 了机器,我们能够很准确的获得发送的 IOCTL 代码。接着就是调试驱 动了。表 10-7 显示的就是一个未知驱动的 fuzzing 过程。 ``` [*] Fuzzing: \\.\unnamed [*] With IOCTL: 0x84002019 [*] Buffer length: 3277 !!FUZZ!! [*] Test case finished. 3277 bytes returned. [*] Fuzzing: \\.\unnamed [*] With IOCTL: 0x84002020 [*] Buffer length: 2137 !!FUZZ!! [*] Test case finished. 1 bytes returned. [*] Fuzzing: \\.\unnamed [*] With IOCTL: 0x84002016 [*] Buffer length: 1097 !!FUZZ!! [*] Test case finished. 1097 bytes returned. [*] Fuzzing: \\.\unnamed [*] With IOCTL: 0x8400201c [*] Buffer length: 9366 !!FUZZ!! ``` Listing 10-7: 一次成功的 fuzzing 记录 能够很清楚的看到,上一个 IOCTL,0x8400201c 引发了系统崩溃,因为这是最后一条 记录。目前为止我们的 fuzzer 很简单,但是很漂亮,可以通过不断的扩展功能,使它更强大。 其中一个可能的方法就是,将 InBufferLength 或者 OutBufferLength 参数设置成和实际传入的数据长度不一样。开始毁灭之路吧 ,哈哈!! destroy all drivers in your path!