【漏洞挖掘】使用Syzkaller&QEMU捕捉内核堆溢出Demo

参考:

        使用Syzkaller&QEMU捕捉内核堆溢出Demo   

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

        实验所需源码

本文主要参考第一篇文章,但是文章中很多步骤不全面,而且存在错误,故记录本实验过程。本实验前提是参照配置syzkaller&QEMU环境配置好syzkaller环境。

本文将演示使用Syzkaller联合QEMU触发一个内核溢出的bug。 包括三个步骤:

        (1)在syzkaller中添加规则触发堆溢出 

        (2)编译一个带有堆溢出模块的kernel

        (3)运行syzkaller&QEMU捕捉内核堆溢出

1.在syzkaller中添加规则

本例新增调用模板见proc_operation.txt,/syzkaller/sys/linux目录下的sys.txt中有通用的调用形式可以参考。

解释:syzkaller使用它自己的声明式语言来描述系统调用模板,docs目录下的syscall_descriptions.md中可以找到相关的说明。这些系统调用模板被翻译成syzkaller使用的代码需要经过两个步骤。第一步是使用syz-extract从linux源代码中提取符号常量的值,结果被存储在.const文件中,例如/sys/linux/tty.txt被转换为sys/linux/tty_amd64.const。第二步是根据系统调用模板和第一步中生成的const文件使用syz-sysgen生成syzkaller用的go代码。可以在/sys/linux/gen/amd64.go和/executor/syscalls.h中看到结果。最后,重新编译生成带有相应规则的syzkaller二进制可执行文件。

调用规则:$号前的syscallname是系统调用名,$号后的type是指特定类型的系统调用。如上文的 open$proc 指的就是open这个类调用中proc这个具体的调用,这个名字是由规则编写者确定的,具体行为靠的是后面的参数去确定。 参数的格式如下: ArgumentName ArgumentType[Limit] ArgumentName是指参数名,ArgumentType指的是参数类型,例如上述例子有string、flags等类型。[ ]号中的内容就是具体的类型的值,不指定的时候由syzkaller自动生成,若要指定须在后文指定,以上文为例:

            mode flags[proc_open_mode]

            proc_open_mode = ...

        因为我们给的例子是通过/proc/test这个内核接口的写操作来触发堆溢出,因此我们需要控制的参数是open函数中的file参数为“/proc/test”即可,其他操作参考sys.txt即可。

步骤

    (1)编译生成syz-extract

         ~/Desktop/ctf/kernel_fuzz/gopath/src/github.com/google/syzkaller$ make bin/syz-extract

    (2)编译生成syz-sysgen

        ~/Desktop/ctf/kernel_fuzz/gopath/src/github.com/google/syzkaller$ make bin/syz-sysgen

    (3)用syz-extract生成.const文件(本例proc_operation.txt有错误,read和write不需要返回值)可选择只生成你新增的.txt

        ~/Desktop/ctf/kernel_fuzz/gopath/src/github.com/google/syzkaller$ bin/syz-extract -os linux -sourcedir "/home/john/Desktop/ctf/kernel_

fuzz/linux/linux" -arch amd64 sys/linux/proc_operation.txt 

        同目录下生成了proc_operation_amd64.const。

    (4)然后运行syz-sysgen

        ~/Desktop/ctf/kernel_fuzz/gopath/src/github.com/google/syzkaller$ bin/syz-sysgen

    (5)重编译syzkaller

        进入syzkaller源码目录,运行:

            $ make clean

            $ make all

    (6)拷贝编译好的syz-fuzzer到目标系统:

            scp -P 10021 -i ./stretch.id_rsa -r ../gopath/bin root@127.0.0.1:/root/bin

2.编译带有堆溢出的内核模块

漏洞:代码见test.c,主要是proc_write()函数有堆溢出。

