样本分析
- 拿到样本后观察到这是个MFC程序,并且在资源段存在加密数据
- 在样本中找到解密这段shellcode的地方后将其dump出来,载入IDA分析
-
经过分析发现这段shellcode通过内存加载运行了位于其中的dll文件
-
将其dump出来后经过分析发现其实现了傀儡进程了那一套,替换的进程就是CVE-2019-1458的32位提权exp
漏洞分析
-
exp中首先根据不同系统版本使用不同方法获取了
NtUserMessageCall
的地址、并初始化了一些内核结构成员的偏移数组 -
随后根据不同系统版本采用了不同的池喷射对象,我测试的环境
Win7 x86 sp1
采用的是Palette
对象,因为在Win7中可以通过GdiSharedHandleTable
来泄露GDI对象的内核地址,所以在exp中通过不断的申请一对Palette对象,直到两者内核地址之差为0x2000,通过后面分析可知,该样本利用这个有条件的任意写修改了位于内存上方的Palette2的numberOfEntries
,然后通过越界写修改位于内存下方的Palette3的ptr_PALETTEENTRY
指针,从而将这个有条件的任意写漏洞转换为了任意地址读写signed int sub_401B40() { unsigned int v0; // edx HPALETTE palette1; // ebx HPALETTE palette2; // eax HPALETTE v3; // edi int v4; // edx unsigned int v5; // esi unsigned int v6; // eax bool v7; // cf bool v8; // zf HPALETTE v9; // eax int v10; // edx HPALETTE v11; // edi unsigned int v12; // eax v0 = Palettle_array_index; while ( v0 < 0xFFD ) { stru_4081C0.palVersion = 0x300; stru_4081C0.palNumEntries = palette_number; memset(stru_4081C0.palPalEntry, 1, 8192u); palette1 = CreatePalette(&stru_4081C0); palette2 = CreatePalette(&stru_4081C0); v3 = palette2; if ( !palette1 || !palette2 ) break; v4 = Palettle_array_index + 2; Palettle_array1[v4] = palette1; Palettle_array2[v4] = palette2; Palettle_array_index = v4; v5 = GetGdiKernelAddress(palette1); v6 = GetGdiKernelAddress(v3); v7 = v5 < v6; v8 = v5 == v6; if ( v5 >= v6 ) goto LABEL_9; if ( v6 - v5 == 0x2000 ) // 保证两个Palettle对象地址足够接近 { handle_Palettle_1 = palette1; kernelAddress_Palettle_1 = v5; handle_Palettle_2 = v3; kernelAddress_Palettle_2 = v6; LABEL_12: v9 = CreatePalette(&stru_4081C0); v10 = Palettle_array_index; v11 = v9; dword_4041A0[Palettle_array_index] = v9; Palettle_array_index = v10 + 1; v12 = GetGdiKernelAddress(v9); if ( v12 > kernelAddress_Palettle_2 && v12 - kernelAddress_Palettle_2 == 0x2000 ) { kernelAddress_Palettle_3 = v12; handle_Palettle_3 = v11; sub_4017F0(); return 1; } if ( v12 < kernelAddress_Palettle_1 && kernelAddress_Palettle_1 - v12 == 0x2000 ) { handle_Palettle_3 = handle_Palettle_2; kernelAddress_Palettle_3 = kernelAddress_Palettle_2; handle_Palettle_2 = handle_Palettle_1; handle_Palettle_1 = v11; kernelAddress_Palettle_2 = kernelAddress_Palettle_1; kernelAddress_Palettle_1 = v12; sub_4017F0(); return 1; } } else { v7 = v5 < v6; v8 = v5 == v6; LABEL_9: if ( !v7 && !v8 && v5 - v6 == 0x2000 ) { handle_Palettle_2 = palette1; kernelAddress_Palettle_2 = v5; handle_Palettle_1 = v3; kernelAddress_Palettle_1 = v6; goto LABEL_12; } } }
-
随后创建了一个
MySwitchWnd
窗口并调用NtUserMessageCall
,通过在IDA中分析win32k!NtUserMessageCall
后发现这只是一个分发函数,其最终的处理函数由其参数Msg和dwType
决定,通过windbg中调试发现在Msg = 0x1 dwType = 0xE0
时,最终的调用流向了win32k!xxxWrapSwitchWndProc -
通过windbg动态调试发现
gpsi->mpFnid_serverCBWndProc[6]
为0,而exp中创建的窗口的Class中将cbwndExtra
设置为4,且新创建的窗口cbwndExtra
的内容为0,因此通过此次NtUserMessageCall
调用绕过了一下三个检查成功将hwnd->fnid
设置为0x2A0(FNDI_SWITCH) -
再接着回来分析exp,发现其通过
SetWindowLongW
将hwnd->cbwndExtra
设置为Palette内核地址-0x40,随后创建了#32771
窗口,这个窗口类在msdn中解释为用于任务切换窗口,通过分析发现创建这个窗口可以将gpsi->mpFnid_serverCBWndProc[6]
设置为0xB4,因此可以绕过后面的检查,然后通过SetKeyboardState
将ALT键的状态设置为press,最后再次调用了NtUserMessageCall
-
在第二次调用
NtUserMessageCall
时Msg = 0x14
并且此时hwnd->fnid = 0x2A0
,因此调用在xxxSwitchWndProc
中流向了xxxPaintSwitchWindow
-
在
xxxPaintSwitchWindow
中调用Getpswi
检查了a1->cbwndExtra + 0xB0 != gpsi->mpFnid_serverCBWndProc[6]
,由于在前面样本中已经创建了#32771
窗口来将gpsi->mpFnid_serverCBWndProc[6]
初始化为0xB4,因此Getpswi
在检查通过后返回了hwnd->cbwndExtra
的值,在简单的检查了当前ALT
键是否被按下后调用了_GetClientRect
漏洞函数。现在我们知道v1 = a1->cbwndExtra = kernelAddress_Palettle_2 - 0x40
,因此_GetClientRect
第二个参数v1 + 0x48之后其实是指向了 kernelAddress_Palettle_2 + 8 -
在
_GetClientRect
中我们观察到了有对第二个参数(也就是kernelAddress_Palettle_2 + 8)赋值的操作,并且在windbg中观察到lprc[3]
就是kernelAddress_Palettle->numberOfEntries
的地址,其被赋值为a1->rcClient.bottom
,这个值是由我们创建窗口的大小和位置决定的,exp中这个值为0x7000。因此通过被扩大的kernelAddress_Palettle->numberOfEntries
来达到越界修改的效果 -
在
kernelAddress_Palettle->numberOfEntries
被增大为0x7000后,就可以通过GetPaletteEntries
和setPaletteEntries
构造读写原语 -
构造好读写原语后,exp中采用了读取system token并替换指定进程token的方式进行了提权
参考链接
https://github.com/piotrflorczyk/cve-2019-1458_POC
样本文件:https://github.com/DreamoneOnly/CVE-2019-1458-malware/tree/master