Windows Kernel stack memory disclosure from nt!RawMountVolume via nt!PiUEventHandleGetEvent (\Device\DeviceApi\CMNotify device) CVE-2018-0747 We have discovered that it is possible to disclose portions of uninitialized kernel stack memory to user-mode applications in Windows 10 through the PiUEventHandleGetEvent IOCTL (0x470804) sent to the \Device\DeviceApi\CMNotify device. The analysis shown below was performed on Windows 10 1709 32-bit. The copying of the disclosed data from kernel to user-mode memory was detected under the following stack trace: --- cut --- kd> k # ChildEBP RetAddr 00 9ecfeafc 81e3b15a nt!memcpy+0x35 01 9ecfeb54 81e3a67c nt!IopCompleteRequest+0x43a 02 9ecfeba8 81e3a31a nt!IopfCompleteRequest+0x35c 03 9ecfebb4 8212c5fb nt!IofCompleteRequest+0x1a 04 9ecfebc0 8212c2b4 nt!PiUEventHandleIoctl+0x39 05 9ecfebd4 8212affc nt!PiUEventDispatch+0x30 06 9ecfebf8 81e97e98 nt!PiDaDispatch+0x28 07 9ecfec14 820e16da nt!IofCallDriver+0x48 08 9ecfecf8 820e113a nt!IopXxxControlFile+0x59a 09 9ecfed24 81f51ca7 nt!NtDeviceIoControlFile+0x2a 0a 9ecfed24 77bc1670 nt!KiSystemServicePostCall 0b 033df550 77bbfeca ntdll!KiFastSystemCallRet 0c 033df554 750b712e ntdll!NtDeviceIoControlFile+0xa 0d 033df5b4 75dd9e9e KERNELBASE!DeviceIoControl+0x6e 0e 033df5e4 752bd243 KERNEL32!DeviceIoControlImplementation+0x3e 0f 033df620 77b861d0 cfgmgr32!CmNotifyWnfNotificationCallback+0x83 10 033df6d4 77b85ee2 ntdll!RtlpWnfWalkUserSubscriptionList+0x245 11 033df6f8 77b85db5 ntdll!RtlpWnfProcessCurrentDescriptor+0xae 12 033df720 77b859e1 ntdll!RtlpWnfNotificationThread+0x65 13 033df754 77b858c0 ntdll!TppExecuteWaitCallback+0xca 14 033df770 77b6b269 ntdll!TppWaitCompletion+0x80 15 033df930 75dd9564 ntdll!TppWorkerThread+0x5d9 16 033df944 77b9293c KERNEL32!BaseThreadInitThunk+0x24 17 033df98c 77b92910 ntdll!__RtlUserThreadStart+0x2b 18 033df99c 00000000 ntdll!_RtlUserThreadStart+0x1b --- cut --- The total size of the output buffer is 0x5a (90) bytes. The last 10 bytes of the memory region are as follows: --- cut --- 9aaad050 52 00 41 00 57 00 bb bb-bb bb R.A.W..... --- cut --- Here, the four 0xbb bytes indicate uninitialized values from the kernel stack. These bytes originate from the stack frame of the nt!RawMountVolume function. Inside of it, we can find the following assembly code: --- cut --- PAGE:0073746F xor ecx, ecx PAGE:00737471 inc ecx PAGE:00737472 mov [ebp+var_54], cx PAGE:00737476 mov [ebp+var_40], edi PAGE:00737479 push 36h PAGE:0073747B pop eax PAGE:0073747C mov [ebp+var_52], ax PAGE:00737480 or [ebp+var_3C], 0FFFFFFFFh PAGE:00737484 mov [ebp+var_38], ecx PAGE:00737487 mov [ebp+var_34], edi PAGE:0073748A push 6 PAGE:0073748C pop ecx PAGE:0073748D mov [ebp+var_30], ecx PAGE:00737490 mov [ebp+var_2C], 10h PAGE:00737497 mov eax, dword ptr ds:aRaw ; "RAW" PAGE:0073749C mov [ebp+var_28], eax PAGE:0073749F mov ax, word ptr ds:aRaw+4 ; "W" PAGE:007374A5 mov [ebp+var_24], ax PAGE:007374A9 lea eax, [ebp+var_54] PAGE:007374AC push eax ; NotificationStructure PAGE:007374AD push ecx ; int PAGE:007374AE push [ebp+Object] ; int PAGE:007374B1 call FsRtlNotifyVolumeEventEx(x,x,x) --- cut --- In the above snippet, we can see that a local structure is first initialized, and then passed via the 3rd argument to nt!FsRtlNotifyVolumeEventEx. While the size of the structure is presumably 0x36, and it starts at EBP-0x54, the last four bytes at EBP-0x22 are never written to. The last initialized portion of memory is the 6-byte L"RAW" string at EBP-0x28, which we also saw in the dump of memory copied to userland. We suspect that the four bytes correspond to a partially filled volume type string buffer, or some kind of padding inserted by the compiler. They are saved in internal kernel structures by nt!FsRtlNotifyVolumeEventEx, and can be later acquired by a user-mode client through the PiUEventHandleGetEvent IOCTL. A proof-of-concept program is not provided for this issue, but it has been observed and confirmed at normal system runtime, and is quite evident in the code. Repeatedly triggering the vulnerability could allow local authenticated attackers to defeat certain exploit mitigations (kernel ASLR) or read other secrets stored in the kernel address space. This bug is subject to a 90 day disclosure deadline. After 90 days elapse or a patch has been made broadly available, the bug report will become visible to the public. Found by: mjurczyk