回归最本质的信息安全

;

HEVD 内核攻击:漏洞攻击的完全实现及SMEP绕过(四)

2017年3月30日发布

14,833
0
1

导语:到目前为止,我们还没有完全实现漏洞的攻击。让我们回顾一下第2篇里为DoS PoC创建的漏洞利用步骤,现在我们可以修改其中一些步骤,来实现SYSTEM shell。

1490159356577934.png

到目前为止,我们还没有完全实现漏洞的攻击。让我们回顾一下第2篇里为DoS PoC创建的漏洞利用步骤,现在我们可以修改其中一些步骤,来实现SYSTEM shell。

第一步,生成cmd.exe进程

虽然这一步非常简单,但是要在Python中实现,还是需要一些额外的代码,与C语言代码相比,我们将使用Kernel32.dll中的CreateProcess API来启动shell。查看函数原型,该函数需要为调用设置两个结构体,其中一个将使用我们启动的cmd.exe进程的PID返回给我们。稍后我们需要使用shellcode来设置我们的结构体。

第一个是STARTUPINFO结构体(STARTUPINFO是用于指定新进程的主窗口特性的一个结构)。使用Python ctypes可以在我们的脚本中重新创建STARTUPINFO结构体,如下所示:

1.png

我们可以在脚本中引用这个结构体,如下所示:

2.png

我们需要的是一个PROCESS_INFORMATION结构,因为这个结构更易于管理,在ctypes中看起来是这样:

3.png

这里包含了dwProcessId dword中创建的进程PID。通过创建这两个结构,我们可以参考CreateProcess函数原型并将我们的API调用放在一起:

4.png

第二步和第三步和第2篇里的过程一模一样,大家可以爬楼。

第四步,使用shellcode分配缓冲区

首先将shellcode翻译成Python。这也包括将cmd.exe进程的PID动态插入到shellcode中,这样我们就创建了一个可以接收我们需要的PID并创建shellcode的函数:

5.png

利用VirtualAlloc函数复制我们的shellcode区域,当然前提是确保指定的分配缓冲区是可执行的。假设一切顺利,我们就可以将shellcode复制到缓冲区(ctypes提供一个memmove()函数),然后返回shellcode所在的地址:

6.png

第五步,创建shellcode的缓冲区

这一步又与第2章提到的DoS PoC非常相似。不过,这一次,我们的函数还需要收到shellcode所在的分配地址,以便我们可以将它添加到我们的缓冲区。我们的DoS PoC缓冲区由2048“A”组成,其后是8“B”和8“C”。 “C”是在rip寄存器中结束的,所以我们要用我们的shellcode地址来替换它:

7.png

第六步,触发漏洞

首先生成cmd.exe并获取它的PID,然后分配shellcode并将该地址插入到我们创建的缓冲区。

8.png

如果一切顺利的话,会出现以下的情景:

1490248621316933.jpg

至此,漏洞就可以完全实现了。不过,我们在实际的测试中发现,这些漏洞攻击只是在Windows 8以前的系统版本中运行的很好,由于Windows 8及更高版本上已经配置了一些新的缓解措施,所以这些漏洞利用就会被禁止。

主管模式执行保护(SMEP)有点像ring 0模式下的DEP,是内核的一种缓解措施,我们可以将它简单的理解成禁止在内核态下执行用户空间的代码。换句话说,当以内核模式运行时,处理器将不会运行映射到用户模式存储器的指令。

在Windows 7版本中,我们是将shellcode复制到内存中。一旦我们劫持了内核中的执行流程,我们就会将其指向带有shellcode的用户内存缓冲区,但如果我们在启用了SMEP的系统上也这么做,那么一旦处理器试图执行用户内存缓冲区的任何指令,则运行就会中断。

正如开始的时候我说SMEP有点像DEP,绕过DEP比较常见的方法就是ROP链,因此绕过SMEP的常见方法也是比较简单的方法也是ROP链,在DEP中构造ROP链需要dll的基址,其实在SMEP中构造ROP链需要动态链接库内核的地址,而获取内核地址的一种非常好用的方法就是NtQuerySystemInformation。

那么我们如何绕过SMEP呢?最简单的途径就是简化CR4寄存器,以便让Windows认为是处理器不支持SMEP。这与我们的Windows 7 HEVD堆栈溢出漏洞大致相同,但在我们触发溢出之前,我们必须首先执行ROP链以禁用SMEP。为了构建我们的ROP链,我们必须找到内核的基址,总共分8步:

1.Spawn cmd.exe进程
2.使用shellcode分配缓冲区
3.获取内核基地址
4.构建ROP链
5.获取容易受到攻击的设备句柄
6.获取正确的IOCTL的堆栈溢出功能
7.创建一个将执行重定向到ROP链及shellcode的缓冲区
8.触发漏洞

以上只有第3步和第4步是新步骤,所以我们就直接来叙述这两个步骤,其余的步骤,请参看前文。

第三步,获取内核基址

就像绕过DEP比较常见的方法就是ROP链一样,我们可以使用ASLR,使用ROP来破坏内核中的SMEP可能会受到KASLR的阻碍。当然有各种方法来击败KASLR,但这不在本文的讨论范围之内。

简单来说,利用psapi.dll的EnumDeviceDrivers功能就可以实现这一目标,EnumDeviceDrivers可以检索系统中每个设备驱动程序的加载地址,其中包括返回结果中的实际内核:

10.png

第四步,建立ROP链

使用这一步的前提是,假设大家已经很熟悉ROP技术了。

现在我们已经得到了内核基地址,接下来我们将继续构建绕过SMEP的ROP链。这不是很难,因为这是一个非常小的ROP链,只需要把ntoskrnl.exe解析为几个字节数组。

我们的目的就是将控制值弹出到CR4寄存器中。在搜索到可用的ROP后,我们发现没有很多与CR4进行交互的指令,这时 ntoskrnl.exe中的KiFlushCurrentTbWorker函数实际上可以被利用起来:

11.png

接下来,我们只需要在内核的地址空间中找到POP RCX就可以了。最后,我们可以构建一个函数,该函数采用内核的基地址和shellcode的用户地址,将CR4值放在该函数中,最后在shellcode缓冲区得到以下代码:

12.png

至此,在Windows 8及更高版本上我们也实现了最终的漏洞利用:

1490248672840189.jpg

本文参考来源于sizzop.github.io,如若转载,请注明来源于嘶吼: http://www.4hou.com/technology/3952.html

点赞 1
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

xiaohui

嘶吼编辑

发私信

发表评论