The Microsoft Windows kernel suffers from a 64-bit pool memory disclosure vulnerability via REG_RESOURCE_LIST registry values (CmResourceTypeDevicePrivate entries).
ed32c0fa3b9a152d5de55a21b3957fdd
Windows Kernel 64-bit pool memory disclosure via REG_RESOURCE_LIST registry values (CmResourceTypeDevicePrivate entries)
CVE-2018-0898
We have discovered a Windows kernel memory disclosure vulnerability through the body of "AllocConfig" registry values (of type REG_RESOURCE_LIST), which can be found under HKLM\SYSTEM\CurrentControlSet\Enum\*\*\*\Control\AllocConfig. The vulnerability affects 64-bit versions of Windows 7 to 10.
The leak was originally detected under the following stack trace (Windows 7):
--- cut ---
kd> k
# Child-SP RetAddr Call Site
00 fffff880`020a68a8 fffff800`0295bdaa nt!memcpy+0x3
01 fffff880`020a68b0 fffff800`0295c30f nt!CmpQueryKeyValueData+0xea
02 fffff880`020a6940 fffff800`0296107f nt!CmQueryValueKey+0x1af
03 fffff880`020a6a20 fffff800`0268d093 nt!NtQueryValueKey+0x37d
04 fffff880`020a6bb0 00000000`772abeaa nt!KiSystemServiceCopyEnd+0x13
05 00000000`007aeb18 00000000`77153dec ntdll!ZwQueryValueKey+0xa
06 00000000`007aeb20 00000000`77153ff2 kernel32!LocalBaseRegQueryValue+0x17c
07 00000000`007aeca0 000007fe`fc281dd1 kernel32!RegQueryValueExW+0xf2
08 00000000`007aed40 000007fe`fc2735e4 umpnpmgr!OpenLogConfKey+0xb3
09 00000000`007aedc0 000007fe`ff25e9d5 umpnpmgr!PNP_GetFirstLogConf+0x8d
[...]
--- cut ---
and more specifically in the copying of the CM_RESOURCE_LIST structure:
--- cut ---
kd> db rdx rdx+r8-1
fffff8a0`049d5bd4 01 00 00 00 05 00 00 00-00 00 00 00 01 00 01 00 ................
fffff8a0`049d5be4 05 00 00 00 03 01 80 00-00 00 00 c0 00 00 00 00 ................
fffff8a0`049d5bf4 00 00 02 00 00 00 00 00-81 01 00 00 01 00 00 00 ................
fffff8a0`049d5c04 00 00 00 00 00 00 00 00-aa aa aa aa 01 01 31 01 ..............1.
fffff8a0`049d5c14 40 c0 00 00 00 00 00 00-40 00 00 00 00 00 00 00 @.......@.......
fffff8a0`049d5c24 81 01 00 00 01 00 00 00-01 00 00 00 00 00 00 00 ................
fffff8a0`049d5c34 aa aa aa aa 02 03 00 00-05 00 00 00 05 00 00 00 ................
fffff8a0`049d5c44 ff ff ff ff 00 00 00 00 ........
--- cut ---
In the above example, the 0xaa values at offsets 0x38-0x3b and 0x60-0x63 are unitialized bytes originating from a pool allocation made in nt!IopResourceRequirementsListToReqList.
If we dive deeper into the layout of the memory area, we can see that in both cases, the leaked bytes reside at the end of a nested CM_PARTIAL_RESOURCE_DESCRIPTOR structure:
--- cut ---
kd> dt _CM_RESOURCE_LIST @rdx
ntdll!_CM_RESOURCE_LIST
+0x000 Count : 1
+0x004 List : [1] _CM_FULL_RESOURCE_DESCRIPTOR
kd> dx -r1 ((ntdll!_CM_FULL_RESOURCE_DESCRIPTOR (*)[1])0xfffff8a0049d5bd8)
((ntdll!_CM_FULL_RESOURCE_DESCRIPTOR (*)[1])0xfffff8a0049d5bd8) : 0xfffff8a0049d5bd8 [Type: _CM_FULL_RESOURCE_DESCRIPTOR (*)[1]]
[0] [Type: _CM_FULL_RESOURCE_DESCRIPTOR]
kd> dx -r1 ((ntdll!_CM_FULL_RESOURCE_DESCRIPTOR *)0xfffff8a0049d5bd8)
((ntdll!_CM_FULL_RESOURCE_DESCRIPTOR *)0xfffff8a0049d5bd8) : 0xfffff8a0049d5bd8 [Type: _CM_FULL_RESOURCE_DESCRIPTOR *]
[<Raw View>] [Type: _CM_FULL_RESOURCE_DESCRIPTOR]
[0] : Memory Resource: 0xc0000000 of length 0x20000 [Type: _CM_PARTIAL_RESOURCE_DESCRIPTOR]
[1] : Private Device Resource [Type: _CM_PARTIAL_RESOURCE_DESCRIPTOR]
[2] : Port Resource: 0xc040 of length 0x40 [Type: _CM_PARTIAL_RESOURCE_DESCRIPTOR]
[3] : Private Device Resource [Type: _CM_PARTIAL_RESOURCE_DESCRIPTOR]
[4] : Interrupt Resource [Type: _CM_PARTIAL_RESOURCE_DESCRIPTOR]
kd> dx -r1 ((ntdll!_CM_PARTIAL_RESOURCE_DESCRIPTOR *)0xfffff8a0049d5bfc)
((ntdll!_CM_PARTIAL_RESOURCE_DESCRIPTOR *)0xfffff8a0049d5bfc) : 0xfffff8a0049d5bfc : Private Device Resource [Type: _CM_PARTIAL_RESOURCE_DESCRIPTOR *]
[<Raw View>] [Type: _CM_PARTIAL_RESOURCE_DESCRIPTOR]
Type : 0x81 [Type: unsigned char]
Flags : 0x0
kd> dx -r1 ((ntdll!_CM_PARTIAL_RESOURCE_DESCRIPTOR *)0xfffff8a0049d5bfc)->@"u".@"DevicePrivate"
((ntdll!_CM_PARTIAL_RESOURCE_DESCRIPTOR *)0xfffff8a0049d5bfc)->@"u".@"DevicePrivate" [Type: <unnamed-tag>]
[+0x000] Data [Type: unsigned long [3]]
kd> dx -r1 ((ntdll!unsigned long (*)[4])0xfffff8a0049d5c00)
((ntdll!unsigned long (*)[4])0xfffff8a0049d5c00) : 0xfffff8a0049d5c00 [Type: unsigned long (*)[4]]
[0] : 0x1 [Type: unsigned long]
[1] : 0x0 [Type: unsigned long]
[2] : 0x0 [Type: unsigned long]
[3] : 0xaaaaaaaa [Type: unsigned long]
kd> dx -r1 ((ntdll!_CM_PARTIAL_RESOURCE_DESCRIPTOR *)0xfffff8a0049d5c24)
((ntdll!_CM_PARTIAL_RESOURCE_DESCRIPTOR *)0xfffff8a0049d5c24) : 0xfffff8a0049d5c24 : Private Device Resource [Type: _CM_PARTIAL_RESOURCE_DESCRIPTOR *]
[<Raw View>] [Type: _CM_PARTIAL_RESOURCE_DESCRIPTOR]
Type : 0x81 [Type: unsigned char]
Flags : 0x0
kd> dx -r1 ((ntdll!_CM_PARTIAL_RESOURCE_DESCRIPTOR *)0xfffff8a0049d5c24)->@"u".@"DevicePrivate"
((ntdll!_CM_PARTIAL_RESOURCE_DESCRIPTOR *)0xfffff8a0049d5c24)->@"u".@"DevicePrivate" [Type: <unnamed-tag>]
[+0x000] Data [Type: unsigned long [3]]
kd> dx -r1 ((ntdll!unsigned long (*)[4])0xfffff8a0049d5c28)
((ntdll!unsigned long (*)[4])0xfffff8a0049d5c28) : 0xfffff8a0049d5c28 [Type: unsigned long (*)[4]]
[0] : 0x1 [Type: unsigned long]
[1] : 0x1 [Type: unsigned long]
[2] : 0x0 [Type: unsigned long]
[3] : 0xaaaaaaaa [Type: unsigned long]
--- cut ---
When CM_PARTIAL_RESOURCE_DESCRIPTOR.Type is set to CmResourceTypeDevicePrivate (0x81), the following structure within the CM_PARTIAL_RESOURCE_DESCRIPTOR.u union is used:
--- cut ---
struct {
ULONG Data[3];
} DevicePrivate;
--- cut ---
However, the size of the overall union is 16 (0x10) bytes on x64 builds, leaving the 4 bytes directly after DevicePrivate.Data unused. It is possible that other descriptor types may also lead to similar leaks due to structure/union alignment or padding, but this is the only one we have observed during regular system run time.
We have verified that regular (non-admin) users have read access to the affected registry values, and thus may successfully exploit the vulnerability. We have also confirmed the bug by enabling the Special Pools mechanism for ntoskrnl.exe, and seeing repeated patterns of marker bytes when inspecting the AllocConfig values in the default Windows Registry Editor (regedit.exe).
A proof-of-concept program is not provided for this issue, but it has been observed 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