一、簡(jiǎn)述
Syzkaller是Google開(kāi)發(fā)的一款內(nèi)核模糊測(cè)試工具,簡(jiǎn)單點(diǎn)說(shuō)就是自動(dòng)化向內(nèi)核輸入各種有效的、無(wú)效的、完全隨機(jī)化的參數(shù)數(shù)據(jù),并觀察內(nèi)核的運(yùn)行狀況,是否發(fā)生了panic、內(nèi)存泄漏等問(wèn)題,以此發(fā)現(xiàn)隱藏在內(nèi)核中的漏洞。近些年很多內(nèi)核的CVE發(fā)現(xiàn)均來(lái)自于此,該工具的開(kāi)發(fā)維護(hù)也相對(duì)活躍。它不僅支持x86,還支持ARM、Power、MIPS等處理器,而且不僅支持Linux,還支持windows、FreeBSD、Fuchsia等系統(tǒng),同時(shí)還能支持對(duì)遠(yuǎn)程物理機(jī)、本地虛擬機(jī)的測(cè)試,此外還能支持分布式多機(jī)器測(cè)試。
本篇文章側(cè)重于使用,并無(wú)太多原理與代碼分析,僅需一點(diǎn)linux使用基礎(chǔ)即可,適合用于syzkaller入門,整個(gè)環(huán)境搭建和使用過(guò)程踩了很多坑,有不少是網(wǎng)上沒(méi)提到的。
二、基礎(chǔ)環(huán)境

三、環(huán)境搭建
3.1 Ubuntu虛擬機(jī)配置
Ubuntu虛擬機(jī)配置如下圖所示,因?yàn)樾枰幾gLinux內(nèi)核與syzkaller所以內(nèi)存盡量的設(shè)置大一些。

【一>所有資源獲取<一】
1、網(wǎng)絡(luò)安全學(xué)習(xí)路線
2、電子書(shū)籍(白帽子)
3、安全大廠內(nèi)部視頻
4、100份src文檔
5、常見(jiàn)安全面試題
6、ctf大賽經(jīng)典題目解析
7、全套工具包
8、應(yīng)急響應(yīng)筆記
Vmware自帶的vmtools安裝在Ubunut1804上不能與物理機(jī)之間互相拷貝文件可以嘗試如下命令解決:
sudo apt update
sudo apt install open-vm-tools-desktop fuse
3.2 安裝基本軟件
sudo apt-get install debootstrap
sudo apt install qemu-kvm
sudo apt-get install subversion
sudo apt-get install git
sudo apt-get install make
sudo apt-get install qemu
sudo apt install libssl-dev libelf-dev
sudo apt-get install flex bison libc6-dev libc6-dev-i386 linux-libc-dev linux-libc-dev:i386 libgmp3-dev libmpfr-dev libmpc-dev
sudo apt-get install g++
sudo apt-get install build-essential
sudo apt install gcc
sudo apt install openssh-server
安裝go編程語(yǔ)言并沒(méi)有使用apt install golang-go,使用apt安裝的go編程語(yǔ)言版本為1.10,使用這個(gè)版本的go會(huì)在編譯syzkaller時(shí)報(bào)錯(cuò),所以在這選擇下載安裝1.17版本的go。
wget https://dl.google.com/go/go1.17.6.linux-amd64.tar.gz
tar -zxvf go1.17.6.linux-amd64.tar.gz
export GOPATH=/home/test/git/go/go //路徑替換為自己虛擬機(jī)中的路徑
export GOROOT=/home/test/git/go/go
export PATH=$GOPATH/bin:$PATH
export PATH=$GOROOT/bin:$PATH
運(yùn)行g(shù)o命令可以執(zhí)行,即為安裝成功。
3.3 編譯syzkaller
使用下面的命令拉取編譯syzkaller代碼。
git clone https://github.com/google/syzkaller.git
cd syzkaller
make //這一步有可能會(huì)報(bào)錯(cuò)
如果出現(xiàn)卡死或killed process,使用dmesg | egrep -i -B100 'killed process'查看,如果為Out of memory即為內(nèi)存不足。這時(shí)可以先使用如下命令單獨(dú)編譯第一個(gè)文件:
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文件:

繼續(xù)使用make命令完成編譯,如下圖所示:

