导语:在这个系列文章中,我们将为读者详细介绍如何利用Google Project Zero最近公布的一个Windows内核漏洞来实现特权提升。这里之所以使用这个漏洞,不仅在于它“好使”,而且易于理解,最重要的是32位的Windows 10 Creator版本仍然存在该漏洞。

在这个系列文章中,我们将为读者详细介绍如何利用Google Project Zero最近公布的一个Windows内核漏洞来实现特权提升。这里之所以使用这个漏洞,不仅在于它“好使”,而且易于理解,最重要的是32位的Windows 10 Creator版本仍然存在该漏洞。

所以….让我们开始吧。

漏洞概述

通过阅读该漏洞的相关报告,发现它涉及Windows 10的32位Creators Update版本。之所以会出现这个漏洞,是由于被添加到NtQuerySystemInformation中的一个新的信息类(名为“WARBIRD”)在32位版本的Windows 10上没有得到正确处理所导致的。

当漏洞被触发时,内核指令指针被设置为NULL。通常来说,在现代操作系统中,为了避免这种类型的漏洞被攻击者所利用,会限制使用内存地址0h。然而,谷歌的研究人员发现,在Windows上启用了16位支持的情况下,特别是通过NTVDM使用NULL地址来支持16位应用程序的执行的情况下,这类漏洞仍然是可以加以利用的。

在编写我们的漏洞利用代码之前,我们需要复现这个漏洞。所以,下面先来介绍如何搭建实验环境。

搭建实验环境

为了搭建实验环境,我们需要用到一些VM:

Windows 10 Creators Update x86——这是含有内核漏洞的主机
Windows与WinDBG——这是我们的内核调试主机

在含有内核漏洞的主机上,我们需要使用以下命令来启用16位支持:

FONDUE.exe /enable-feature:NTVDM

我们还需要启用内核调试,为此可以使用下列命令:

bcdedit /debug on
bcdedit /dbgsettings NET HOSTIP:<WINDBG_HOST> PORT:50000

在执行上述命令时,会为您提供一个密钥,当WinDBG在启动过程中连接主机时会用到该密钥。在我们的内核调试主机中,启动WinDBG,并通过“File -> Kernel Debug”来设置内核调试会话,这时会用到上面提到的密钥:

windbg_kernel-1

重新启动含有内核漏洞的主机,这时会在WinDBG中打开内核调试器会话,这样有助于在漏洞利用过程中更加轻松地了解内核状态:

windbg_established

完成上述操作之后,我们再来介绍在利用这个安全漏洞过程中涉及到的一个重要概念:进程注入。

进程注入

在该漏洞的报告中,研究人员指出:

如果我们生成一个16位的应用程序(例如debug.exe),并将我们的漏洞利用代码注入ntvdm的话,在通过nt!WbAddLookupEntryEx对地址0进行写入操作时,系统就不会立即崩溃了。

它对于这里的漏洞利用代码来说是非常重要的,因此,我们需要了解进程注入是如何工作的,以及如何使用这种技术让NTVDM在其地址空间内执行我们的代码,从而允许我们利用NULL映射页面。

Windows上的进程注入通常涉及许多Win32 API,具体为:

OpenProcess
VirtualAllocEx
WriteProcessMemory
CreateRemoteThread

下面,我们对这些调用进行详尽的说明:

OpenProcess:这个调用可以通过PID来获取Windows进程的句柄,我们可以通过这个句柄对相应的进程采取进一步的操作。

VirtualAllocEx:这个调用用于在目标进程中分配内存,为我们预留空间,以便存放我们的自定义代码,或者将参数传递给远程线程。

WriteProcessMemory:提供一个地址和一个进程句柄,我们可以通过这个调用将数据复制到远程进程地址空间。

CreateRemoteThread:我们可以通过它在远程进程中创建一个新的线程,并指定执行的起始位置。

使用这些API调用,我们可以将shellcode注入到NTVDM进程中,但是为了简单起见,我们这里将把一个DLL加载到NTVDM中。这样做的好处是,我们可以直接使用诸如Visual Studio之类的工具来创建一个DLL,在其中保存我们的漏洞利用代码,这样的话,在运行时就不必担心诸如API解析之类的问题了。

为了加载我们的DLL,将用到另一个Win32 API调用LoadLibrary,它的作用是获取DLL的路径,并将其动态加载到进程地址空间中。因此,我们需要构造一个注入工具,以便:

使用OpenProcess获取NTVDM进程的句柄。

使用VirtualAllocEx分配足够的空间来复制我们的LoadLibrary参数值,这个值就是我们的漏洞利用DLL的路径。

使用WriteProcessMemory将我们的漏洞利用DLL路径写入远程分配的内存中。

最后,使用CreateRemoteThread生成一个线程并在远程进程中执行LoadLibrary调用,将我们复制的DLL路径地址作为参数进行传递。

构建完成后,我们的注入代码如下所示:

如果我们用一个非常简单的DLL来完成上述任务的话,NTVDM就能够顺利调用我们的代码:

dll_injection_test

构建漏洞利用代码

现在,我们已经可以将任意DLL加载到NTVDM进程中了,接下来,我们开始考虑如何构建漏洞利用代码了。下面是触发该漏洞的示例代码:

BYTE Buffer[8];
DWORD BytesReturned;
RtlZeroMemory(Buffer, sizeof(Buffer));
NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)185, Buffer, sizeof(Buffer), &BytesReturned);
RtlCopyMemory(NULL, "xcc", 1);
RtlZeroMemory(Buffer, sizeof(Buffer));
NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)185, Buffer, sizeof(Buffer), &BytesReturned);

如果将这段代码添加到一个DLL中,并将其注入到NTVDM进程中,我们会发现WinDBG将触发下面的断点:

interrupt_hit

我们可以看到,EIP是00000000h,我们的中断已经被触发了….真棒,我们现在已经控制了内核代码的执行:)

小结

在这个系列文章中,我们将为读者详细介绍如何利用Google Project Zero最近公布的一个Windows内核漏洞来实现特权提升。首先,我们就本文中利用的内核漏洞进行了介绍,然后为读者介绍了如何搭建实验环境,然后对进程注入的概念进行了说明,最后详细介绍了如何构建弄懂利用代码。

接下来,我们将开始着手编写shellcode——也就是我们的漏洞利用代码执行的shellcode。

源链接

Hacking more

...