-
-
[原创]Windows内核模糊测试之Interface-aware fuzzing
-
发表于: 2022-3-2 11:41 8119
-
Interface-aware fuzzing是通过将内核API函数的参数进行随机化,随后调用内核API来实现的。通过这种方式,可以主动地对内核模块进行测试,且覆盖面和深度都更加优异,性能可以得到显著的提高。这种模糊测试方法要解决如下的问题:
内核API数量那么多,要怎么样主动调用这些API才可以完成测试
每个API的参数个数各不相同,应当如何生成合适的值来完成测试
通过https://github.com/FSecureLABS/KernelFuzzer这个模糊测试器(附件是作者的PPT),看看它是如何解决上述问题的。
对于API的调用,显然不能通过常规的方式从相应的dll文件中慢慢调用进去,这样不仅运行效率低,参数不合法的时候都进不到内核,最关键的是找全这些函数的地址太耗时间的。
由于每个dll中的API,在将参数压入栈中以后,会通过ntdll中的相应存根函数进入内核。而这些存根函数是具有固定格式的,比如下面就是函数ReadProcessMemory在ntdll中执行的存根函数:
此时的esp指向的栈顶指针保存了该函数的参数,这里的eax保存的是服务号,进入内核以后,内核通过对该值进行运算,去SSDT表中找到相应的内核函数进行调用。0x7FFE0300则保存了进入内核的函数,所有的函数都是通过这种格式,从用户层发起调用进入内核的。因此,就可以参考这种格式来完成模糊测试。
KernelFuzzer中实现的相应调用的代码在bughut_syscall.asm和bughunt_syscall_x64.asm中完成的,其中bughut_syscall.asm代码如下:
有了输入点,就需要相应的输入数据才能完成测试,这里有两项输入数据,分别是调用号和参数。在https://github.com/tinysec/windows-syscall-table中,作者收集了各个版本的内核函数的调用号和参数个数。
如下是win7 sp0系统的内核函数的调用号和参数个数,id32和id64分别代表32位和64位系统的内核函数调用号,argc32和argc64则分别代表了32位系统和64位系统的内核函数的参数个数。
但是KernelFuzzer看起来并没有去获取内核函数的调用号与参数个数,对于调用号,只要按顺序调用下去就可以。而对于参数个数,只要在栈中压入足够多的参数也可以完成测试。
内核函数的参数可以分为以下三类:
不同类型的具体数值,比如字符型或者整型1,2,3
指向某块地址的指针
各种各样的句柄
对于第一类只需要随机生成相应大小的数值就好,第二类也只需要随机生成4字节(32位系统)大小的数值就可以,因为所有的指针都是4个字节,指向了某个地址。
句柄不可以随机生成一个数值,因此句柄值需要在句柄表中有相应的表项才可以作为合法的输入,因此在KerFuzzer的主函数中会在开启测试前先调用make_HANDLES函数随机生成一些合法的句柄,以下是关键的代码
make_HANDLES函数则是随机生成一些合法的句柄保存到全局变量HANDLES中,供测试函数使用
在测试函数bughunt_thread中是通过SYSCALL结构体来传递参数的,该结构体定义如下:
在bughunt_thread中,会按如下步骤进行测试:
随机获取syscall,此时结构中保存了调用号和参数个数及对应类型
为每个参数生成随机的数值
调用bughunt_syscall完成测试
部分代码如下:
这里的random_SYSCALLl函数是从全局数组SYSCALLS中随机获取数据,具体实现如下:
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
- [原创]CVE-2022-21882提权漏洞学习笔记 16382
- [原创]CVE-2021-1732提权漏洞学习笔记 19489
- [原创]CVE-2014-1767提权漏洞学习笔记 15192
- [原创]CVE-2018-8453提权漏洞学习笔记 18526
- [原创]CVE-2020-1054提权漏洞学习笔记 13542