如果單獨(dú)編譯第一個(gè)文件之后還是存在內(nèi)存不足的問(wèn)題,可以通過(guò)添加swap分區(qū)解決。
dd if=/dev/zero of=/root/swapfile bs=1M count=1024 //創(chuàng)建要作為swap分區(qū)的文件:增加1GB大小的交換分區(qū),則命令寫法如下,其中的count等于想要的塊的數(shù)量(bs*count=文件大?。?。
mkswap /root/swapfile #建立swap的文件系統(tǒng)
swapon /root/swapfile #啟用swap文件
/root/swapfile swap swap defaults 0 0 //使系統(tǒng)開(kāi)機(jī)時(shí)自啟用,在文件/etc/fstab中添加
3.4 編譯Linux內(nèi)核
git拉取linux代碼:
git clone https://mirrors.tuna.tsinghua.edu.cn/git/linux.git
cd linux
如果拉取代碼的時(shí)候報(bào)證書(shū)校驗(yàn)錯(cuò)誤如下圖所示:

通過(guò)如下命令解決:
sudo apt update
sudo apt install -y libgnutls30
進(jìn)入linux目錄后使用如下命令進(jìn)行配置:
make CC="/usr/bin/gcc" defconfig
make CC="/usr/bin/gcc" kvm_guest.config

配置完成后打開(kāi)當(dāng)前目錄下的.config文件進(jìn)行手動(dòng)添加配置,添加內(nèi)容如下:
CONFIG_KCOV=y
CONFIG_DEBUG_INFO=y
CONFIG_KASAN=y
CONFIG_KASAN_INLINE=y
CONFIG_CONFIGFS_FS=y
CONFIG_SECURITYFS=y

再執(zhí)行如下命令:
make CC="/usr/bin/gcc" olddefconfig
如果出現(xiàn)如下圖所示:

再次打開(kāi).config文件發(fā)現(xiàn)剛才添加的配置被刪除了,那是因?yàn)榕渲梦募写嬖谌缦聢D所示:

重新執(zhí)行olddefconfig之前的所有配置命令,然后在.config文件中,刪除我們想添加配置的注釋命令所在的行如:# CONFIG_KCOV is not set,最后在上面重新添加配置,然后執(zhí)行make CC="/usr/bin/gcc" olddefconfig命令可以發(fā)現(xiàn)不會(huì)出現(xiàn)warning。
如果不刪除在之后進(jìn)行qemu虛擬化時(shí)會(huì)出現(xiàn)Failed to start Remount Root and Kernel File Systems的錯(cuò)誤。

最后執(zhí)行如下命令即可完成編譯。
make CC="/usr/bin/gcc" -j64

3.5 制作文件系統(tǒng)
使用如下命令:
wget https://raw.githubusercontent.com/google/syzkaller/master/tools/create-image.sh -O create-image.sh
chmod +x create-image.sh
./create-image.sh
wget命令下載文件失敗,可以直接瀏覽器訪問(wèn)拷貝一份也不影響使用。

可以看到目錄下出現(xiàn)stretch.id_rsa、stretch.id_rsa.pub、stretch.img文件即為成功。

3.6 運(yùn)行syzkall
這里需要打開(kāi)Vmware虛擬機(jī)的虛擬化。

安裝qemu虛擬工具。
sudo apt-get install qemu-system-x86
在當(dāng)前目錄創(chuàng)建boot.sh文件,文件內(nèi)容如下:
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
運(yùn)行boot.sh,出現(xiàn)Failed to start Remount Root and Kernel File Systems是上面配置文件沒(méi)配置好,出現(xiàn)不能訪問(wèn)KVM為虛擬機(jī)設(shè)置問(wèn)題。
運(yùn)行qemu虛擬機(jī)有登錄提示輸入root如下圖所示,無(wú)密碼登錄。

