| Metric | Result | |--------|--------| | Time to system compromise (from user execution) | 1.2 seconds | | Success rate | 97.8% (45/46 runs) | | AV detection (static) | 0/64 (VirusTotal, driver signed with leaked test cert) | | AV detection (runtime) | Defender blocked the dropper, but not the driver load | | Persistence across reboot | Yes (driver re-loads automatically) |
Arbitrary kernel write to a user-controlled address, enabling Write-What-Where primitive. 3.3 Unsafe Interrupt Request Level (IRQL) Handling The driver performed file I/O operations (e.g., writing macro logs to C:\ProgramData\Bloodbat\macros.txt ) while at IRQL = DISPATCH_LEVEL (DPC context). This violates Windows driver rules and can cause a 0x0A (IRQL_NOT_LESS_OR_EQUAL) crash, leading to denial of service. In a controlled exploit, an attacker can force a predictable crash to bypass security monitors (crash-driven exploit). 4. Exploit Chain Construction We built a proof-of-concept exploit chain to achieve local privilege escalation (LPE). Step 1: Reconnaissance Enumerate loaded drivers using NtQuerySystemInformation . Check for presence of bloodbat.sys . Step 2: Gaining Arbitrary Kernel Write Using the IOCTL (0x9C402474), we set devExt->UserLogBuffer to a kernel target address (e.g., nt!HalDispatchTable+0x8 ). Subsequent mouse movement triggered a kernel write to that address. Step 3: Hijacking Control Flow We overwrote the HalDispatchTable entry for HalQuerySystemInformation with a pointer to our user-mode shellcode (after mapping it into kernel space via NtMapViewOfSection ). Step 4: Token Stealing When the system called HalQuerySystemInformation , it executed our shellcode, which located the current process’s EPROCESS structure and replaced its token with that of the SYSTEM process (PID 4). Step 5: Persistence The exploit installed a kernel callback ( PsSetCreateProcessNotifyRoutineEx ) via a second crafted IOCTL, ensuring the exploit code was re-injected into every new privileged process. 5. Results The exploit was tested on fully patched Windows 11 22H2 (x64) with Windows Defender enabled. gaming bloodbat mouse driver
case IOCTL_READ_FIRMWARE: ProbeForRead(UserBuffer, UserSize, 4); RtlCopyMemory(KernelBuffer, UserBuffer, UserSize); // No bounds check return ReadFirmwareData(KernelBuffer); By supplying UserSize = 0x2000 but a buffer of only 8 bytes, a user-mode application can trigger a stack buffer overflow in the kernel. 3.2 Unvalidated User Pointer Dereference (CWE-763) The driver’s mouse movement callback function trusted a user-mode pointer for logging: | Metric | Result | |--------|--------| | Time
VOID OnMouseMove(PDEVICE_EXTENSION devExt, PMOUSE_INPUT_DATA data) PVOID logPtr = devExt->UserLogBuffer; // Set via IOCTL if (logPtr) RtlCopyMemory(logPtr, data, sizeof(MOUSE_INPUT_DATA)); // Direct write to user VA from kernel In a controlled exploit, an attacker can force