编译生成内核镜像
先下载一个内核源码 :https://mirrors.edge.kernel.org/pub/linux/kernel/
我下载的是linux-4.9.tar.gz
然后安装一些依赖1
2sudo apt-get update
sudo apt-get install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc
解压源码后进入内核目录,输入命令:sudo make menuconfig
进入内核编译设置
进入kernel hacking,检查保证勾选了以下选项(其实默认都是勾选的,只是进去看一眼而已)
- Kernel debugging
- Compile-time checks and compiler options —> Compile the kernel with debug info和Compile the kernel with frame pointers
- KGDB: kernel debugger
保存并退出
sudo make bzImage
生成 bzImage,过程挺久的,完成后在boot下生成了一个bzImage文件
这样,就算编译成功了这样我们就从/arch/x86/boot
得到了 bzImage文件
下载内核镜像
根据版本号搜索 sudo apt search linux-image-xxx
然后下载 sudo apt download linux-image-4.10.0-1004-gcp
,解压
安装busybox
这里下载,解压后进入目录,make menuconfig
,同样会进入图形界面,在Settings 上勾选Build static binary (no shared libs),然后保存退出
编译,执行make install
,根目录下会生成一个_install
文件夹,进入文件夹配置
1 | cd _install |
编辑init 文件,用于内核初始化
1 | #!/bin/sh |
几个常见指令
- insmod: 指定模块加载到内核中
- rmmod: 从内核中卸载指定模块
- lsmod: 列出已经加载的模块
在packet 中写入,用于将FileSystem 打包成映像
1 |
|
运行 packet 将得到 rootfs.img文件
运行内核
这里使用qemu进行运行,qemu 有多种运行模式,常见的有User-mode emulation
和System emulation
两种
安装 qemu
1 | 安装QEMU的依赖库 |
接着写一个shell脚本boot.sh用来启动qemu,运行内核
1 |
|
将前面生成的bzImage,rootfs.img一起放到_install
文件夹下,运行boot.sh
这里解释一下shell命令中参数的意义
1 | -m 是指定RMA大小(默认384) |
到这里也说明了为什么kernel pwn 题目一般都会给出这3个文件.sh ,bzImage,rootfs.cpio
,分别是启动脚本,kernel镜像以及文件系统映像
一般来说kernel pwn 里面,漏洞通常是出现在ko文件,也就是模块文件,驱动 文件中,而kernel pwn 的最终目标一般是提权,拿到root才能读取flag
添加syscall
在内核源码下添加一个目录:mysyscall,在mysyscall文件夹下添加一个mysyscall.c 一个Makefile
1 | mkdir mysyscall |
编辑Makefile:
1 | obj-y=mysyscall.o |
编辑mysyscall.c
1 |
|
接着编辑源码根目录下的Makefile,添加mysyscall/
然后编辑include/linux/syscall.h
,在末尾添加函数原型
1 | asmlinkage long sys_mysyscall(void); |
最后编辑arch/x86/entry/syscalls/syscall_32.tbl
和arch/x86/entry/syscalls/syscall_64.tbl
,添加系统 调用号
1 | //syscall_32.tbl |
到这里,syscall就添加完了,如果调用了2333号就会输出 一句{==== kernel ====}this is my syscall!
,不过要重新编译一次内核才能生效,make bzImage重新得到bzImage文件
编译ko
在kernel 源码目录下创建一个新的文件夹
1 | mkdir test_ko |
编辑hello.c
1 | //hello.c |
编辑Makefile,(写Makefile的时候注意要使用Tab而不是空格)
1 | obj-m := hello.o |
然后make 命令编译出一个hello.ko文件
将编译好的hello.ko放到busybox的_install
目录下,再写一个demo来调用前面添加的syscall,将demo也放到_install
目录下
1 | //demo |
注意这里我们需要加载自己编译的驱动 hello.ko,所以需要在init 文件中加入一句insmod /hello.ko
然后再打包./packet
接着./boot.sh
启动可以看到我们的ko模块和syscall都生效了