📜 ⬆️ ⬇️

Parse vulnerability CVE-2017-0263 for privilege escalation in Windows



May turned out to be rich in interesting vulnerabilities in a popular operating system. The other day, attackers massively infected computers with the WannaCry ransomware virus, exploiting a security flaw in the SMB protocol and a tool known as Eternalblue. Earlier, on May 9, Microsoft eliminated CVE-2017-0263 , which allows it to obtain maximum privileges on machines running Windows 10, Windows 8.1, Windows 7, Windows Server 2008, Windows Server 2012 and Windows Server 2016.

Vulnerability CVE-2017-0263 has already been used in phishing ezine. The letter contained a nested exploit, which involved first the incorrect processing of EPS files in Microsoft Office ( CVE-2017-0262 ) for getting into the system, and once inside, received with the help of CVE-2017-0263 full administrator rights. Two years ago, we had already prepared a similar vulnerability in Windows, and in this article we will tell you how fresh CVE-2017-0263 allows you to become the owner of someone else’s workstation or server.
')
In short, this vulnerability is of type use after free ( CWE-416 ) and arises from the fact that when the context menu is closed and the memory used by this menu is freed, the pointer to the freed memory is not reset. As a result, the pointer can be reused.

All further narration is devoted to the window processing process in the win32k.sys driver and how this process allows to exploit this vulnerability.

Context menus


Perhaps every Windows user is familiar with context menus. This is the same drop-down list that appears whenever we right-click.



The view of the context menu and the conditions for its display are completely on the conscience of the developer of a specific application who is free to act here, as his heart tells him. WinAPI provides for this in its use the function TrackPopupMenuEx , the call of which leads to the appearance of the context menu specified in the parameters in the specified position on the screen.
In the kernel, the state of the context menu is stored in the variable 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__

It is worth mentioning here that all the descriptions of structures and call stacks presented in this article were created on the Windows 7 x86 system. The 32-bit version of the system is chosen for reasons of convenience: the arguments of most functions are stored on the stack and there is no WoW64 interlayer, which during system calls switches to a 64-bit stack, due to which 32-bit stack frames are lost when printing a call stack. A complete list of affected vulnerability systems can be found on the corresponding page on the Microsoft website.

As you can see, the 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

In both structures, the fields that are of interest to us are highlighted in color and will be used further in the description of the use case.

The variable 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)

Conversely, when the context menu is destroyed, because, for example, the user selected one of the menu items or clicked outside the menu area displayed on the screen, the 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))

It is important here that the 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 function


This function will be devoted to the main part of our narration. In a few lines of its code lies the investigated vulnerability.



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.

Then the function 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

As can be seen from the presented figure, dropping the above flag results in the release of the memory occupied by the 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.

Immediately after the memory is freed from the drop-down menu, the execution flow proceeds to delete the links to the windows that were clicked in the context menu state structure (the uButtonDownHitArea field) at the moment of the menu operation or selected for dragging (the uDraggingHitArea field).

Operating option


As we mentioned earlier in the article on CVE-2015-1701, in the core the window object is described by the 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.

Deleting references to a window, as indicated in the previous section, can lead to the destruction of the window itself. Before destroying the window, a WM_NCDESTROY message is sent notifying that the window state has WM_NCDESTROY .

This means that when executing 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

For example, in the specified call stack, the 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.

Let us now consider the most interesting part of the processing of this window message in the form in which it is presented in the sample, removed from the fake .docx document:



When receiving control, the attacker first needs to take the memory just freed from under 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)

After the memory is busy, you can proceed to the next stage. Here, the exploit refers to the 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)

As described in the previous section, the procedure begins with the de-initialization of the 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.

In the exploit in question, the address is replaced in the 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.

The figure shows that immediately after returning from 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.

Completion


So, we list the key features of the exploit. Addressing callbacks in user space at times when any kernel structures are in an intermediate state in the middle of a transaction that modifies them is the most common cause of vulnerabilities in the 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.

In this sense, the presented exploit looks rather ordinary. At the same time, many operation nuances were only briefly mentioned in the article or deliberately omitted.

For example, we did not stop at the exact view of the context menu, as well as of the actions performed on it, which lead to the correct position of the flags and the filling of the 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.

In conclusion, it is worth saying a few words about the update , fixing the explored vulnerability. A quick inspection of the patch showed that now the release of the buffer addressed by the 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