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

参考:

本文主要参考第一篇文章,但是文章中很多步骤不全面,而且存在错误,故记录本实验过程。本实验前提是参照配置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二进制可执行文件。

调用规则 号前的 s y s c a l l n a m e 是系统调用名, 号前的syscallname是系统调用名, 号前的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/81949703和https://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添加规则捕捉到了堆溢出的代码。

结果我啥都没跑出来。

img

syzkaller网页显示

img

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-execprogsyz-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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
推荐,网络安全中的漏洞挖掘实践合集,仅供大家学习参阅,包含内容如下: 针对现实应用的文本对抗攻击研究 安全众测下的漏洞发展新趋势 安卓应用漏洞挖掘 从0到1-发现与拓展攻击面 对基于Git的版本控制服务的通用攻击面的探索 对民用飞行控制系统固件的逆向与漏洞分析 卫星通信的安全缺陷 基于全流量的智慧漏洞挖掘 基于运行时类型嗅探技术提高模糊测试的漏洞发掘效果 漏洞挖掘进化论-推开xray之门 逆向在漏洞挖掘中的应用 苹果攻击面和漏洞挖掘自动化研究 如何从高赏金项目中拿到高危 如何去挖掘物联网环境中的高级恶意软件威胁 如何在3个月发现 12 个内核信息泄露漏洞 沙箱内持久化.行之有效的沙箱攻击新思路 深度解析Weblogic_XMLDecoder反序列化 使用数据流敏感模糊测试发现漏洞 锁不住的安全 谈谈工业协议转换器的一些问题 逃逸IE浏览器沙箱-在野0Day漏洞利用复现 为何自动化漏洞挖掘如此困难 现代可抵赖后门研究 一扇虚掩的大门-现代智能系统的重要攻击面 源代码漏洞挖掘 远程root现代安卓设备 在现代Windows内核中发现存在20年的漏洞 针对智能设备漏洞挖掘的一些新方法 AI用于软件漏洞挖掘 AndroidWebView安全攻防指南2020 Java反序列化漏洞自动挖掘方法 macOS从运行库劫持到内核提权 MTK安全启动大剖析.CIS大会分论 MyBatis框架下SQL注入解决方案 Qemu-kvm和ESXi虚拟机逃逸实例分享 WEB常见漏洞与挖掘技巧研究 Web漏洞挖掘速成特训营 混合式漏洞挖掘研究进展

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值