编译:参考https://www.cnblogs.com/zhangjy6/p/5462644.html

            $ make

            $ scp -P 10021 -i ./stretch.id_rsa -r ./test/test.ko root@127.0.0.1:/root/bin

            目标机器上$ sudo insmod test.ko

问题:无法insmod

        我本机linux-headers版本是4.4.0-103-generic,目标内核版本是5.2.0-rc1+(查看版本命令$ uname -r),编译出来的driver在目标机上无法ismod,需安装linux-headers-5.2.0-rc1+。

解决:安装linux-headers-5.2.0-rc1+方法,先在网页上找到对应版本的headers。

        $ wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.2-rc1/linux-headers-5.2.0-050200rc1_5.2.0-050200rc1.201905191930_all.deb

        $ wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.2-rc1/linux-headers-5.2.0-050200rc1-generic_5.2.0-050200rc1.201905191930_amd64.deb

        $ sudo dpkg -i *.deb

        修改KDIR =/usr/src/linux-headers-5.2.0-050200rc1-generic

结果:还是不匹配,很无奈,要么重新编译内核吧,我选择linux-4.4.0.184版本,大不了把本机内核也更新为这个版本。(参考https://www.itsmearunchandel.co.in/linux/ubuntu/upgrade-kernel-version-in-ubuntu.html; 内核源码https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.4.184/)

问题:应该更新了也还是不行,linux-headers-5.2.0-050200rc1-generic跟linux-headers-5.2.0-rc1+还是不匹配。

解决:将驱动模块编译进内核。所以要么把模块编译到目标内核,要么魔改许多module里的数据结构进行错版本加载。

        (参考https://blog.csdn.net/qq_33487044/article/details/81949703https://kouriba.iteye.com/blog/1632767

         make menuconfig->Enable loadable module support->Forced module loading(同时关闭Module versioning support,只开启前3个)。

        修改drvier目录下的MAKEFILE文件,在最后一行添加: obj-y += testmod/

        然后在testmode目录下,添加一个MAKEFILE 文件,文件的内容为:obj-m := hello.o

步骤如下

        (1)test.c拷贝到/linux/drivers/char/目录下

        (2)/linux/drivers/char/Kconfig下添加

            menu "Character devices"            #已有

            config TEST_MODULE

            tristate "Heap Overflow Test"        #在menuconfig中显示的名字

            default y                                        #默认选项

            help

                This file is to test a buffer overflow.

            endmenu              #已有

        (3)/linux/drivers/char/Makefile下添加

                obj-$(CONFIG_TEST_MODULE) += test.o

        (4)如果/linux/drivers/char/是新目录,需修改/linux/drivers/Kconfig(加上source "drivers/char/Kconfig");修改/linux/drivers/Makefile(加上obj-$(CONFIG_TEST_MODULE) += char/)。

        (5)配置文件选择该模块$ make menuconfig -> Device Drivers -> Character devices -> Heap Overflow Test  (*表示直接编如内核,M表示模块形式,)

        (6)运行内核,查看模块是否加载

                $ls /proc/test  或    $dmesg|grep test

3.运行syzkaller捕捉溢出

(1)修改my.cfg(只允许某些调用,速度更快):

    "enable_syscalls": [

                "open$proc",

                "read$proc",

                "write$proc",

                "close$proc"

        ],

(2)运行虚机测试: 

        $ bin/syz-manager -config ./my.cfg  -v 10

        用浏览器打开“127.0.0.1:56741”,运行一段时间后出现以下日志:

```

PROC_DEV:into open!

==================================================================

BUG: KASAN: slab-out-of-bounds in copy_from_user arch/x86/include/asm/uaccess.h:698 [inline] at addr ffff88003c1f5e20

BUG: KASAN: slab-out-of-bounds in proc_write+0x64/0x90 drivers/mod_test/test.c:45 at addr ffff88003c1f5e20

Write of size 4096 by task syz-executor0/2569

CPU: 0 PID: 2569 Comm: syz-executor0 Not tainted 4.11.0-rc8+ #23

Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014

Call Trace:

__dump_stack lib/dump_stack.c:16 [inline]

dump_stack+0x95/0xe8 lib/dump_stack.c:52

kasan_object_err+0x1c/0x70 mm/kasan/report.c:164

print_address_description mm/kasan/report.c:202 [inline]

kasan_report_error mm/kasan/report.c:291 [inline]

kasan_report+0x252/0x510 mm/kasan/report.c:347

check_memory_region_inline mm/kasan/kasan.c:326 [inline]

check_memory_region+0x13c/0x1a0 mm/kasan/kasan.c:333

kasan_check_write+0x14/0x20 mm/kasan/kasan.c:344

copy_from_user arch/x86/include/asm/uaccess.h:698 [inline]

proc_write+0x64/0x90 drivers/mod_test/test.c:45

proc_reg_write+0xf6/0x180 fs/proc/inode.c:230

__vfs_write+0x10b/0x560 fs/read_write.c:508

vfs_write+0x187/0x520 fs/read_write.c:558

SYSC_write fs/read_write.c:605 [inline]

SyS_write+0xd4/0x1a0 fs/read_write.c:597

entry_SYSCALL_64_fastpath+0x18/0xad

RIP: 0033:0x450a09

RSP: 002b:00007ff6efd15b68 EFLAGS: 00000216 ORIG_RAX: 0000000000000001

RAX: ffffffffffffffda RBX: 00000000006f8000 RCX: 0000000000450a09

RDX: 0000000000000090 RSI: 0000000020d09000 RDI: 0000000000000005

RBP: 0000000000000046 R08: 0000000000000000 R09: 0000000000000000

R10: 0000000000000000 R11: 0000000000000216 R12: 0000000000000000

R13: 00007ffc210fd8ff R14: 00007ff6efd16700 R15: 0000000000000000

Object at ffff88003c1f5e20, in cache kmalloc-512 size: 512

...

Dumping ftrace buffer:

  (ftrace buffer empty)

Kernel Offset: disabled

```

        这就是内核被crash时打印出来的调用信息,我们可以看到溢出发生在proc_write+0x64/0x90 drivers/mod_test/test.c:45处,也就是我们添加进去的带有堆溢出的模块。说明我们用Syzkaller添加规则捕捉到了堆溢出的代码。

        结果我啥都没跑出来。

syzkaller网页显示
syzkaller所跑的syscall

4.漏洞复现

        workdir/crashes目录下包含crash之前执行的程序。/tools目录下几个工具值得关注:syz-execprog以各种模式执行单个或一组程序,首先在循环中运行log中所有的程序来确认确实它们之一引发了crash。

        $./syz-execprog -executor=./syz-executor -repeat=0 -procs=16 -cover=0 crash-log

        然后尝试识别是哪个程序导致的crash。

        $./syz-execprog -executor=./syz-executor -repeat=0 -procs=16 -cover=0 single-program

        syz-execprog在本地执行程序,所以需要将syz-execprog和syz-executor复制到带有测试内核的VM中并在那里运行它。一旦确认了引发崩溃的单个程序,尝试通过注释掉单个系统调用并删除无关的数据来缩小范围。还可以尝试将所有mmap调用合并为一个。给syz-execprog加上-threaded=0 -collide=0标志确认这个程序仍然能够导致crash。

        如果不能复现的话,尝试把每个系统调用移到单独的线程中[4]。然后通过syz-prog2c得到C程序,C程序应该也可以导致crash。这个过程在某种程度上也可以通过syz-repro自动化,需要提供config文件和crash报告。

$./syz-repro -config my.cfg crash-qemu-1-1455745459265726910

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,265评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,274评论 1 288
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,087评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,479评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,782评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,218评论 1 207
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,594评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,316评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,955评论 1 237
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,274评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,803评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,177评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,732评论 3 229
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,953评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,687评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,263评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,189评论 2 258