在Vmware虛擬機(jī)使用如下命令,以是否能登錄qemu虛擬機(jī)判斷qemu虛擬機(jī)的ssh服務(wù)是否成功啟動(dòng)(syzkaller需要使用ssh)。
ssh -i stretch.id_rsa -p 10021 -o "StrictHostKeyChecking no" root@localhost
進(jìn)入之前下載的syzkaller目錄,創(chuàng)建my.cfg配置文件,文件內(nèi)容如下:
{
"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命令運(yùn)行。運(yùn)行時(shí)稍微有些慢需要等待一下。

四、解決Failed to start Raise network interfaces錯(cuò)誤
執(zhí)行syz-manager或qemu模擬運(yùn)行的時(shí)候經(jīng)常會(huì)出現(xiàn)Failed to start Raise network interfaces錯(cuò)誤。
執(zhí)行boot.sh腳本,運(yùn)行起虛擬機(jī),執(zhí)行ifconfig命令,發(fā)現(xiàn)不存在此命令。

目前qemu虛擬機(jī)ping不通外網(wǎng)不能使用apt命令進(jìn)行安裝,所以這里選擇下載net-tools離線包編譯好,拷貝進(jìn)qemu虛擬機(jī)。
qemu虛擬機(jī)初始有默認(rèn)的ip為10.0.2.15,同時(shí)也會(huì)初始化物理機(jī)ip為10.0.2.2。

可以使用如下命令進(jìn)行文件拷貝操作:
ip link set enp0s3 up
scp -r test@10.0.2.2:/home/test/Desktop/net-tools-2.10 ./
拷貝完成后就可以執(zhí)行ifconfig命令了,如下圖所示:

當(dāng)使用boot.sh腳本運(yùn)行qemu虛擬機(jī),出現(xiàn)報(bào)錯(cuò)Failed to start Raise network interfaces的時(shí)候,再次執(zhí)行ifconfig命令發(fā)現(xiàn)只存在lo網(wǎng)卡、enp0s3網(wǎng)卡未啟動(dòng)或未分配ip地址。進(jìn)行刪除qemu虛擬機(jī)中的/etc/network/interfaces文件,新建interfaces文件,文件內(nèi)容如下,拷貝到到qemu虛擬機(jī)/etc/network/interfaces路徑。
auto eth0
iface eth0 inet dhcp
auto enp0s3
iface enp0s3 inet dhcp
多次使用boot.sh啟動(dòng)qemu虛擬機(jī),有時(shí)報(bào)錯(cuò)Failed to start Raise network interfaces,然后使用ifconfig命令查看結(jié)果依舊存在ip地址。
本機(jī)網(wǎng)卡名不為eth0可以使用如下命令進(jìn)行更改:
ip link set ens33 down
ip link set ens33 name eth0
ip link set eth0 up
再次使用syzkaller 進(jìn)行fuzz,效果會(huì)好很多,至于根本原因筆者目前也并未分析源碼,以后可能會(huì)更新。

五、fuzz Linux驅(qū)動(dòng)程序
5.1 編譯驅(qū)動(dòng)
在test.c中存在一個(gè)堆溢出的demo:

編譯內(nèi)核模塊的時(shí)候,涉及到一個(gè)linux header的問(wèn)題。(比如說(shuō)我在5.4.0的系統(tǒng)下編譯5.17的驅(qū)動(dòng))所以這里的Makefile如下:
CONFIG_MODULE_SIG=n
obj-m += test.o
EXTRA_CFLAGS += -fno-stack-protector -no-pie
all:
make -C /lib/modules/5.17.0-rc3-00316-gb81b1829e7e3/build M=$(PWD) modules
創(chuàng)建目錄test,將test.c和Makefile拷貝到目錄下,運(yùn)行make命令。

如果找不到
/lib/modules/5.17.0-rc3-00316-gb81b1829e7e3路徑,在linux源代碼目錄下執(zhí)行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。
進(jìn)入linux源碼目錄重新make,編譯后使用boot.sh啟動(dòng)虛擬機(jī),進(jìn)入proc目錄,可以看到test,表明成功編譯代碼并加載。

5.2 添加syzkaller規(guī)則
進(jìn)入syzkaller/sys/linux/目錄,新建proc_operation.txt,文件內(nèi)容如下所示:
include <linux/fs.h>
open$proc(file ptr[in, string["/proc/test"]], flags flags[proc_open_flags], mode flags[proc_open_mode]) fd
read$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_TMPFILE
proc_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-extract
make 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內(nèi)容如下:

接下來(lái)執(zhí)行如下命令:
bin/syz-sysgen
make clean
make //這里參考上面
修改my.cfg文件,在其中加上如下字段:
"enable_syscalls": [
"open$proc",
"read$proc",
"write$proc",
"close$proc"
],
5.3 fuzz linux 驅(qū)動(dòng)程序
使用bin/syz-manager -config my.cfg命令:




syzkaller將其識(shí)別為空指針解引用錯(cuò)誤。
六、總結(jié)
從使用體驗(yàn)來(lái)講這個(gè)框架進(jìn)行漏洞發(fā)掘還是存在一定難度,尤其對(duì)一些具有復(fù)雜接口的內(nèi)核模塊來(lái)說(shuō)更是如此,并且是使用go編寫的增加了學(xué)習(xí)成本,但它確實(shí)挖出了不少漏洞值得學(xué)習(xí)。