web 安全之挖掘 Linux 内核漏洞
一、简述
Syzkaller 是 Google 开发的一款内核模糊测试工具,简单点说就是自动化向内核输入各种有效的、无效的、完全随机化的参数数据,并观察内核的运行状况,是否发生了 panic、内存泄漏等问题,以此发现隐藏在内核中的漏洞。近些年很多内核的 CVE 发现均来自于此,该工具的开发维护也相对活跃。它不仅支持 x86,还支持 ARM、Power、MIPS 等处理器,而且不仅支持 Linux,还支持 windows、FreeBSD、Fuchsia 等系统,同时还能支持对远程物理机、本地虚拟机的测试,此外还能支持分布式多机器测试。
本篇文章侧重于使用,并无太多原理与代码分析,仅需一点 linux 使用基础即可,适合用于 syzkaller 入门,整个环境搭建和使用过程踩了很多坑,有不少是网上没提到的。
二、基础环境

【一>所有资源获取<一】1、网络安全学习路线 2、电子书籍(白帽子)3、安全大厂内部视频 4、100 份 src 文档 5、常见安全面试题 6、ctf 大赛经典题目解析 7、全套工具包 8、应急响应笔记
三、环境搭建
3.1 Ubuntu 虚拟机配置
Ubuntu 虚拟机配置如下图所示,因为需要编译 Linux 内核与 syzkaller 所以内存尽量的设置大一些。

Vmware 自带的 vmtools 安装在 Ubunut1804 上不能与物理机之间互相拷贝文件可以尝试如下命令解决:
3.2 安装基本软件
安装 go 编程语言并没有使用 apt install golang-go,使用 apt 安装的 go 编程语言版本为 1.10,使用这个版本的 go 会在编译 syzkaller 时报错,所以在这选择下载安装 1.17 版本的 go。
运行 go 命令可以执行,即为安装成功。
3.3 编译 syzkaller
使用下面的命令拉取编译 syzkaller 代码。
如果出现卡死或 killed process,使用 dmesg | egrep -i -B100 ‘killed process’查看,如果为 Out of memory 即为内存不足。这时可以先使用如下命令单独编译第一个文件:
查看 bin 目录下是否有编译好的 syz-manager 文件:

继续使用 make 命令完成编译,如下图所示:

如果单独编译第一个文件之后还是存在内存不足的问题,可以通过添加 swap 分区解决。
3.4 编译 Linux 内核
git 拉取 linux 代码:
如果拉取代码的时候报证书校验错误如下图所示:

通过如下命令解决:
进入 linux 目录后使用如下命令进行配置:

配置完成后打开当前目录下的.config 文件进行手动添加配置,添加内容如下:

再执行如下命令:make CC="/usr/bin/gcc" olddefconfig
如果出现如下图所示:

再次打开.config 文件发现刚才添加的配置被删除了,那是因为配置文件中存在如下图所示:

重新执行 olddefconfig 之前的所有配置命令,然后在.config 文件中,删除我们想添加配置的注释命令所在的行如:# CONFIG_KCOV is not set,最后在上面重新添加配置,然后执行 make CC=”/usr/bin/gcc” olddefconfig 命令可以发现不会出现 warning。
如果不删除在之后进行 qemu 虚拟化时会出现 Failed to start Remount Root and Kernel File Systems 的错误。

最后执行如下命令即可完成编译。make CC="/usr/bin/gcc" -j64

3.5 制作文件系统
使用如下命令:
wget 命令下载文件失败,可以直接浏览器访问拷贝一份也不影响使用。

可以看到目录下出现 stretch.id_rsa、stretch.id_rsa.pub、stretch.img 文件即为成功。

3.6 运行 syzkall
这里需要打开 Vmware 虚拟机的虚拟化。

安装 qemu 虚拟工具。
sudo apt-get install qemu-system-x86
在当前目录创建 boot.sh 文件,文件内容如下:
运行 boot.sh,出现 Failed to start Remount Root and Kernel File Systems 是上面配置文件没配置好,出现不能访问 KVM 为虚拟机设置问题。
运行 qemu 虚拟机有登录提示输入 root 如下图所示,无密码登录。

