Репост из блога Esage Lab
Мы выпустили глобальное обновление IOCTL Fuzzer - программы для автоматического выявления уязвимостей в драйверах режима ядра при обработке IOCTL запросов. Подробности работы с данной программой рассматривались в статье Уязвимости в драйверах режима ядра для Windows.
В текущей версии фаззера присутствуют следующие нововведения:
- Поддержка Windows 7
- Полная поддержка 64-х разрядных версий Windows
- Мониторинг исключений
- Режим "честного фаззинга" (отправка IOCTL запросов из контекста процесса фаззера)
- Разные режимы генерации некорректных данных для фаззинга
- Возможность запуска фаззинга/мониторинга на начальных этапах загрузки операционной системы
Поддержка 64-х разрядных версий Windows
Для работы на Windows x64 предусмотрена отдельная версия фаззера - ioctlfuzzer64.exe, отличия которой от 32-х разрядной версии минимальны. Заключаются они в способе перехвата системного вызова NtDeviceIoControlFile(): на x32 - замена адреса обработчика системного вызова в таблице KiServiceTable, а на x64 - сплайсинг (модификация кода) оригинального обработчика. Переход на сплайсинг был обусловлен тем, что в 64-х разрядных версиях Windows в KiServiceTable хранятся не сами адреса обработчиков системных вызовов, а 4-х байтовые смещения этих обработчиков относительно начала таблицы.
Фаззер не имеет функций отключения PatchGuard (защита от модификации кода ядра) и действительной цифровой подписи файла драйвера, поэтому его запуск на 64-х разрядных версиях Windows следует производить исключительно с активным удалённым отладчиком режима ядра, при наличии которого PatchGuard и проверка цифровых подписей драйверов выключаются автоматически.
Мониторинг исключений
Во время фаззинга (причём не только драйверов) хакеры довольно часто встречаются со следующей ситуацией: внутри исследуемой программы происходит попытка записи по недействительному (но потенциально контролируемому атакующим) адресу, которая "давится" встроенной в код программы обработкой исключений. В результате наличие уязвимости никак не скажется на поведении программы во время тестирования, и как следствие - такая уязвимость с огромной долей вероятности останется просто незамеченной.
Для решения подобных проблем и используют мониторинг исключений, суть которого сводится к тому, что бы каким-либо образом перехватить информацию об возникшем исключении до того, как его успеет обработать тестируемая программа.
К сожалению, все существующие на данный момент программы для мониторинга исключений или слишком медленны и не универсальны (касается тех, которые используют стандартный debug API) или работают только на нескольких относительно старых версиях Windows (касается популярной программы ExcpHook). По этой причине нами был разработан собственный инструмент для мониторинга исключений свободный от данных недостатков, который в последствии был интегрирован в IOCTL Fuzzer.
Принцип его работы заключается в перехвате не экспортируемой и не документированной функции ядра KiDispatchException() методом сплайсинга. А так как адрес данной функции получается из отладочных символов ядра, которые фаззер автоматически загружает с PDB сервера Microsoft, реализованный способ перехвата не привязан к конкретной версии операционной системы и является универсальным.
Монитор исключений записывает в лог следующую информацию:
- Имя процесса и идентификатор потока, в контексте которого произошло исключение
- Код исключения, с указанием текстовых констант для тех, которые являются стандартными
- Адрес вызвавшей исключение инструкции и так же дополнительные параметры исключения
- Ассемблерная мнемоника инструкции, которая вызвала исключение
- Состояние регистров процессора на момент возникновения исключения
Для активации мониторинга исключений необходимо указать в командной строке к приложению ioctlfuzzer.exe параметр "--exceptions".
Режим "честного фаззинга"
Старая версия фаззера отправляла "мусорные" IOCTL запросы из контекста того же процесса, где был перехвачен оригинальный IOCTL запрос, что на практике приносило некоторое количество "ложных срабатываний" фаззера на не эксплуатируемых уязвимостях.
Для того, что бы проиллюстрировать причину таких "ложных срабатываний", рассмотрим следующий пример кода обработки IOCTL запроса в драйвере:
1 2 typedef struct _REQUEST_BUFFER 3 { 4 char szString[]; 5 6 } REQUEST_BUFFER, 7 *PREQUEST_BUFFER; 8 9 // Указатель на доверенный процесс, который устанавливается, 10 // к примеру, при инициализации драйвера. 11 PEPROCESS m_TrustedProcess = NULL; 12 13 NTSTATUS DriverDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) 14 { 15 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); 16 17 Irp->IoStatus.Status = ns; 18 Irp->IoStatus.Information = 0; 19 20 if (stack->MajorFunction == IRP_MJ_DEVICE_CONTROL) 21 { 22 // извлечение параметров IOCTL запроса 23 ULONG Code = stack->Parameters.DeviceIoControl.IoControlCode; 24 ULONG Size = stack->Parameters.DeviceIoControl.InputBufferLength; 25 PREQUEST_BUFFER Buff = (PREQUEST_BUFFER)Irp->AssociatedIrp.SystemBuffer; 26 27 switch (Code) 28 { 29 case IOCTL_DO_SOMETHING: 30 { 31 // проверка параметров IOCTL запроса 32 if (PsGetCurrentProcess() == m_TrustedProcess && 33 Size > 0) 34 { 35 char szLocalString[255]; 36 strcpy(szLocalString, &Buff->szString); 37 38 // выполнение какой-то полезной работы 39 // ... 40 } 41 42 break; 43 } 44 } 45 } 46 47 // ... 48 49 }
Как мы можем видеть, вызов функции strcpy() на 36-й строке уязвим к классическому переполнению буфера, которое, однако, не эксплуатируемое на практике, так как ему предшествует "отсекание" IOCTL-запросов от процессов, не являющихся доверенными (32-я строка). Поскольку IOCTL запросы старой версии фаззера отправлялись из контекста оригинального процесса, осуществляющего взаимодействие с тестируемым драйвером, то фаззинг продемонстрированного фрагмента кода приводил бы к краху системы.
Разумеется, далеко не все подобные проверки действительно нельзя обойти, однако, на практике было бы удобно иметь опцию, которая бы позволяла фаззеру пропускать подобные места кода. В новой версии IOCTL Fuzzer такая опция именуется "честный фаззинг". Её суть заключается в том, что активация настройки "fair_fuzzing" в конфигурационном файле указывает фаззеру на необходимость отправлять все "мусорные" IOCTL запросы из контекста своего собственного процесса, который, разумеется, вряд-ли будет являться доверенным для драйверов посторонних приложений.
В заключении рассмотрим пользу "честного фаззинга" при тестировании реального приложения на примере последней версии Avira Premium Security Suite. При запуске фаззера с отключенной настройкой "fair_fuzzing" довольно быстро происходит аварийное завершение работы системы в следствии краха тестируемого приложения. При анализе аварийного дампа обнаруживается следующий стек вызовов:
Access violation - code c0000005 (!!! second chance !!!)
*** ERROR: Module load completed but symbols could not be loaded for avgntflt.sys
avgntflt+0x698c:
b2a8a98c 66393e cmp word ptr [esi],di
kd> kb
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
b27739b4 b2a87745 304ef370 caba0198 caba0384 avgntflt+0x698c
b27739cc b2a89ad4 81dea508 00000037 00000037 avgntflt+0x3745
b27739ec b2a89ba8 caba021c 81dea508 00000037 avgntflt+0x5ad4
b2773a1c 804ee119 81f2fd80 82174a68 806d22d0 avgntflt+0x5ba8
b2773a2c 80574d5e 82174ad8 8211ee58 82174a68 nt!IopfCallDriver+0x31
b2773a40 80575bff 81f2fd80 82174a68 8211ee58 nt!IopSynchronousServiceTail+0x70
b2773ae8 8056e46c 000000f4 00000000 00000000 nt!IopXxxControlFile+0x5e7
*** ERROR: Module load completed but symbols could not be loaded for IOCTLfuzzer.sys
b2773b1c b201b405 000000f4 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
b2773ba8 b201ba90 00000001 000000f4 00000000 IOCTLfuzzer+0x4405
b2773c9c b201be17 00000001 81ecf008 000000f4 IOCTLfuzzer+0x4a90
b2773d34 8053d638 000000f4 00000000 00000000 IOCTLfuzzer+0x4e17
b2773d34 7c90e4f4 000000f4 00000000 00000000 nt!KiFastCallEntry+0xf8
00a1e338 7c90d26c 7c801675 000000f4 00000000 ntdll!KiFastSystemCallRet
00a1e33c 7c801675 000000f4 00000000 00000000 ntdll!NtDeviceIoControlFile+0xc
Из аргументов функции avgntflt+0x5ba8 (выделены красным) извлекается имя устройства и параметры IOCTL запроса, который вызвал ошибку:
kd> !devobj 81f2fd80 Device object (81f2fd80) is for: avgntflt \FileSystem\avgntflt DriverObject 8210c1c8 Current Irp 00000000 RefCount 1 Type 00000008 Flags 00000040 Dacl e138a1dc DevExt 00000000 DevObjExt 81f2fe38 ExtensionFlags (0000000000) Device queue is not busy. kd> !irp 82174a68 Irp is active with 1 stacks 1 is current (= 0x82174ad8) No Mdl: System buffer=81dea508: Thread 81f29da8: Irp stack trace. cmd flg cl Device File Completion-Context >[ e, 0] 5 0 81f2fd80 8211ee58 00000000-00000000 \FileSystem\avgntflt Args: 00000000 00000037 caba021c 00000000 kd> dt _IO_STACK_LOCATION 82174ad8 Parameters.DeviceIoControl. ntdll!_IO_STACK_LOCATION +0x004 Parameters : +0x000 DeviceIoControl : +0x000 OutputBufferLength : 0 +0x004 InputBufferLength : 0x37 +0x008 IoControlCode : 0xcaba021c +0x00c Type3InputBuffer : (null)
Как видно, ошибка происходит при обработке IOCTL запроса с кодом 0xcaba021c, адресованного устройству avgntflt (драйвер тестируемого продукта). Изучение уязвимого драйвера с помощью дизассемблера приводит к следующему фрагменту кода:
1 unsigned int __stdcall sub_F7F376AA(unsigned int Code, int FileInformation, int a3, int a4, ULONG Length, int a6, int a7) 2 { 3 int v8; // eax@20 4 int v9; // [sp+0h] [bp-4h]@1 5 6 v9 = 0; 7 if (KeGetCurrentIrql()) 8 return STATUS_UNSUCCESSFUL; 9 10 if ( Code != 0xCABA0198 11 && Code != 0xCABA0320 12 && Code != 0xCABA032C 13 && Code != 0xCABA0384 14 && IoGetCurrentProcess() != (PEPROCESS)dword_F7F3C184) 15 return STATUS_UNSUCCESSFUL; 16 17 // ... 18 19 if (Code == 0xCABA021C) 20 { 21 sub_F7F356F0(FileInformation, a3); 22 return v9; 23 } 24 25 // ... 26 27 return v9; 28 }
Как видно, вызов уязвимой функции sub_F7F356F0, которая осуществляет обработку IOCTL запроса с нужным нам кодом, происходит только в том случае, если будет удовлетворено условие, осуществляющее проверку текущего процесса на предмет того, является ли он доверенным. В этом легко убедиться запустив фаззер с активированной настройкой "fair_fuzzing" - в этом случае падения системы при повторном проведении теста не произойдет.
Режимы генерации некорректных данных для фаззинга
Алгоритм, который фаззер будет использовать для генерации некорректных данных, так же является важным фактором, определяющим эффективность его работы. Продемонстрируем это утверждение на следующем примере кода:
1 typedef struct _REQUEST_BUFFER 2 { 3 ULONG Operation; 4 char szString[]; 5 6 } REQUEST_BUFFER, 7 *PREQUEST_BUFFER; 8 9 NTSTATUS DriverDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) 10 { 11 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); 12 13 Irp->IoStatus.Status = ns; 14 Irp->IoStatus.Information = 0; 15 16 if (stack->MajorFunction == IRP_MJ_DEVICE_CONTROL) 17 { 18 // извлечение параметров IOCTL запроса 19 ULONG Code = stack->Parameters.DeviceIoControl.IoControlCode; 20 ULONG Size = stack->Parameters.DeviceIoControl.InputBufferLength; 21 PREQUEST_BUFFER Buff = (PREQUEST_BUFFER)Irp->AssociatedIrp.SystemBuffer; 22 23 switch (Code) 24 { 25 case IOCTL_DO_SOMETHING: 26 { 27 // проверка параметров IOCTL запроса 28 if (Buff->Operation == SOME_CONST && 29 Size > 0) 30 { 31 char szLocalString[255]; 32 strcpy(szLocalString, &Buff->szString); 33 34 // выполнение какой-то полезной работы 35 // ... 36 } 37 38 break; 39 } 40 } 41 } 42 43 // ... 44 45 }
Как видно, уязвимому к переполнению буфера вызову функции strcpy предшествует проверка значения поля Operation, структуры входящих данных IOCTL запроса, на равенство некоторой константе. Старая версия фаззера, с большой долей вероятности, не обнаружила бы подобную уязвимость по причине того, что при генерации "мусорных" IOCTL запросов она использовала примитивное заполнение входного буфера случайными байтами.
Данная недоработка была исправлена, и текущая версия фаззера поддерживает следующие режимы генерации некорректных данных:
- Random - применявшееся ранее заполнение буфера случайными байтами.
- Dwords - поочерёдное копирование в оригинальный входной буфер двойного слова таким образом, что бы его смещение начиная с первой и заканчивая последней итерацией отправки мусорных данных варьировалось в диапазоне от нуля до BuffSize - sizeof(DWORD). В качестве значения этого двойного слова поочерёдно используются константы 0x00000000, 0x00001000, 0xFFFF0000 и 0xFFFFFFFF.
Запуск фаззинга/мониторинга на начальных этапах загрузки
Для более полного покрытия IOCTL запросов, обрабатываемых тестируемым драйвером, бывает необходимо выполнить так же фаззинг и тех из них, которые могут генерироваться приложением или системным сервисом единожды, например во время инициализации. Поскольку подобная инициализация может происходить ещё до запуска пользовательского окружения операционной системы, в новой версии фаззера была добавлена возможность запуска процесса фаззинга/мониторинга на ранних этапах загрузки.
Для активации IOCTL Fuzzer при следующей перезагрузке системы необходимо указать в командной строке к его приложению параметр "--boot".
Пример использования фаззера при поиске реальных уязвимостей
В завершении данной заметки приведем пример ещё одной уязвимости, которая была найдена с помощью IOCTL Fuzzer. В качестве тестируемого приложения будет выступать популярный на западном рынке антивирусных решений продукт - Trend Micro Titanium Maximum Security.
Вскоре после запуска фаззера происходит аварийное завершение работы системы, в выводе удалённого отладчика режима ядра отображается следующее сообщение, c информацией о последнем обработанном фаззером IOCTL запросе:
'C:\Program Files\Trend Micro\AMSP\coreServiceShell.exe' (PID: 792) '\Device\TmComm' (0x81d6a030) [\SystemRoot\system32\DRIVERS\tmcomm.sys] IOCTL Code: 0x9000402b, Method: METHOD_NEITHER InBuff: 0x018fc080, InSize: 0x0000004c OutBuff: 0x018fc080, OutSize: 0x0000004c
Как видно, в данном фрагменте фигурируют имена драйвера и процесса Trend Micro. Стек вызовов на момент краха системы выглядит следующим образом:
ChildEBP RetAddr Args to Child b2862410 804f7b9d 00000003 ffff0000 00000000 nt!RtlpBreakWithStatusInstruction b286245c 804f878a 00000003 00000000 c07fff80 nt!KiBugCheckDebugBreak+0x19 b286283c 804f8cb5 00000050 ffff0000 00000001 nt!KeBugCheck2+0x574 b286285c 8051cc4f 00000050 ffff0000 00000001 nt!KeBugCheckEx+0x1b b28628bc 8054051c 00000001 ffff0000 00000000 nt!MmAccessFault+0x8e7 b28628bc b217f927 00000001 ffff0000 00000000 nt!KiTrap0E+0xcc WARNING: Stack unwind information not available. Following frames may be wrong. b2862974 b2176acb 00000000 018fc060 00000001 tmcomm!CSystemThread::TearDown+0x46b1 b286298c b2176fa0 018fc080 018fc080 00000000 tmcomm!NormalizeFullNtPathToDosName+0x3aa7 b28629a8 b2176823 b2862a04 009f1edd c0000001 tmcomm!NormalizeFullNtPathToDosName+0x3f7c b28629e8 b217592f 9000402b b2862a04 82057bd0 tmcomm!NormalizeFullNtPathToDosName+0x37ff b2862a1c 804ee119 81d6a030 81d6a034 806d22d0 tmcomm!NormalizeFullNtPathToDosName+0x290b b2862a2c 80574d5e 8228e6b0 82057bd0 8228e640 nt!IopfCallDriver+0x31 b2862a40 80575bff 81d6a030 8228e640 82057bd0 nt!IopSynchronousServiceTail+0x70 b2862ae8 8056e46c 00000d00 00000000 00000000 nt!IopXxxControlFile+0x5e7 b2862b1c b1eae4ca 00000d00 00000000 00000000 nt!NtDeviceIoControlFile+0x2a b2862ba8 b1eaea90 00000001 00000d00 00000000 IOCTLfuzzer+0x44ca b2862c9c b1eaee17 00000001 81ef9a48 00000d00 IOCTLfuzzer+0x4a90 b2862d34 8053d638 00000d00 00001554 00000000 IOCTLfuzzer+0x4e17 b2862d34 7c90e4f4 00000d00 00001554 00000000 nt!KiFastCallEntry+0xf8 018fbf70 7c90d26c 7c8016c2 00000d00 00001554 ntdll!KiFastSystemCallRet
Приступим к реверсингу уязвимого драйвера tmcomm.sys, начав с процедуры обработки IRP запросов к устройствам данного драйвера:
1 int __stdcall sub_1E8BE(int DriverObject, char *Irp) 2 { 3 StackLocation = *((_DWORD *)Irp + 24); 4 IoStatus = Irp + 28; 5 *((_DWORD *)Irp + 7) = 0; 6 7 MajorFunction = *(_BYTE *)StackLocation; 8 9 if (MajorFunction == 2) 10 goto LABEL_12; 11 12 if (MajorFunction > 0xDu) 13 { 14 // обработка IRP запросов типа IRP_MJ_DEVICE_CONTROL 15 if (MajorFunction <= 0xFu) 16 { 17 // извлечение параметров IOCTL запроса из структуры IO_STACK_LOCATION 18 Type3InputBuffer = *(_DWORD *)(StackLocation + 0x10); 19 UserBuffer = *((_DWORD *)v6 + 15); 20 InputBufferLength = *(_DWORD *)(StackLocation + 8); 21 OutputBufferLength = *(_DWORD *)(StackLocation + 4); 22 v27 = IoStatus; 23 v24 = OutputBufferLength; 24 25 // дальнейшая обработка IOCTL запроса 26 v5 = sub_1F7A6(*(_DWORD *)(StackLocation + 0xC), (int)&InputBufferLength); 27 goto LABEL_9; 28 } 29 30 // ... 31 } 32 33 // ... 34 35 return v5; 36 }
Как видно по приведенному псевдокоду, обработка IOCTL запросов осуществляется в процедуре sub_1F7A6():
1 int __stdcall sub_1F7A6(int ControlCode, int a2) 2 { 3 v7 = 0xC00000BBu; 4 v6 = 0; 5 v2 = ExGetPreviousMode(); 6 v3 = 0; 7 if (off_34CB4) 8 { 9 v4 = 0; 10 11 // Поиск процедуры дальнейшей обработки IOCTL запроса по значению 12 // ControlCode. Для 0x9000402b (значение, которое было выявленно при фаззинге) 13 // будет вызвана процедура sub_1FF38() 14 while (*(int *)((char *)&dword_34CB0 + v4) != ControlCode) 15 { 16 ++v3; 17 v4 = 8 * v3; 18 if (!*(&off_34CB4 + 2 * v3)) 19 goto LABEL_7; 20 } 21 v6 = *(&off_34CB4 + 2 * v3); 22 } 23 LABEL_7: 24 if (v2 == UserMode) 25 { 26 // проверка входного и выходного буферов 27 ProbeForRead(*(const void **)(a2 + 8), *(_DWORD *)a2, 1u); 28 ProbeForWrite(*(PVOID *)(a2 + 12), *(_DWORD *)(a2 + 4), 1u); 29 } 30 if ( v6 ) 31 { 32 v7 = v6(a2); // <-- вызов процедуры sub_1FF38() 33 34 // ... 35 } 36 return v7; 37 }
Полный код всех процедур, которые участвуют в обработке IOCTL запроса, приводиться не будет по причине его громоздкости.
В ходе проведенного реверсинга было выяснено, что IOCTL запрос с кодом 0x9000402b используется для вызова из пользовательского приложения оригинальных обработчиков тех системных вызовов, которые были перехвачены драйвером антивирусной защиты. При этом во входном буфере по нулевому смещению находится байт, значение которого определяет то, какой системный вызов следует вызвать (например, для NtCreateFile() это значение равно 0x2713). Все остальное пространство входного буфера используется для хранения указателей на структуры (UNICODE_STRING, OBJECT_ATTRIBUTES и другие), которые следует заполнить и передать в качестве параметров для системного вызова.
Уязвимость, позволяющая выполнить произвольный код с наивысшими привилегиями, содержится в функции, которая непосредственно осуществляет системный вызов. Она заключается в отсутствии проверок упоминавшихся выше указателей на параметры системного вызова:
1 int __thiscall sub_288AA(void *this, int InputBuffer, int a3, int a4) 2 { 3 // извлечение параметров для системного вызова из входного буфера 4 v18 = *(_DWORD *)(InputBuffer + 56); 5 v17 = *(_DWORD *)(InputBuffer + 32); 6 v12 = *(_DWORD *)(InputBuffer + 36); 7 v14 = *(_DWORD *)(InputBuffer + 40); 8 v15 = *(_DWORD *)(InputBuffer + 44); 9 v11 = (HANDLE *)(a3 + 8); 10 ObjAttr = *(_DWORD *)(a3 + 0x3C); 11 v10 = (int)this; 12 StringBuffer = *(_DWORD *)(InputBuffer + 0xC); 13 v13 = *(_DWORD *)(InputBuffer + 52); 14 UnicodeString = *(_DWORD *)(InputBuffer + 0x44); 15 v19 = *(struct _IO_STATUS_BLOCK **)(a3 + 0x40); 16 StringLen = *(_DWORD *)(InputBuffer + 0x14); 17 v16 = *(_DWORD *)(InputBuffer + 48); 18 19 if (StringBuffer && UnicodeString && ObjAttr && v19 && StringLen) 20 { 21 // заполнение структуры UNICODE_STRING 22 *(_DWORD *)(UnicodeString + 4) = StringBuffer; 23 *(_WORD *)(UnicodeString + 2) = StringLen; 24 *(_WORD *)UnicodeString = StringLen; 25 26 // заполнение структуры OBJECT_ATTRIBUTES 27 *(_DWORD *)ObjAttr = 24; 28 *(_DWORD *)(ObjAttr + 4) = 0; 29 *(_DWORD *)(ObjAttr + 12) = 0x240u; 30 *(_DWORD *)(ObjAttr + 8) = UnicodeString; 31 *(_DWORD *)(ObjAttr + 16) = 0; 32 *(_DWORD *)(ObjAttr + 20) = 0; 33 34 // вызов оригинального обработчика системного вызова NtCreateFile() 35 result = sub_185C2(v10, v11, v12, (OBJECT_ATTRIBUTES *)ObjAttr, v19, 0, v13, v14, v15, v16, 0, 0, a4); 36 if (result < 0) 37 *v11 = (HANDLE)-1; 38 } 39 else 40 { 41 result = 0xC000000Du; 42 *(_DWORD *)(InputBuffer + 4) = 0xC000000Du; 43 } 44 return result; 45 }
Таким образом, путём передачи уязвимому драйверу специальным образом сформированного буфера атакующий может переписать произвольным значением произвольный байт памяти в пространстве ядра. Более подробно эксплуатация подобных уязвимостей рассматривалась в уже упоминавшейся в данной заметке статье.
Стоит отметить, что рассмотренная уязвимость, не смотря на возможность локального выполнения произвольного кода в пространстве ядра, имеет низкую степень опасности. Это связанно с тем, что необходимое для эксплуатации уязвимости устройство \Device\TmComm может быть открыто только пользователем с наивысшими привилегиями:
Таким образом, уязвимость представляет исключительно образовательную ценность, и её эксплуатация в реальных условиях является бессмысленной. Для уязвимости был разработан полнофункциональный эксплойт.
Загрузить IOCTL Fuzzer
IOCTL Fuzzer распространяется в виде исходных текстов и исполняемых файлов под 32-х и 64-х разрядные версии Windows.
Страница программы на Google Code
Файл README.TXT