A couple of days ago, a Microsoft Windows Kernel "Win32k.sys" Local Denial of Service Vulnerability (BID: 53343) has been published on the exploit-db website: follow this link to get the poc code.
As I wanted to investigate this vulnerability, I compiled the code in Visual Studio and built the executable.
Then I ran it on a dedicated virtual machine, and…
Yeah… I got the dreaded Blue Screen Of Death! So… it worked :P
This screen gives us useful information; we can read: "PAGE_FAULT_IN_NONPAGED_AREA" and then "STOP: 0x00000050 (0xFF7C98CC, 0x00000000, 0x805D33A5, 0x00000000)".
Now, if we read the documentation we get "Bug Check 0x50: PAGE_FAULT_IN_NONPAGED_AREA". But, what does that mean? Well, in the Windows Kernel, the memory is divided into two kinds: paged memory and nonpaged memory.
Basically the difference is that the former can be swapped to the disk while the latter can't. So, the error means that the kernel referenced an invalid memory location within the area reserved to the nonpaged memory.
Basically the difference is that the former can be swapped to the disk while the latter can't. So, the error means that the kernel referenced an invalid memory location within the area reserved to the nonpaged memory.
The parameters of the Bug Check stand respectively for: memory address being referenced ("0xFF7C98CC"); read operation/write operation (0 in this case indicates that read operation mode is selected); address that referenced memory (0x805D33A5, the line of code where the crash happened); reserved (that is not set).
I opened ntkrnlpa.exe with IDA, I loaded the debug symbols and searched for the address that caused the crash, getting this:
PAGE:004FC3A5 cmp word ptr [ecx], 23h
This means that ecx cointans an invalid pointer.
Also, IDA tells us that we are inside the function:
PAGE:004FC370 ; int __stdcall RtlpGetIntegerAtom(ULONG CrashPointer,int)
Then, analyzing the code of the function:
PAGE:004FC372 push ebpPAGE:004FC373 mov ebp, esp
PAGE:004FC375 push ecx
PAGE:004FC376 push ecx
PAGE:004FC377 mov ecx, [ebp+CrashPointer]
PAGE:004FC37A test ecx, 0FFFF0000h
PAGE:004FC380 jnz short Crash_Dead
...
PAGE:004FC3A5 Crash_Dead:
PAGE:004FC3A5 cmp word ptr [ecx], 23h
we see that the invalid pointer is the first parameter of the function, and it is accessed without being properly validated.
Besides, we can see that the memory location being accessed is the same that is passed from the user mode POC code:
Besides, we can see that the memory location being accessed is the same that is passed from the user mode POC code:
UINT c[]={
0x00000000,0x28001500,0xff7c98cc,0x23ffffff
Thus we know that the pointer from user mode is never validated or modified in any way.
From the cross-references we see that the previous function is called by these two functions:
RtlAddAtomToAtomTable(x,x,x)
RtlLookupAtomInAtomTable(x,x,x)
Both these functions don't validate the pointer either. In particular we can see it from the code of the second one:
PAGE:004FC692 push 18h
PAGE:004FC694 push offset dword_4031A0
PAGE:004FC699 call __SEH_prolog
PAGE:004FC69E push [ebp+arg_0]
PAGE:004FC6A1 call _RtlpLockAtomTable@4;
PAGE:004FC6A6 test al, al
PAGE:004FC6A8 jnz short loc_4FC6B4
PAGE:004FC6AA mov eax, 0C000000Dh
PAGE:004FC6AF jmp loc_4FC76C
PAGE:004FC6B4 xor edi, edi
PAGE:004FC6B6 mov [ebp+ms_exc.disabled], edi
PAGE:004FC6B9 lea eax, [ebp+var_20]
PAGE:004FC6BC push eax ; int
PAGE:004FC6BD mov esi, [ebp+PointerCrash]
PAGE:004FC6C0 push esi ; CrashPointer
PAGE:004FC6C1 call _RtlpGetIntegerAtom@8 ;
This function is the one used in the exploit.
Again, from the cross-references we got that this function is called by NtFindAtom, which instead does valid proper validation:
PAGE:00535B81 mov ecx, [ebp+CopyOfCrashPointer]
PAGE:00535B87 lea eax, [ecx+ebx]
PAGE:00535B8A cmp eax, ecx
PAGE:00535B8C jb short Exception
PAGE:00535B8E cmp eax, _MmUserProbeAddress
PAGE:00535B94 jbe short CodeOk
PAGE:00535B96 call _ExRaiseAccessViolation@0 ;
NtFindAtom is a dead end for us, so we switch the analysis on win32k.sys.
From the source code we see the code making a call to a function named NtUserCreateWindowEx. In particular, this code is a home made syscall to a Kernel API in win32k.sys:
mov eax,0x1157
mov edx,7FFE0300h
call dword ptr[edx]
Thus loading win32k.sys in IDA, and searching for this API, we find the function:
.text:BF8344E2 ; int __cdecl xxxUserCreateWindowEx(char,int,SIZE_T NumberOfBytes,int pData,int,int,int,int,int,int,int,int,int,int,int)
This function executes a little bit of code until it gets to the following lines:
.text:BF833E54 mov eax, [ebp+DataBlock]
.text:BF833E57 test eax, 0FFFF0000h
.text:BF833E5C jz short Skip
.text:BF833E5E push dword ptr [eax+8]
.text:BF833E61 call _UserFindAtom@4 ;
DataBlock corresponds to the buffer of data which is stored in the variable "c" in the source code.
The code takes a DWORD at the offset + 8 from such a buffer, and this DWORD is exactly 0xff7c98cc… that is... the vulnerable pointer!
We get into UserFindAtom, and we finally find the missing link:
.text:BF80DA1B push ebp
.text:BF80DA1C mov ebp, esp
.text:BF80DA1E push ecx
.text:BF80DA1F and [ebp+NtStatus], 0
.text:BF80DA23 lea eax, [ebp+NtStatus]
.text:BF80DA26 push eax
.text:BF80DA27 push [ebp+CrashPointer]
.text:BF80DA2A push _UserAtomTableHandle
.text:BF80DA30 call ds:__imp__RtlLookupAtomInAtomTable@12
this is where win32k.sys transfers control to the vulnerable function RtlLookupAtomInAtomTable in ntkrnlpa.exe passing the non-validated pointer.
This pointer was set in the exploit code to be 0xff7c98cc, which is a memory address that falls within the kernelspace region, and the problem is that nowhere in this series of calls this pointer is validated to make sure it is accessible.
usermode app
----|------------------------------------
V
xxxUserCreateWindowEx
|
V
UserFindAtom win32k.sys
----|------------------------------------
V ntkrnlpa.exe
RtlLookupAtomInAtomTable
|
V
RtlpGetIntegerAtom
This vulnerability does not seem to be exploitable for code execution, it looks like the security impact is a Denial Of Service.
However, we have seen that there are two functions potentially vulnerable:
RtlAddAtomToAtomTable(x,x,x)
RtlLookupAtomInAtomTable(x,x,x)
I had a quick look at all the other functions that call these two, and at a first glance they seem to perform proper validation.
Thus I am not going to spend too much time on them, but if anyone wants and finds anything, please let me know!
P.S. As it is, the exploit won't work on 64 bit OSes (I tested Windows 7 Professional and Windows 8 Consumer Preview). This may be due to the pointers being 64bit sized, for one thing (or maybe win32k.sys syscall interface is not the same, I haven't checked).
No comments:
Post a Comment