在 Vmware 虚拟机使用如下命令,以是否能登录 qemu 虚拟机判断 qemu 虚拟机的 ssh 服务是否成功启动(syzkaller 需要使用 ssh)。
进入之前下载的 syzkaller 目录,创建 my.cfg 配置文件,文件内容如下:
使用./bin/syz-manager -config my.cfg 命令运行。运行时稍微有些慢需要等待一下。

四、解决 Failed to start Raise network interfaces 错误
执行 syz-manager 或 qemu 模拟运行的时候经常会出现 Failed to start Raise network interfaces 错误。
执行 boot.sh 脚本,运行起虚拟机,执行 ifconfig 命令,发现不存在此命令。

目前 qemu 虚拟机 ping 不通外网不能使用 apt 命令进行安装,所以这里选择下载 net-tools 离线包编译好,拷贝进 qemu 虚拟机。
qemu 虚拟机初始有默认的 ip 为 10.0.2.15,同时也会初始化物理机 ip 为 10.0.2.2。

可以使用如下命令进行文件拷贝操作:
拷贝完成后就可以执行 ifconfig 命令了,如下图所示:

当使用 boot.sh 脚本运行 qemu 虚拟机,出现报错 Failed to start Raise network interfaces 的时候,再次执行 ifconfig 命令发现只存在 lo 网卡、enp0s3 网卡未启动或未分配 ip 地址。进行删除 qemu 虚拟机中的/etc/network/interfaces 文件,新建 interfaces 文件,文件内容如下,拷贝到到 qemu 虚拟机/etc/network/interfaces 路径。
多次使用 boot.sh 启动 qemu 虚拟机,有时报错 Failed to start Raise network interfaces,然后使用 ifconfig 命令查看结果依旧存在 ip 地址。
本机网卡名不为 eth0 可以使用如下命令进行更改:
ip link set ens33 down ip link set ens33 name eth0 ip link set eth0 up
再次使用 syzkaller 进行 fuzz,效果会好很多,至于根本原因笔者目前也并未分析源码,以后可能会更新。

五、fuzz Linux 驱动程序
5.1 编译驱动
在 test.c 中存在一个堆溢出的 demo:

编译内核模块的时候,涉及到一个 linux header 的问题。(比如说我在 5.4.0 的系统下编译 5.17 的驱动)所以这里的 Makefile 如下:
创建目录 test,将 test.c 和 Makefile 拷贝到目录下,运行 make 命令。

如果找不到/lib/modules/5.17.0-rc3-00316-gb81b1829e7e3
路径,在 linux 源代码目录下执行make modules_install /lib/module
命令即可。

将 test.c 拷贝到 linux/drivers/char 目录下:
在 char 目录下的 Kconfig 文件中添加如下配置:
在 char 目录下的 Makefile 中添加 obj-$(CONFIG_TEST_MODULE) += test.o。
进入 linux 源码目录重新 make,编译后使用 boot.sh 启动虚拟机,进入 proc 目录,可以看到 test,表明成功编译代码并加载。

5.2 添加 syzkaller 规则
进入 syzkaller/sys/linux/目录,新建 proc_operation.txt,文件内容如下所示:
回到 syzkaller 目录,编译 syz-extract 和 syz-sysgen:
使用 syz-extract 生成.const 文件:
生成了 proc_operation.txt.const 内容如下:

接下来执行如下命令:
5.3 fuzz linux 驱动程序
使用 bin/syz-manager -config my.cfg 命令:




syzkaller 将其识别为空指针解引用错误。
六、总结
从使用体验来讲这个框架进行漏洞发掘还是存在一定难度,尤其对一些具有复杂接口的内核模块来说更是如此,并且是使用 go 编写的增加了学习成本,但它确实挖出了不少漏洞值得学习。
评论