首页
社区
课程
招聘
[翻译]Windows内核漏洞利用教程3:任意内存写入
发表于: 2018-1-18 16:24 10726

[翻译]Windows内核漏洞利用教程3:任意内存写入

2018-1-18 16:24
10726

(译者注:ProbeForRead()函数如果检测打到所指定的地址不在用户态的内存范围,将会扔出一个异常STATUS_DATATYPE_MISALIGNMENT,看ArbitraryOverwrite.c源码可以知道在此处存在异常处理。)

译者注:注意观察shellcode的popad之后的堆栈平衡和上一片文章中的不太一样,主要是两者的堆栈状态不同,此处是在调用nt!HalDispatchTable+0x4之后直接返回到nt!NtQueryIntervalProfile+0x70位置,也就是调用nt!KeQueryIntervalProfile结束。也可以不出栈这么多,返回到 nt!HalDispatchTable+0x4调用结束即可,那么只需一个xor eax,eax /  ret 0x10即可。


原文地址:https://rootkits.xyz/blog/2017/09/kernel-write-what-where/

已经翻译:


上一篇文章中,我们了解了一个基本的内核缓冲区溢出漏洞的利用。

在这篇文章中,我们将关注另一个类型的漏洞,任意内存写入,也就是Write-What-Where漏洞。这种类型漏洞利用的基本思路是:将我们的shellcode指针写入内核分发表(Kernel Dispatch Table)中。

再一次感谢hacksystem提供的驱动模块和FuzzySec提供的分析报告。


让我们通过ArbitraryOverwrite.c文件的源码来分析这个漏洞:
#ifdef SECURE
//安全的代码:在执行写操作之前,对指向where和what的两个指针,利用ProbeForRead()函数判断是否属于用户态。
        *(Where) = *(What);
#else
        DbgPrint("[+] Triggering Arbitrary Overwrite\n");
//不安全的代码:这是一个常见的任意内存写入漏洞,
//代码对要写入的内容(What)的内存地址和写入的地址的指针(Where)没有检查是否属于用户态。
        *(Where) = *(What);

#ifdef SECURE
//安全的代码:在执行写操作之前,对指向where和what的两个指针,利用ProbeForRead()函数判断是否属于用户态。
        *(Where) = *(What);
#else
        DbgPrint("[+] Triggering Arbitrary Overwrite\n");
//不安全的代码:这是一个常见的任意内存写入漏洞,
//代码对要写入的内容(What)的内存地址和写入的地址的指针(Where)没有检查是否属于用户态。
        *(Where) = *(What);

(译者注:ProbeForRead()函数如果检测打到所指定的地址不在用户态的内存范围,将会扔出一个异常STATUS_DATATYPE_MISALIGNMENT,看ArbitraryOverwrite.c源码可以知道在此处存在异常处理。)


这是对漏洞和相应修复很好的展示。不安全的代码缺少对两个指针(What和Where)没有判断其属于用户空间还是内核空间。而安全的代码,使用ProbeForRead函数对这两个指针是否属于用户空间进行了判断。

现在我们对这个漏洞产生原因有了一定的理解,我们现在需要出发这个漏洞的IOCTL编号。在上一篇文章中,我们通过分析IrpDeviceCtlHandle的调用找到了IOCTL编号。这一次我们通过HackSysExtremeVulnerableDriver.h文件查看所有的IOCTL编号。
#define HACKSYS_EVD_IOCTL_ARBITRARY_OVERWRITE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_NEITHER, FILE_ANY_ACCESS)

#define HACKSYS_EVD_IOCTL_ARBITRARY_OVERWRITE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_NEITHER, FILE_ANY_ACCESS)

通过CTL_CODE宏创建了不同的系统IOCTL,并且通过这个宏,我们可以用下面的Python代码计算相应的IOCTL编号值。
hex((0x00000022 << 16) | (0x00000000 << 14) | (0x802 << 2) | 0x00000003)

hex((0x00000022 << 16) | (0x00000000 << 14) | (0x802 << 2) | 0x00000003)

这一次,我们要用到的IOCTL值是0x22200b.

接下来,使用IDA分析TriggerArbitraryOverwrite函数。


可以发现,这里有8个字节,前四个是写入内容的指针(What),后四个是写入地址的指针(Where)


让我们进入好玩的部分。我们使用上一篇文章中的脚本框架,修改IOCTL,观察是否可以正常运行。
import ctypes, sys, struct
from ctypes import *
from subprocess import *
 
def main():
    kernel32 = windll.kernel32
    psapi = windll.Psapi
    ntdll = windll.ntdll
    hevDevice = kernel32.CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", 0xC0000000, 0, None, 0x3, 0, None)
 
    if not hevDevice or hevDevice == -1:
        print "*** Couldn't get Device Driver handle"
        sys.exit(-1)
 
    buf = "A"*100
    bufLength = len(buf)
 
    kernel32.DeviceIoControl(hevDevice, 0x22200b, buf, bufLength, None, 0, byref(c_ulong()), None)
 
if __name__ == "__main__":
    main()
import ctypes, sys, struct
from ctypes import *
from subprocess import *
 
def main():
    kernel32 = windll.kernel32
    psapi = windll.Psapi
    ntdll = windll.ntdll
    hevDevice = kernel32.CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", 0xC0000000, 0, None, 0x3, 0, None)
 
    if not hevDevice or hevDevice == -1:
        print "*** Couldn't get Device Driver handle"
        sys.exit(-1)
 
    buf = "A"*100
    bufLength = len(buf)
 
    kernel32.DeviceIoControl(hevDevice, 0x22200b, buf, bufLength, None, 0, byref(c_ulong()), None)
 
if __name__ == "__main__":
    main()


正常运行。现在我们开始构建我们的漏洞利用。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 1
支持
分享
最新回复 (1)
雪    币: 1290
活跃值: (2332)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
2
围观
2020-2-9 15:43
0
游客
登录 | 注册 方可回帖
返回
//