-
-
[翻译]Windows exploit开发系列教程第十三部分:内核利用程序之未初始化栈变量
-
发表于: 2018-3-14 20:26 4218
-
点击查看原文
欢迎回到Windows exp开发系列教材的第13部分。今天我们将编写一个基于HEVD有漏洞驱动的未初始化栈变量exp。调试环境的安装请参考第十部分。让我们开始吧!
简单的看一下有问题的函数(here)。
如果我们传入一个正确的魔数,它会填充变量以及回调参数。如果传递的值不正确那么就不会填充。这里的问题在于变量定义时并没有设置一个特定的初始值。由于该变量布局在栈上,它会拥有一个前调用函数遗留的随机垃圾值。注意到这样的一个检查(if UninitializedStackVariable.Callback...)毫无卵用并不能阻止其崩溃。
该函数的IOCTL码是0x22202F。可以查看本系列教程的第十部分和第十一部分来了解IOCTL是如何被识别的。转入IDA来看看这个函数。
思考一下上图的4个函数块。如果比较成功我们就会命中绿色块,在这里我们的变量被填充了适当的值,此后在红色块中当回调函数被调用时也不会出什么意外。
不错,然而如果我们比较失败了,跳过了绿色快,继续下行调用函数的时候,我们调用的将是一个内核栈上的垃圾值!
这个值是不固定的,如果你尝试重现,很可能会在Windbg中看到不同的值。在虚拟机BSOD之前,让我们快速的看一下该变量距离当前栈起始位置有多远。
计算方式:0x8a15ced0 - 0x8a15c9cc = 0x504 (1284 bytes)
让我们重新执行并对BSOD进行心智健全检查。
如果我们可以覆盖内核栈上的整型指针为我们shellcode的地址就大功告成了,但是这要怎么做呢?看起来内核栈喷射是个办法,我强烈推荐你去阅读@j00ru的这篇文章 。有一个未文档化的函数,NtMapUserPhysicalPages,我们不关心它用于干什么,但它的一部分功能是拷贝输入的字节到内核栈上的一个本地缓冲区。最大尺寸可以拷贝1024*IntPtr::Size(32位机器上是4字节=>4096字节)。对我们的需求来说足够了,下面的POC用以展示!
我们在NtMapUserPhysicalPages函数返回前下一个断点,运行POC以检阅内核栈。
完美,在NtMapUserPhysicalPages返回后,栈应该被设置下去。因此我们可以污染该未初始化栈变量并调用该驱动函数。注意到该喷射是不连续的,巡视之后我发现栈上有大小相当的块(sizable chunks)但是他们被存储的值分割开来(我推测)。幸运的是,我们需要的偏移处可以被正确设置。
还有个关键点是栈不是一成不变的,因此最好在恰好触发bug之前进行喷射,这可以避免缓冲区被更少的操作修改。
再一次,我们覆盖该函数调用为那个重用的窃取token的shellcode地址,它和前面的章节一致无需任何修改。
我们的exp工作流将如下:(1)将shellcode放在内存任意位置,(2)使用指向shellcode的指针喷射内核栈,(3)触发未初始化变量漏洞。
这就是所有的内容,可以参考下面的完整exp来了解更多信息。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
- [翻译]Windows 10 Segment Heap内部机理 19880
- [翻译]Windows 8堆内部机理 7159
- [翻译]深入理解LFH 7787
- [翻译]Bitmap轶事:Windows 10纪念版后的GDI对象泄露 9296
- [翻译]理解池污染三部曲 6821