作者:维阵漏洞研究员--km1ng一、简述Syzkaller是Google开发的一款内核模糊测试工具,简单点说就是自动化向内核输入各种有效的、无效的、完全随机化的参数数据,并观察内核的运行状况,是否发生了panic、内存泄漏等问题,以此发现隐藏在内核中的漏洞近些年很多内核的CVE发现均来自于此,该工具的开发维护也相对活跃它不仅支持x86,还支持ARM、Power、MIPS等处理器,而且不仅支持Linux,还支持windows、FreeBSD、Fuchsia等系统,同时还能支持对远程物理机、本地虚拟机的测试,此外还能支持分布式多机器测试本篇文章侧重于使用,并无太多原理与代码分析,仅需一点linux使用基础即可,适合用于syzkaller入门,整个环境搭建和使用过程踩了很多坑,有不少是网上没提到的二、基础环境三、环境搭建3.1 Ubuntu虚拟机配置Ubuntu虚拟机配置如下图所示,因为需要编译Linux内核与syzkaller所以内存尽量的设置大一些Vmware自带的vmtools安装在Ubunut1804上不能与物理机之间互相拷贝文件可以尝试如下命令解决:
sudo apt updatesudo apt install open-vm-tools-desktop fuse
3.2 安装基本软件
sudo apt-get install debootstrapsudo apt install qemu-kvmsudo apt-get install subversionsudo apt-get install gitsudo apt-get install makesudo apt-get install qemusudo apt install libssl-dev libelf-devsudo apt-get install flex bison libc6-dev libc6-dev-i386 linux-libc-dev linux-libc-dev:i386 libgmp3-dev libmpfr-dev libmpc-devsudo apt-get install g++sudo apt-get install build-essentialsudo apt install gccsudo apt install openssh-server
安装go编程语言并没有使用apt install golang-go,使用apt安装的go编程语言版本为1.10,使用这个版本的go会在编译syzkaller时报错,所以在这选择下载安装1.17版本的go
wget https://dl.google.com/go/go1.17.6.linux-amd64.tar.gztar -zxvf go1.17.6.linux-amd64.tar.gz export GOPATH=/home/test/git/go/go //路径替换为自己虚拟机中的路径export GOROOT=/home/test/git/go/goexport PATH=$GOPATH/bin:$PATHexport PATH=$GOROOT/bin:$PATH
运行go命令可以执行,即为安装成功3.3 编译syzkaller使用下面的命令拉取编译syzkaller代码
git clone https://github.com/google/syzkaller.gitcd syzkallermake //这一步有可能会报错
如果出现卡死或killed process,使用dmesg | egrep -i -B100 'killed process'查看,如果为Out of memory即为内存不足这时可以先使用如下命令单独编译第一个文件:
GOOS=linux GOARCH=amd64 go build "-ldflags=-s -w -X github.com/google/syzkaller/prog.GitRevision= -X 'github.com/google/syzkaller/prog.gitRevisionDate='" -o ./bin/syz-manager github.com/google/syzkaller/syz-manager
查看bin目录下是否有编译好的syz-manager文件:继续使用make命令完成编译,如下图所示:如果单独编译第一个文件之后还是存在内存不足的问题,可以通过添加swap分区解决
dd if=/dev/zero of=/root/swapfile bs=1M count=1024 //创建要作为swap分区的文件:增加1GB大小的交换分区,则命令写法如下,其中的count等于想要的块的数量(bscount=文件大小)mkswap /root/swapfile #建立swap的文件系统swapon /root/swapfile #启用swap文件/root/swapfile swap swap defaults 0 0 //使系统开机时自启用,在文件/etc/fstab中添加
3.4 编译Linux内核git拉取linux代码:
git clone https://mirrors.tuna.tsinghua.edu.cn/git/linux.gitcd linux
如果拉取代码的时候报证书校验错误如下图所示:通过如下命令解决:
sudo apt updatesudo apt install -y libgnutls30
进入linux目录后使用如下命令进行配置:
make CC="/usr/bin/gcc" defconfigmake CC="/usr/bin/gcc" kvm_guest.config
配置完成后打开当前目录下的.config文件进行手动添加配置,添加内容如下:
CONFIG_KCOV=yCONFIG_DEBUG_INFO=yCONFIG_KASAN=yCONFIG_KASAN_INLINE=yCONFIG_CONFIGFS_FS=yCONFIG_SECURITYFS=y
再执行如下命令:
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 https://raw.githubusercontent.com/google/syzkaller/master/tools/create-image.sh -O create-image.shchmod +x create-image.sh./create-image.sh
wget命令下载文件失败,可以直接浏览器访问拷贝一份也不影响使用可以看到目录下出现stretch.id_rsa、stretch.id_rsa.pub、stretch.img文件即为成功3.6 运行syzkall这里需要打开Vmware虚拟机的虚拟化安装qemu虚拟工具
sudo apt-get install qemu-system-x86
在当前目录创建boot.sh文件,文件内容如下:
qemu-system-x86_64 \ -kernel linux/arch/x86/boot/bzImage \ -append "console=ttyS0 root=/dev/sda debug earlyprintk=serial slub_debug=QUZ"\ -hda ./stretch.img \ -net user,hostfwd=tcp::10021-:22 -net nic \ -enable-kvm \ -nographic \ -m 2560M \ -smp 2 \ -pidfile vm.pid \ 2>&1 | tee vm.log
运行boot.sh,出现Failed to start Remount Root and Kernel File Systems是上面配置文件没配置好,出现不能访问KVM为虚拟机设置问题运行qemu虚拟机有登录提示输入root如下图所示,无密码登录在Vmware虚拟机使用如下命令,以是否能登录qemu虚拟机判断qemu虚拟机的ssh服务是否成功启动(syzkaller需要使用ssh)
ssh -i stretch.id_rsa -p 10021 -o "StrictHostKeyChecking no" root@localhost
进入之前下载的syzkaller目录,创建my.cfg配置文件,文件内容如下:
{ "target": "linux/amd64", "http": "127.0.0.1:56741", "workdir": "/home/test/git/syzkaller/workdir", "kernel_obj": "/home/test/git/linux", "image": "/home/test/git/stretch.img", "sshkey": "/home/test/git/stretch.id_rsa", "syzkaller": "/home/test/git/syzkaller", "procs": 8, "type": "qemu", "vm": { "count": 4, "kernel": "/home/test/git/linux/arch/x86/boot/bzImage", "cpu": 2, "mem": 2048 }}
使用./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可以使用如下命令进行文件拷贝操作:
ip link set enp0s3 upscp -r test@10.0.2.2:/home/test/Desktop/net-tools-2.10 ./
拷贝完成后就可以执行ifconfig命令了,如下图所示:当使用boot.sh脚本运行qemu虚拟机,出现报错Failed to start Raise network interfaces的时候,再次执行ifconfig命令发现只存在lo网卡、enp0s3网卡未启动或未分配ip地址进行删除qemu虚拟机中的/etc/network/interfaces文件,新建interfaces文件,文件内容如下,拷贝到到qemu虚拟机/etc/network/interfaces路径
auto eth0iface eth0 inet dhcpauto enp0s3iface enp0s3 inet dhcp
多次使用boot.sh启动qemu虚拟机,有时报错Failed to start Raise network interfaces,然后使用ifconfig命令查看结果依旧存在ip地址本机网卡名不为eth0可以使用如下命令进行更改:
ip link set ens33 downip link set ens33 name eth0ip link set eth0 up
再次使用syzkaller 进行fuzz,效果会好很多,至于根本原因笔者目前也并未分析源码,以后可能会更新五、fuzz Linux驱动程序5.1 编译驱动在test.c中存在一个堆溢出的demo:编译内核模块的时候,涉及到一个linux header的问题(比如说我在5.4.0的系统下编译5.17的驱动)所以这里的Makefile如下:
CONFIG_MODULE_SIG=n obj-m += test.o EXTRA_CFLAGS += -fno-stack-protector -no-pieall: make -C /lib/modules/5.17.0-rc3-00316-gb81b1829e7e3/build M=$(PWD) modules
创建目录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文件中添加如下配置:
config TEST_MODULE tristate "Heap Overflow Test" default y help This file is to test a buffer overflow.
在char目录下的Makefile中添加obj-$(CONFIG_TEST_MODULE) += test.o进入linux源码目录重新make,编译后使用boot.sh启动虚拟机,进入proc目录,可以看到test,表明成功编译代码并加载5.2 添加syzkaller规则进入syzkaller/sys/linux/目录,新建proc_operation.txt,文件内容如下所示:
include <linux/fs.h> open$proc(file ptr[in, string["/proc/test"]], flags flags[proc_open_flags], mode flags[proc_open_mode]) fdread$proc(fd fd, buf buffer[out], count len[buf])write$proc(fd fd, buf buffer[in], count len[buf])close$proc(fd fd) proc_open_flags = O_RDONLY, O_WRONLY, O_RDWR, O_APPEND, FASYNC, O_CLOEXEC, O_CREAT, O_DIRECT, O_DIRECTORY, O_EXCL, O_LARGEFILE, O_NOATIME, O_NOCTTY, O_NOFOLLOW, O_NONBLOCK, O_PATH, O_SYNC, O_TRUNC, __O_TMPFILEproc_open_mode = S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP, S_IROTH, S_IWOTH, S_IXOTH
回到syzkaller目录,编译syz-extract和syz-sysgen:
make bin/syz-extractmake bin/syz-sysgen
使用syz-extract生成.const文件:
bin/syz-extract -os linux -sourcedir "/home/test/git/linux" -arch amd64 proc_operation.txt
生成了proc_operation.txt.const内容如下:接下来执行如下命令:
bin/syz-sysgenmake cleanmake //这里参考上面
修改my.cfg文件,在其中加上如下字段:
"enable_syscalls": [ "open$proc", "read$proc", "write$proc", "close$proc"],
5.3 fuzz linux 驱动程序使用bin/syz-manager -config my.cfg命令:syzkaller将其识别为空指针解引用错误六、总结从使用体验来讲这个框架进行漏洞发掘还是存在一定难度,尤其对一些具有复杂接口的内核模块来说更是如此,并且是使用go编写的增加了学习成本,但它确实挖出了不少漏洞值得学习
参考链接:1、syzkaller 环境搭建:https://kiprey.github.io/2021/11/syzkaller_1/#%E4%B8%89%E3%80%81crash-%E6%B5%8B%E8%AF%952、syzkaller的安装与运行:https://www.giantbranch.cn/2021/06/25/syzkaller%E7%9A%84%E5%AE%89%E8%A3%85%E4%B8%8E%E8%BF%90%E8%A1%8C/3、从0到1开始使用syzkaller进行Linux内核漏洞挖掘:https://bbs.pediy.com/thread-265405.htm#%E5%B0%9D%E8%AF%95%E4%BD%BF%E7%94%A8syzkaller%E6%8D%95%E6%8D%89%E4%B8%80%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84%E5%86%85%E6%A0%B8%E5%A0%86%E6%BA%A2%E5%87%BA4、Linux Kernel Pwn III:使用syzkaller进行漏洞挖掘:https://arttnba3.cn/2021/11/24/NOTE-0X06-LINUX-KERNEL-PWN-PART-III/#0x02-%E5%BC%80%E5%A7%8B%E4%BD%BF%E7%94%A8-syzkaller5、使用Syzkaller测试Linux内核:https://i-m.dev/posts/20200313-143737.html
0 评论