零基礎(chǔ)挖掘Linux內(nèi)核漏洞

一、簡(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)境

image.png

三、環(huán)境搭建

3.1 Ubuntu虛擬機(jī)配置

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

image.png

【一>所有資源獲取<一】
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文件:

image.png

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

image.png

如果單獨(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ò)誤如下圖所示:

image.png

通過(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
image.png

配置完成后打開(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
image.png

再執(zhí)行如下命令:

make CC="/usr/bin/gcc" olddefconfig

如果出現(xiàn)如下圖所示:


image.png

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

image.png

重新執(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ò)誤。


image.png

最后執(zhí)行如下命令即可完成編譯。

make CC="/usr/bin/gcc" -j64
image.png

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)拷貝一份也不影響使用。


image.png

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

image.png

3.6 運(yùn)行syzkall

這里需要打開(kāi)Vmware虛擬機(jī)的虛擬化。

image.png

安裝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ú)密碼登錄。

image.png

在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í)稍微有些慢需要等待一下。


image.png

四、解決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)不存在此命令。

image.png

目前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。

image.png

可以使用如下命令進(jìn)行文件拷貝操作:

ip link set enp0s3 up
scp -r test@10.0.2.2:/home/test/Desktop/net-tools-2.10 ./

拷貝完成后就可以執(zhí)行ifconfig命令了,如下圖所示:

image.png

當(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ì)更新。

image.png

五、fuzz Linux驅(qū)動(dòng)程序

5.1 編譯驅(qū)動(dòng)

在test.c中存在一個(gè)堆溢出的demo:

image.png

編譯內(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命令。


image.png

如果找不到
/lib/modules/5.17.0-rc3-00316-gb81b1829e7e3路徑,在linux源代碼目錄下執(zhí)行make modules_install /lib/module命令即可。

將test.c拷貝到linux/drivers/char目錄下:

image.png

在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,表明成功編譯代碼并加載。

image.png

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)容如下:

image.png

接下來(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命令:

image.png
image.png
image.png
image.png

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í)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容