win32k.sys
driver and how this process allows to exploit this vulnerability.win32k!gMenuState
, which is the win32k!tagMENUSTATE
:0: kd> dt win32k! TagMenuState
+ 0x000 pGlobalPopupMenu: Ptr32 tagPOPUPMENU
+ 0x004 flags: Int4B
+ 0x008 ptMouseLast: tagPOINT
+ 0x010 mnFocus: Int4B
+ 0x014 cmdLast: Int4B
+ 0x018 ptiMenuStateOwner: Ptr32 tagTHREADINFO
+ 0x01c dwLockCount: Uint4B
+ 0x020 pmnsPrev: Ptr32 tagMENUSTATE
+ 0x024 ptButtonDown: tagPOINT
+ 0x02c uButtonDownHitArea : Uint4B
+ 0x030 uButtonDownIndex: Uint4B
+ 0x034 vkButtonDown: Int4B
+ 0x038 uDraggingHitArea: Uint4B
+ 0x03c uDraggingIndex: Uint4B
+ 0x040 uDraggingFlags: Uint4B
+ 0x044 hdcWndAni: Ptr32 HDC__
+ 0x048 dwAniStartTime: Uint4B
+ 0x04c ixAni: Int4B
+ 0x050 iyAni: Int4B
+ 0x054 cxAni: Int4B
+ 0x058 cyAni: Int4B
+ 0x05c hbmAni: Ptr32 HBITMAP__
+ 0x060 hdcAni: Ptr32 HDC__
win32k!tagMENUSTATE
stores, for example, information such as the clicked area of the screen, the number of the last command menu sent, as well as pointers to the windows that were clicked or that were selected for drag-and-drop. The list of windows in the drop-down menu itself is stored in the first field, pGlobalPopupMenu
, of type win32k!tagPOPUPMENU
:0: kd> dt win32k! TagPopupMenu
+ 0x000 flags: Int4B
+ 0x004 spwndNotify: Ptr32 tagWND
+ 0x008 spwndPopupMenu : Ptr32 tagWND
+ 0x00c spwndNextPopup: Ptr32 tagWND
+ 0x010 spwndPrevPopup : Ptr32 tagWND
+ 0x014 spmenu: Ptr32 tagMENU
+ 0x018 spmenuAlternate: Ptr32 tagMENU
+ 0x01c spwndActivePopup: Ptr32 tagWND
+ 0x020 ppopupmenuRoot: Ptr32 tagPOPUPMENU
+ 0x024 ppmDelayedFree: Ptr32 tagPOPUPMENU
+ 0x028 posSelectedItem: Uint4B
+ 0x02c posDropped: Uint4B
+ 0x030 ppmlockFree: Ptr32 tagPOPUPMENU
win32k!gMenuState
initialized at the moment of creating the context menu, that is, during the execution of the previously mentioned function TrackPopupMenuEx
. Initialization occurs when calling win32k!xxxMNAllocMenuState
:1: kd> k
# ChildEBP RetAddr
00 95f29b38 81fe3ca6 win32k! xxxMNAllocMenuState + 0x7c
01 95f29ba0 81fe410f win32k! XxxTrackPopupMenuEx + 0x27f
02 95f29c14 82892db6 win32k! NtUserTrackPopupMenuEx + 0xc3
03 95f29c14 77666c74 nt! KiSystemServicePostCall
04 0131fd58 7758480e ntdll! KiFastSystemCallRet
05 0131fd5c 100015b3 user32! NtUserTrackPopupMenuEx + 0xc
06 0131fd84 7756c4b7 q_Main_Window_Class_wndproc (call TrackPopupMenuEx)
win32k!xxxMNEndMenuState
function is win32k!xxxMNEndMenuState
, responsible for releasing the menu state:1: kd> k
# ChildEBP RetAddr
00 a0fb7ab0 82014f68 win32k! xxxMNEndMenuState
01 a0fb7b20 81fe39f5 win32k! XxxRealMenuWindowProc + 0xd46
02 a0fb7b54 81f5c134 win32k! XxxMenuWindowProc + 0xfd
03 a0fb7b94 81f1bb74 win32k! XxxSendMessageTimeout + 0x1ac
04 a0fb7bbc 81f289c8 win32k! XxxWrapSendMessage + 0x1c
05 a0fb7bd8 81f5e149 win32k! NtUserfnNCDESTROY + 0x27
06 a0fb7c10 82892db6 win32k! NtUserMessageCall + 0xcf
07 a0fb7c10 77666c74 nt! KiSystemServicePostCall
08 013cfd90 77564f21 ntdll! KiFastSystemCallRet
09 013cfd94 77560908 user32! NtUserMessageCall + 0xc
0a 013cfdd0 77565552 user32! SendMessageWorker + 0x546
0b 013cfdf0 100014e4 user32! SendMessageW + 0x7c
0c 013cfe08 775630bc q_win_event_hook (call SendMessageW (MN_DODRAGDROP))
gMenuState.pGlobalPopupMenu
field gMenuState.pGlobalPopupMenu
updated only at the time of initialization in the xxxMNAllocMenuState
function, but is not reset when the structure is destroyed.xxxMNEndMenuState
begins execution by deinitializing and freeing the information associated with the drop-down menu. To do this, call the MNFreePopup
function, to which we will return in the next section. The main task of MNFreePopup
is to reduce reference counters for windows related to this drop-down menu. Reducing the reference count may, in turn, lead to the destruction of the window when the reference count to it drops to zero.xxxMNEndMenuState
calling the fMenuWindowRef
flag of the fMenuWindowRef
field checks whether there is a drop-down menu of links to the main window. This flag is cleared when the window contained in the spwndPopupMenu
field of the drop-down menu is spwndPopupMenu
:3: kd> k
# ChildEBP RetAddr
00 95fffa5c 81f287da win32k! Xxx FreeWindow + 0x847
01 95fffab0 81f71252 win32k! XxxDestroyWindow + 0x532
02 95fffabc 81f7122c win32k! HMDestroyUnlockedObject + 0x1b
03 95fffac8 81f70c4a win32k! HMUnlockObjectInternal + 0x30
04 95fffad4 81f6e1fc win32k! HMUnlockObject + 0x13
05 95fffadc 81fea664 win32k! HMAssignmentUnlock + 0xf
06 95fffaec 81fea885 win32k! MNFreePopup + 0x7d
07 95fffb14 8202c3d6 win32k! XxxMNEndMenuState + 0x40
xxxFreeWindow + 83f disasm:
.text: BF89082E loc_BF89082E :
.text: BF89082E and ecx, 7FFFFFFFh; ~ fMenuWindowRef
.text: BF890834 mov [eax + tagPOPUPMENU.flags], ecx
pGlobalPopupMenu
field, but the pointer itself does not reset. Thus, we obtain a dangling pointer , which under certain conditions can be used in the future.uButtonDownHitArea
field) at the moment of the menu operation or selected for dragging (the uDraggingHitArea
field).tagWND
structure. The same article describes the concept of kernel callbacks, which we will need later. The number of active references to the window is contained in the cLockObj
field of the cLockObj
structure.WM_NCDESTROY
message is sent notifying that the window state has WM_NCDESTROY
.xxxMNEndMenuState
control can be transferred to the user code of the application, namely, the window procedure of the window being destroyed. This happens in the case when the window, the pointer to which is stored in the gMenuState.uButtonDownHitArea
field, is no longer referenced.2: kd> k
# ChildEBP RetAddr
0138fc34 7756c4b7 q_new_SysShadow_window_proc
0138fc60 77565f6f USER32! InternalCallWinProc + 0x23
0138fcd8 77564ede USER32! UserCallWinProcCheckWow + 0xe0
0138fd34 7755b28f USER32! DispatchClientMessage + 0xcf
0138fd64 77666bae USER32! __ fnNCDESTROY + 0x26
0138fd90 77564f21 ntdll! KiUserCallbackDispatcher + 0x2e
95fe38f8 81f56d86 nt! KeUserModeCallback
95fe3940 81f5c157 win32k! XxxSendMessageToClient + 0x175
95fe398c 81f5c206 win32k! XxxSendMessageTimeout + 0x1cf
95fe39b4 81f2839c win32k! xxxSendMessage + 0x28
95fe3a10 81f2fb00 win32k! XxxDestroyWindow + 0xf4
95fe3a24 81f302ee win32k! xxxRemoveShadow + 0x3e
95fe3a64 81f287da win32k! XxxFreeWindow + 0x2ff
95fe3ab8 81f71252 win32k! XxxDestroyWindow + 0x532
95fe3ac4 81f7122c win32k! HMDestroyUnlockedObject + 0x1b
95fe3ad0 81f70c4a win32k! HMUnlockObjectInternal + 0x30
95fe3adc 81f6e1fc win32k! HMUnlockObject + 0x13
95fe3ae4 81fe4162 win32k! HMAssignmentUnlock + 0xf
95fe3aec 81fea8c3 win32k! UnlockMFMWFPWindow + 0x18
95fe3b14 8202c3d6 win32k! XxxMNEndMenuState + 0x7e
WM_NCDESTROY
message processes the window procedure of the SysShadow
class SysShadow
. Windows of this class are designed to draw shadows and are usually destroyed along with windows that cast this shadow.gMenuState.pGlobalPopupMenu
in order to enable the ability to use this pointer afterwards. In an attempt to allocate the specified memory block, the exploit makes many calls to SetClassLongW
, setting a specially crafted menu name to the window classes previously created for this purpose:2: kd> k
# ChildEBP RetAddr
00 9f74bafc 81f240d2 win32k! Memcpy + 0x33
01 9f74bb3c 81edadb1 win32k! AllocateUnicodeString + 0x6b
02 9f74bb9c 81edb146 win32k! XxxSetClassData + 0x1d1
03 9f74bbb8 81edb088 win32k! XxxSetClassLong + 0x39
04 9f74bc1c 82892db6 win32k! NtUserSetClassLong + 0xc8
05 9f74bc1c 77666c74 nt! KiSystemServicePostCall
06 0136fac0 7755658b ntdll! KiFastSystemCallRet
07 0136fac4 775565bf user32! NtUserSetClassLong + 0xc
08 0136fafc 10001a52 user32! SetClassLongW + 0x5e
09 0136fc34 7756c4b7 q_new_SysShadow_window_proc (call SetClassLongW)
NtUserMNDragLeave
system procedure, which, in turn, makes a nested call to the xxxMNEndMenuState
function, i.e., clearing the gMenuState
structure starts again:2: kd> k
# ChildEBP RetAddr
00 9f74bbf0 8202c3d6 win32k! xxxMNEndMenuState
01 9f74bc04 8202c40e win32k! XxxUnlockMenuStateInternal + 0x2e
02 9f74bc14 82015672 win32k! XxxUnlockAndEndMenuState + 0xf
03 9f74bc24 82001728 win32k! XxxMNDragLeave + 0x45
04 9f74bc2c 82892db6 win32k! NtUserMNDragLeave + 0xd
05 9f74bc2c 100010a9 nt! KiSystemServicePostCall
06 0136fafc 10001a84 q_exec_int2e (int 2Eh)
07 0136fc34 7756c4b7 q_new_SysShadow_window_proc (call q_exec_int2e)
pGlobalPopupMenu
field, which is done by calling MNFreePopup
, which reduces the values of the window reference counters contained in the various tagPOPUPMENU
fields. The content of this structure after the previous step is controlled by the attacker. Thus, when performing the described chain of actions, an attacker receives a decrement primitive to an arbitrary kernel address.tagPOPUPMENU.spwndPrevPopup
field and the primitive is used to decrement the flag field of one of the windows, which causes the bServerSideProc
flag in this window to signify that it executes its window procedure in the kernel.NtUserMNDragLeave
a message is sent to such a window by calling SendMessage, which leads to the execution of arbitrary code in the kernel ( kernel code execution ). Usually, using this feature, the attacker steals the token of the system process, obtaining system privileges. This is exactly what happens in the described exploit.win32k.sys
library. Putting the bServerSideProc
flag at the window is also a popular method of obtaining the ability to run code in the kernel. And third, when executing code in the kernel, copying the reference to the system token is the most convenient way to raise privileges.win32k!gMenuState
variable fields when performing the xxxMNEndMenuState
procedure. It was also bypassed that the menu names set when calling SetClassLong should, on the one hand, be a Unicode string with no null characters, and on the other hand, be a legitimate tagPOPUPMENU
structure. It also means that the address of the window in the kernel, to which the field for decrement will point, must not contain wchar_t null characters. These are just a few examples from a rather impressive list.gMenuState.pGlobalPopupMenu
field occurs closer to the end of the xxxMNEndMenuState
function, much later MNFreePopup
and UnlockMFMWPWindow
, and is accompanied by zeroing of the pointer itself. Thus, the patch eliminates two reasons, the simultaneous presence of which led to the appearance of vulnerability.Source: https://habr.com/ru/post/328804/
All Articles