作者归档:Jack

Pwn学习总结(28):Kernel Pwn – 入门与KROP_LPE

由于个人需求,需要入门Kernel Pwn。所以又继续开始更新这个系列啦!

我的入门参考了Keith Makan的Kernel Pwn系列文章:
[Linux Kernel Exploitation 0x0] Debugging the Kernel with QEMU
[Linux Kernel Exploitation 0x1] Smashing Stack Overflows in the Kernel
[Linux Kernel Exploitation 0x2] Controlling RIP and Escalating privileges via Stack Overflow

但我只能说,这系列文章的写作质量非常感人。第一篇文章写的还是比较优秀的,后面作者就开始放飞自我了。在一些关键的地方会出现不能看的错误。因此我自己再写一篇踩坑教程。

环境配置

我们首先选择一个工作目录:

export WORKSPACE=~/Documents/Kernel
cd $WORKSPACE

构建内核

根据教程文章,选择Ubuntu 18.04 LTS上进行内核编译。本文作者写作时,Ubuntu 18.04的最新版本应该是18.04.6。

首先安装依赖:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install -y git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison qemu-system-x86

根据教程,用的是5.9.7的内核:

wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.9.7.tar.xz
tar -xf linux-5.9.7.tar.xz
cd linux-5.9.7

将宿主机的内核.config直接复制过来,作为当前的内核编译.config。作者写作时,Ubuntu 18.04 LTS的最新内核版本是5.4.0-150-generic,后续随系统更新可能有变动。

cp /boot/config-5.4.0-150-generic .config

然后再开启kernel对kvm虚拟化的支持,以便于在qemu中运行时更好的调试:

make kvmconfig

然后手动更改.config,开启调试信息、特定文件系统,关闭保护机制和启用网卡支持,更改如下:

CONFIG_DEBUG_INFO=y
CONFIG_BINFMT_MISC=y
# CONFIG_RANDOMIZE_BASE is not set
# CONFIG_STACKPROTECTOR is not set
# CONFIG_FORTIFY_SOURCE is not set
CONFIG_SYSTEM_TRUSTED_KEYS=""
CONFIG_E100=y
CONFIG_E1000=y
CONFIG_E1000E=y

最后,保存.config并编译:

make savedefconfig
make -j16

构建启动镜像(rootfs)

我们使用syzkaller中的镜像构建脚本:

cd $WORKSPACE
mkdir image
cd image
wget https://raw.githubusercontent.com/google/syzkaller/master/tools/create-image.sh
chmod +x create-image.sh
./create-image.sh

如果创建成功,当前目录下应该会有一个bullseye.img

启动虚拟机并附加调试器

接下来,我们创建run.sh,内容如下:

#!/bin/bash
sudo qemu-system-x86_64 \
  -kernel ../linux-5.9.7/arch/x86_64/boot/bzImage \
  -append "console=ttyS0 root=/dev/sda earlyprintk=serial nokaslr net.ifnames=0"\
  -hda ./bullseye.img \
  -net user,host=10.0.2.10,hostfwd=tcp::10022-:22 -net nic,model=e1000 \
  -enable-kvm \
  -nographic \
  -m 2G \
  -s \
  -S \
  -smp 2 \
  -pidfile vm.pid \
  2>&1 | tee vm.log

其中,参数-s代表-gdb tcp::1234。表示gdb可以从1234端口对内核进行附加调试。-net user一行创建了网卡,并使得guest的22端口转发到了host的10022端口。这使得我们可以使用SSH。

在image目录下启动qemu:

./run.sh

新开一个窗口,启动gdb并连接调试端口:

cd $WORKSPACE/linux-5.9.7
gdb vmlinux
> (gdb) target remote :1234

然后在gdb cli中使用continue语句,即可使得qemu继续运行。

镜像的默认用户名为root,无密码。

编译有漏洞的内核驱动与使用驱动的App

cd $WORKSPACE/linux-5.9.7
mkdir debug_driver
cd debug_driver
wget https://raw.githubusercontent.com/bjrjk/pwn-learning/main/ROP/KROP_LPE/Makefile
wget https://raw.githubusercontent.com/bjrjk/pwn-learning/main/ROP/KROP_LPE/stacksmash_driver.c
cd ..
make -C . M=drivers/debug_driver/

stacksmash_driver.ko通过ssh上传到guest,然后再使用如下命令,在guest中下载stacksmash_app.c并进行编译。

wget https://raw.githubusercontent.com/bjrjk/pwn-learning/main/ROP/KROP_LPE/stacksmash_app.c
gcc stacksmash_app.c -o stacksmash_app

启用内核驱动并在gdb中加载符号

启用内核模块,并获得内核模块的基地址,以在调试器中加载符号:

insmod stacksmash_driver.ko
cat /proc/modules
> stacksmash_driver 16384 0 - Live 0xffffffffa006b000 (OE)

从中可以看出,0xffffffffa006b000是内核驱动的基地址。在调试器中,执行如下命令,以加载stacksmash_driver.ko的符号:

add-symbol-file drivers/debug_driver/stacksmash_driver.ko 0xffffffffa006b000

然后就可以下断点了。例如,给stacksmash_dev_write函数下断点:

b stacksmash_dev_write