superuser5 / google-security-research

Automatically exported from code.google.com/p/google-security-research
0 stars 0 forks source link

Kernel-mode type-confusion vulnerability via NtUserSetInformationThread/UserThreadCsrApiPort #436

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
The Windows Kernel is subject to a kernel-mode type-confusion vulnerability 
inside win32k!NtUserSetInformationThread due to referencing a user-mode handle 
via ObReferenceObjectByHandle with a "NULL" type specified (it should instead 
be using *LpcPortObjectType to protect against this vulnerability).

This vulnerability can be triggered from inside CSRSS via the syscall 
win32k!NtUserSetInformationThread with ThreadInformationClass set to 
"UserThreadCsrApiPort" and the parameter of the syscall set to a HANDLE that is 
not an LPC object.

This bug is subject to a 90 day disclosure deadline. If 90 days elapse
without a broadly available patch, then the bug report will automatically
become visible to the public.

Original issue reported on code.google.com by mattt...@google.com on 9 Jun 2015 at 1:43

GoogleCodeExporter commented 9 years ago
Additional information provided to Microsoft; Jun 9th:

This vulnerability allows a process running within user-mode to corrupt 
kernel-mode structures and allow an attacker to take full control of the 
operating system. Specifically, this vulnerability allows an attacker to run 
code in Ring-0 on Windows x64 without obtaining a driver-signing certificate, 
or submitting code to the Windows Hardware Certification service.

This issue is primarily to highlight that there are a number of places where 
the Windows kernel unsafely passes "NULL" as the "ObType" parameter to the 
"nt!ObReferenceObjectByHandle" function call - expecting that the result of the 
call to be a kernel-pointer to a specific type - rather than securely calling 
nt!ObReferenceObjectByHandle with a fixed "ObType" parameter corresponding to 
the expected object's type. 

There are only a small number of such issue, they are easy to fix, and they 
have zero application-compatibility risk.

Exploitation of this category of vulnerability is as follows:

Firstly, the attacker creates a handle to any object that is not an LPC type.

Secondly, the attacker calls NtUserSetInformationThread / UserThreadCsrApiPort 
from within CSRSS passing this handle as the parameter
NtUserSetInformationThread( hCurrentThread, UserThreadCsrApiPort, &handle, 
sizeof(handle) );

win32k!NtUserSetInformation begins by first verifying that the caller of the 
syscall is CSRSS. In this case, we are, so the call continues.

CSRSS runs with high user-mode permissions, but it is not a kernel-mode driver, 
and does not run with the full set of permissions that Ring-0 code has. For 
example, an Administrator on Windows 7 x64 cannot load code within Ring-0 that 
is not in a signed driver, but can inject code into CSRSS. For this reason, in 
order to maintain the "signed driver" requirement, the kernel should not trust 
parameters sent by CSRSS.

This is precisely the reason why during the syscall, 
win32k!NtUserSetInformation validates the length and pointer fields inside the 
user-mode parameters using ProbeForRead. Win32k!NtUserSetInformation captures 
the parameters to the syscall and sends them to win32k!xxxSetInformationThread.

win32k!xxxSetInformationThread can perform a variety of different functions 
depending on the "class" parameter to the syscall. In this case, we specified 
"UserThreadCsrApiPort", and so win32!xxxSetInformationThread calls 
win32k!SetCsrApiPortHandle.

win32k!SetCsrApiPortHandle now tries to resolve the parameter to a kernel 
object via the ObReferenceObjectByHandle function call. Crucially, the kernel 
lazily passes "NULL" as the "ObType" parameter, rather than 
"*LpcPortObjectType", which means that the kernel merely checks that the 
provided handle is valid, not that it is valid and pointing to an ALPC port.

This results in a kernel-mode type-confusion vulnerability in the case where 
usermode provides a valid handle to the syscall, but where the handle is not 
not a PLPCP_PORT_OBJECT. In this case, the kernel resolves the handle to the 
not-ALPC object, and this pointer is then implicitly cast to an ALPC kernel 
object leading to type-confusion in the kernel.

The pointer to this "confused object" is stored in the global variable 
win32k!CsrApiPort. When the kernel next tries to write data via this ALPC port 
(for example, via win32k!xxxActivateDebugger), kernel-mode memory corruption 
occurs.

The vulnerability exists on all supported versions of Windows, including 
Windows7, Windows 8.1 and Windows 10.

Thankfully this bug is extremely easy to fix with zero app-compat or 
performance considerations: since CsrApiPort can only ever safely be a handle 
to a LPC port, the the memory-corruption issue can be immediately resolved by 
making the ObReferenceObjectByHandle explicitly request an "LpcPortObjectType" 
via the ObType parameter. This will cause the function to abort any request to 
set the CsrApiPort to a non-LPC object and eliminating the potential for 
kernel-mode type confusion.

Original comment by mattt...@google.com on 2 Sep 2015 at 5:56

GoogleCodeExporter commented 9 years ago
Reporting timeline:

June 5th 2015:  Me -> MSRC   Initial Report
June 5th 2015:  MSRC -> Me   Automatically assigned MSRC case number 30381
June 9th 2015:  MSRC -> Me   Microsoft requests additional clarification
June 9th 2015:  Me -> MSRC   Clarification above given.
Aug 27th 2015:  Me -> MSRC   7 days before deadline; querying if Microsoft will 
need a deadline extension after 80 days with no-response or feedback from MSRC.
Sep  2nd 2015:  Me -> MSRC   2 days before deadline; re-querying if Microsoft 
will need a deadline extension after no response or feedback from MSRC.

Original comment by mattt...@google.com on 2 Sep 2015 at 6:02

GoogleCodeExporter commented 9 years ago
Looks like this won't get fixed in a bulletin, but may be addressed in a future 
version (based on a mail from MSRC on Sep 2). 

Note that this issue is a kernel driver signing bypass from Administrator 
privileges, i.e. it would typically be used as the final stage in an exploit 
chain that would already have given Administrator access, rather than as a 
standalone exploit.

Original comment by haw...@google.com on 9 Sep 2015 at 12:47