通过一道简单的例题了解Linux内核PWN

这篇文章目的在于简单介绍内核PWN题,揭开内核的神秘面纱。背后的知识点包含Linux驱动和内核源码,学习路线非常陡峭。也就是说,会一道Linux内核PWN需要非常多的铺垫知识,如果要学习可以先从UNICORN、QEMU开始看起,然后看Linux驱动的内容,最后看Linux的内存管理、进程调度和文件的实现原理。至于内核API函数不用死记硬背,用到的时候再查都来得及。

题目概述

这题是参考ctf-wiki上的内核例题,题目名称CISCN2017_babydriver,是一道简单的内核入门题,所牵涉的知识点并不多。题目附件可以在ctf-wiki的GitHub仓库找到:https://github.com/ctf-wiki/ctf-challenges/tree/master/pwn/kernel/CISCN2017-babydriver。

首先将题目附件下载下来,解压后得到所有的文件如下:

. ├── boot.sh # 启动脚本,运行这个脚本来启动QEMU ├── bzImage # 压缩过的内核镜像 └── rootfs.cpio # 作为初始RAM磁盘的文件

查看启动脚本boot.sh内容如下:

#!/bin/bash qemu-system-x86_64 \ -initrd rootfs.cpio \ # 指定使用rootfs.cpio作为初始RAM磁盘。可以使用cpio 命令提取这个cpio文件,提取出里面的需要的文件,比如init脚本和babydriver.ko的驱动文件。提取操作的命令放在下面的操作步骤中 -kernel bzImage \ # 使用当前目录的bzImage作为内核镜像 -append \'console=ttyS0 root=http://www.likecs.com/dev/ram oops=panic panic=1\' \ # 使用后面的字符串作为内核命令行 -enable-kvm \ # 启用加速器 -monitor /dev/null \ # 将监视器重定向到字符设备/dev/null -m 64M \ # 参数设置RAM大小为64M --nographic \ # 参数禁用图形输出并将串行I/O重定向到控制台 -smp cores=1,threads=1 \ # 参数将CPU设置为1核心1线程 -cpu kvm64,+smep # 参数选择CPU为kvm64,开启了smep保护,无法在ring 0级别执行用户代码

文件bzImage是压缩编译的内核镜像文件。有些题目会提供vmlinux文件,它是未被压缩的镜像文件。这个题目没有提供,但也不要紧,可以用脚本提取出vmlinux,而使用vmlinux的目的也就是找gadget,提取vmlinux的脚本也可以在Linux的GitHub上找到:https://github.com/torvalds/linux/blob/master/scripts/extract-vmlinux。把代码复制到文件中,保存为extract-vmlinux,然后赋予执行权限。提取vmlinux命令如下:

./extract-vmlinux ./bzImage > vmlinux

可以使用ropper在提取的vmlinux中搜寻gadget,ropper比ROPgadget快很多:

ropper --file ./vmlinux --nocolor > g1

rootfs.cpio是启动内核的RAM磁盘文件,可以把它看作一个微型Linux文件系统。使用file命令查看可以看到它是gzip格式:

unravel@unravel:~/pwn$ file rootfs.cpio rootfs.cpio: gzip compressed data, last modified: Tue Jul 4 08:39:15 2017, max compression, from Unix, original size modulo 2^32 2844672

我们将rootfs.cpio改名为rootfs.cpio.gz,然后将它解压出来:

unravel@unravel:~/pwn$ ls boot.sh bzImage rootfs.cpio unravel@unravel:~/pwn$ mv rootfs.cpio rootfs.cpio.gz unravel@unravel:~/pwn$ ls boot.sh bzImage rootfs.cpio.gz unravel@unravel:~/pwn$ gunzip rootfs.cpio.gz unravel@unravel:~/pwn$ ls boot.sh bzImage rootfs.cpio unravel@unravel:~/pwn$ file rootfs.cpio rootfs.cpio: ASCII cpio archive (SVR4 with no CRC)

因为rootfs.cpio里面包含一些文件系统,它的文件比较多,我们可以创建一个文件夹,然后用cpio命令把所有文件提取到新建的文件夹下,保证一个干净的根目录,后面也将内容重新打包:

unravel@unravel:~/pwn$ mkdir core && cp rootfs.cpio core && cd core && cpio -idmv < rootfs.cpio unravel@unravel:~/pwn/core$ ls bin etc home init lib linuxrc proc rootfs.cpio sbin sys tmp usr

启动文件和驱动程序函数

在我们上一步解压完rootfs.cpio之后可以看到它就是Linux的文件系统。在根目录下里面有一个「init」文件,它决定启动哪些程序,比如执行某些脚本和启动shell。它的内容如下,除了insmod命令之外都是Linux的基本命令便不再赘述:

#!/bin/sh mount -t proc none /proc mount -t sysfs none /sys mount -t devtmpfs devtmpfs /dev chown root:root flag chmod 400 flag exec 0</dev/console exec 1>/dev/console exec 2>/dev/console insmod /lib/modules/4.4.72/babydriver.ko # insmod命令加载了一个名为babydriver.ko的驱动,根据一般的PWN题套路,这个就是有漏洞的LKM了 chmod 777 /dev/babydev echo -e "\nBoot took $(cut -d\' \' -f1 /proc/uptime) seconds\n" setsid cttyhack setuidgid 1000 sh umount /proc umount /sys poweroff -d 0 -f

在init文件中看到用insmod命令加载了babydriver.ko驱动,那么我们把这个驱动拿出来,检查一下开启的保护:

unravel@unravel:~/pwn/core/lib/modules/4.4.72$ checksec --file=babydriver.ko RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE No RELRO No canary found NX disabled Not an ELF file No RPATH No RUNPATH 64 Symbols No 0 0 babydriver.ko

可以看到程序保留了符号信息,其他保护都没有开启

把驱动程序放到IDA里面查看程序逻辑,除了init初始化和exit外还有5个函数:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgzfwz.html