内核漏洞挖掘技术系列(4)——syzkaller(3)

2019-05-19 约 2935 字 预计阅读 6 分钟

声明:本文 【内核漏洞挖掘技术系列(4)——syzkaller(3)】 由作者 houjingyi 于 2019-05-19 08:50:00 首发 先知社区 曾经 浏览数 87 次

感谢 houjingyi 的辛苦付出!

这是内核漏洞挖掘技术系列的第七篇。
第一篇:内核漏洞挖掘技术系列(1)——trinity
第二篇:内核漏洞挖掘技术系列(2)——bochspwn
第三篇:内核漏洞挖掘技术系列(3)——bochspwn-reloaded(1)
第四篇:内核漏洞挖掘技术系列(3)——bochspwn-reloaded(2)
第五篇:内核漏洞挖掘技术系列(4)——syzkaller(1)
第六篇:内核漏洞挖掘技术系列(4)——syzkaller(2)

在上一篇文章中我们聊了聊编写的系统调用模板被编译的过程,这篇文章从syz-manager入手分析,主要来看看crash复现的过程。syzkaller的使用是通过这条命令:./syz-manager -config=my.cfg
syzkaller\pkg\mgrconfig\testdata目录下提供的示例qemu.cfg如下。

{
    "target": "linux/amd64",
    "http": "myhost.com:56741",
    "workdir": "/syzkaller/workdir",
    "kernel_obj": "/linux/",
    "image": "/linux_image/wheezy.img",
    "sshkey": "/linux_image/ssh/id_rsa",
    "syzkaller": "/syzkaller",
    "disable_syscalls": ["keyctl", "add_key", "request_key"],
    "suppressions": ["some known bug"],
    "procs": 4,
    "type": "qemu",
    "vm": {
        "count": 16,
        "cpu": 2,
        "mem": 2048,
        "kernel": "/linux/arch/x86/boot/bzImage",
        "initrd": "linux/initrd"
    }
}

这些参数的含义如下(有一些上面的示例中没有)。
http:显示正在运行的syz-manager进程信息的URL
email_addrs:第一次出现bug时接收通知的电子邮件地址,只支持Mailx
workdir:syz-manager进程的工作目录的位置。产生的文件包括:

  • workdir/crashes/*:crash输出文件
  • workdir/corpus.db:包含一些程序的语料库
  • workdir/instance-x:每个VM实例临时文件

syzkaller:syzkaller的位置,syz-manager将在bin子目录中查找二进制文件
kernel_obj:包含目标文件的目录,例如linux中的vmlinux
procs:每个VM中的并行测试进程数,一般是4或8
image:QEMU实例的磁盘镜像文件的位置
sshkey:用于与虚拟机通信的root SSH ID的位置
sandbox:沙盒模式,支持以下模式:

  • none:默认设置,不做任何特殊的事情
  • setuid:冒充用户nobody(65534)
  • namespace:使用命名空间删除权限(内核需要使用CONFIG_NAMESPACES,CONFIG_UTS_NS,CONFIG_USER_NS,CONFIG_PID_NS和CONFIG_NET_NS构建)

enable_syscalls:测试的系统调用列表
disable_syscalls:禁用的系统调用列表
suppressions:已知错误的正则表达式列表
type:要使用的虚拟机类型,例如qemu
vm:特定VM类型相关的参数,例如对于qemu来说参数包括:

  • count:并行运行的VM数
  • kernel:要测试的内核的bzImage文件的位置
  • cmdline:启动内核的其它命令行选项,例如root=/dev/sda1
  • cpu:要在VM中模拟的CPU数
  • mem:VM的内存大小,以MB为单位

除了config参数以外,syz-manager还可以接受debug参数和bench参数。debug参数将VM所有输出打印到console帮助我们排查使用中出现的错误;bench参数定期将执行的统计信息写入我们指定的文件。

main函数中首先启用日志缓存的功能,缓存在内存中的日志不能超过1000行或者1^29个字节。然后加载config文件,获取操作系统和架构信息,检查是否支持。还记得syz-sysgen生成的.go文件中的RegisterTarget函数么?这里用GetTarget函数获取参数对应的target。

在qemu.cfg中可以看到通过disable_syscalls指定排除的syscall,同样可以通过enable_syscalls指定测试的syscall,如果没有这两个参数默认会fuzz所有的syscall。那么接下来就是通过ParseEnabledSyscalls解析这两个参数,之后就进入RunManager函数中了。


在RunManager函数中如果config文件中指定的type不为none则创建一个vmpool。将type指定为none是在调试开发中用的,这样manager就不会启动VM而是需要手动启动。

一个vmPool可以用来创建多个独立的VM。上一篇文章说过vm.go对不同的虚拟化方案提供了统一的接口,这里会调用到qemu.go的Ctor函数。其中主要检查了一些参数,所以这里不再展开。

接下来又经过一些初始化操作之后在一个线程中定期记录VM状态、crash数量等信息。如果设置了bench参数还要在指定的文件中记录一些信息。最后调用vmLoop函数。

crash被保存在reproQueue中,通过len(reproQueue) != 0判断当前是否有等待复现的crash。

vmIndexes := append([]int{}, instances[len(instances)-instancesPerRepro:]...)
instances = instances[:len(instances)-instancesPerRepro]

这两行代码把instances分成vmIndexes和instances两个部分,vmIndexes对crash进行复现,instances运行新的实例。我们先看Run函数复现部分的代码。在经过一些设置之后,主要是调用到了repro函数。

在repro函数中首先调用extractProg函数提取出触发crash的程序。Timeouts有三个取值:10s,1min和5min。10s是用来复现比较简单的crash用的,5min是用来复现条件竞争这样比较复杂的crash用的。如果单个程序无法复现,则采用二分查找的方法找出那些触发crash的程序。按照时间从短到长,从后向前(通常最后一个程序就是触发crash的程序),从单个到多个的顺序尝试复现出crash。


如果能够成功复现,则继续调用minimizeProg函数对其最小化。

minimizeProg函数主要调用了Minimize函数。

Minimize函数首先调用了SanitizeCall函数,因为有些系统调用需要做一些特殊的处理。


然后尝试逐个移除系统调用。

test中的例子如下,open系统调用被移除了。

之后再去除系统调用的无关参数。

在do函数中,根据不同的参数类型调用不同的minimize函数。

比如如果参数是指针类型的,把指针或者指针指向的内容置空。


如果参数是数组类型的,尝试一个一个移除数组中的元素。

之后,调用extractC函数提取出C程序。

extractC函数主要是调用了testCProg函数,后者调用csource中的Write函数生成C代码,csource中的Build函数编译出可执行文件。比较简单,所以不再详细分析。


接下来调用simplifyProg函数对之前的结果进行简化,simplifyProg函数再次调用extractC函数提取出C程序,然后调用simplifyC函数对提取出的C程序进行简化。这里简化的是复现crash时设置的一些选项,比如线程、并发、沙盒等等。


我们返回到manager.go中,这一部分的代码就分析完了。在下一篇文章中我们将介绍vmLoop函数中是怎么进行fuzz的。

关键词:[‘安全技术’, ‘二进制安全’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now