Linux Kernel Exploitation - Setup
In this post, I will explain how to build and debug the Linux kernel.
Since the kernel and file image will be provided, it is not strictly necessary to follow the content of this article in order to read the other posts in this guide.
How to Build the Linux Kernel with Buildroot
The method of configuration may vary depending on the version.
- Install Buildroot.
- Run the following commands to configure Buildroot:
1 2 3
make list-defconfigs # List available configurations make qemu_x86_64_defconfig # Select default configurations for QEMU x86_64 make menuconfig # Modify configurations if needed
- Select
Filesystem images -> ext2/3/4 root file system
and selectext2/3/4 variant -> ext3
.
I prefer ext3 to cpio because it doesn’t require extracting or compressing.
If you want to change the kernel version, follow these steps:
- Select
Kernel -> Kernel version -> Custom Version
. - Select
Kernel version
and set the version as you want. - Select
Toolchain -> Custom Kernel Header Series
and choose the appropriate version.
- Select
- Run
make linux-menuconfig
and configure the kernel:- Select
Kernel hacking -> Kernel debugging
. - Select
Compile-time checks and compiler options -> Debug information -> Rely on the toolchain's implicit default DWARF version
. - Optionally, enable any other configurations you want.
- Select
- Run
make busybox-menuconfig
and configure BusyBox:- Select
Shells -> cttyhack
. - Select
Runtime utilities -> setuidgid
.
- Select
- Run
make -j$(nproc)
to build.
You can find bzImage and rootfs.ext3 in <PATH_TO_BUILDROOT>/output/images and vmlinux with debug symbols at <PATH_TO_BUILDROOT>/output/linux-<VERSION>/vmlinux.
How to Build the Linux Kernel without Buildroot
In most cases, Buildroot is sufficient, but sometimes you’ll need to build the kernel without it (for example, when you want to use Clang/LLVM to enable CONFIG_CFI_CLANG).
- Download and extract the kernel source code (for example, from here).
- Run
make menuconfig
and configure as you want. - Run
make build -j$(nproc)
to build.
If you want to build the kernel with Clang/LLVM, follow the instructions here.
If you want to enable CONFIG_CFI_CLANG, you may need to compile Clang/LLVM with compiler-rt enabled. follow the instructions here.
- Run
- Download and extract the Busybox source code(for example, from here).
- Run
make menuconfig
and configure as you want. Make sure to selectSettings -> Build static binary file (no shared lib)
. - Run
make install
to build. Make sure not to usesudo
. You can find the compiled binaries in <PATH_TO_BUSYBOX>/_install.
- Run
- Create the ext3 root file system image:
1 2 3 4 5 6 7
dd if=/dev/zero of=rootfs.ext3 bs=1M count=16 mkfs.ext3 -F rootfs.ext3 mkdir -p mnt sudo mount -o loop rootfs.ext3 ./mnt sudo chown -R 1000:1000 ./mnt cp -a <PATH_TO_BUSYBOX>/_install/* ./mnt mkdir -p ./mnt/{dev,etc,proc,root,run,sys}
How to Run the Linux Kernel with QEMU
- Install QEMU.
- Run
mkdir -p mnt
andsudo mount -o loop <PATH_TO_ROOTFS> ./mnt
. - Run
sudo chown -R 1000:1000 ./mnt
. - Create
/init
:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
#!/bin/sh if (exec 0</dev/console) 2>/dev/null; then exec 0</dev/console exec 1>/dev/console exec 2>/dev/console fi mkdir /home echo 'root:x:0:0:root:/root:/bin/sh' > /etc/passwd echo 'root:x:0:' > /etc/group chmod 644 /etc/passwd chmod 644 /etc/group adduser ctf --disabled-password 2>/dev/null chown -R root:root / chmod 700 -R /root chown ctf:root /home/ctf chmod 777 /home/ctf chmod 755 /dev chmod u+s /bin/su mount -t proc -o nodev,noexec,nosuid proc /proc mount -t sysfs -o nodev,noexec,nosuid sysfs /sys mount -t tmpfs -o "noexec,nosuid,size=10%,mode=0755" tmpfs /run ln -sf /proc/mounts /etc/mtab echo 1 > /proc/sys/kernel/kptr_restrict echo 1 > /proc/sys/kernel/dmesg_restrict echo 1 > /proc/sys/kernel/perf_event_paranoid setsid cttyhack setuidgid 1000 sh
- Create
run.sh
:1 2 3 4 5 6 7 8 9 10 11 12
#!/bin/sh qemu-system-x86_64 \ -m 64M \ -cpu qemu64 \ -kernel bzImage \ -drive file=rootfs.ext3,format=raw \ -snapshot \ -nographic \ -monitor /dev/null \ -no-reboot \ -smp 1 \ -append "root=/dev/sda rw init=/init console=ttyS0 nokaslr nopti loglevel=3 oops=panic panic=-1"
- Run
sudo umount ./mnt
. - Run
./run.sh
.
How to Debug the Linux Kernel with QEMU and GDB
- Run QEMU with the
-gdb tcp::1234
option. - Run GDB and execute
target remote localhost:1234
.
I recommend using the GEF extension as it provides useful commands for kernel debugging.