Microsoft Windows Kernel - Registry Hive Loading Relative Arbitrary Read in nt!RtlValidRelativeSecurityDescriptor (MS16-123)








We have encountered a Windows kernel crash in the nt!RtlValidRelativeSecurityDescriptor function invoked by nt!CmpValidateHiveSecurityDescriptors while loading corrupted registry hive files. An example of a crash log excerpt generated after triggering the bug is shown below:

This is a very common bugcheck.  Usually the exception address pinpoints
the driver/function that caused the problem.  Always note this address
as well as the link date of the driver/image that contains this address.
Some common problems are exception code 0x80000003.  This means a hard
coded breakpoint or assertion was hit, but this system was booted
/NODEBUG.  This is not supposed to happen as developers should never have
hardcoded breakpoints in retail code, but ...
If this happens, make sure a debugger gets connected, and the
system is booted /DEBUG.  This will let us see why this breakpoint is
Arg1: c0000005, The exception code that was not handled
Arg2: 81815974, The address that the exception occurred at
Arg3: 80795644, Trap Frame
Arg4: 00000000

Debugging Details:


807956c4 81814994 a4f3f098 0125ffff 00000000 nt!RtlValidRelativeSecurityDescriptor+0x5b
807956fc 818146ad 03010001 80795728 80795718 nt!CmpValidateHiveSecurityDescriptors+0x24b
8079573c 8181708f 03010001 80000560 80000540 nt!CmCheckRegistry+0xd8
80795798 817eafa0 80795828 00000002 00000000 nt!CmpInitializeHive+0x55c
8079585c 817ebd85 80795bb8 00000000 807959f4 nt!CmpInitHiveFromFile+0x1be
807959c0 817f3aae 80795bb8 80795a88 80795a0c nt!CmpCmdHiveOpen+0x50
80795acc 817ec3b8 80795b90 80795bb8 00000010 nt!CmLoadKey+0x459
80795c0c 81682dc6 002afc90 00000000 00000010 nt!NtLoadKeyEx+0x56c
80795c0c 77066bf4 002afc90 00000000 00000010 nt!KiSystemServicePostCall
WARNING: Frame IP not in any known module. Following frames may be wrong.
002afcf8 00000000 00000000 00000000 00000000 0x77066bf4


81815974 803801          cmp     byte ptr [eax],1

The bug seems to be caused by insufficient verification of the security descriptor length passed to the nt!RtlValidRelativeSecurityDescriptor function. An inadequately large length can render the verification of any further offsets useless, which is what happens in this particular instance. Even though the nt!RtlpValidateSDOffsetAndSize function is called to sanitize each offset in the descriptor used to access memory, it returns success due to operating on falsely large size. This condition can be leveraged to get the kernel to dereference any address relative to the pool allocation, which may lead to system crash or disclosure of kernel-mode memory. We have not investigated if the bug may allow out-of-bounds memory write access, but if that is the case, its severity would be further elevated.

The issue reproduces on Windows 7 and 8.1. In order to reproduce the problem with the provided sample, it is necessary to load it with a dedicated program which calls the RegLoadAppKey() API.

Attached is a proof of concept hive file.

Proof of Concept: