Post

Linux Kernel Exploitation - Setup

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 select ext2/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.
  • 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.
  • Run make busybox-menuconfig and configure BusyBox:
    • Select Shells -> cttyhack.
    • Select Runtime utilities -> setuidgid.
  • 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.

  • Download and extract the Busybox source code(for example, from here).
    • Run make menuconfig and configure as you want. Make sure to select Settings -> Build static binary file (no shared lib).
    • Run make install to build. Make sure not to use sudo. You can find the compiled binaries in <PATH_TO_BUSYBOX>/_install.
  • 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 and sudo 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.

This post is licensed under CC BY 4.0 by the author.

Trending Tags