I have been participating in Cyber Jawara International 2024, an international CTF organized by SKSD as team "swusjask fans club", and we managed to achieve rank 2 out of 211 teams. I only solved 1 out of 4 pwn challenge because of skill issues, but anyway let's dive into it.
Attachment:
As we can see from the structure, it seems to be a kernel exploitation challenge. Here is a brief explanation (and the content) of each files:
bzImage
: Compiled Linux version 6.11.5 x86 kernel imagerun.sh
: Script to run the emulated vulnerable environment using QEMU.
rootfs.cpio.gz
: Compressed file system that will be booted into the QEMU environment.backdoor.patch
: Diff output file containing the difference between the compiled kernel and the original Linux kernel source code. This file tells us where the vulnerability is, where users can access /dev/mem
without CAP_SYS_RAWIO
capability.
π‘ As seen in the patch above, users don't need to have
CAP_SYS_RAWIO
capability to access/dev/mem
. See the source code for more details.
Kconfig
: Configuration of the compiled kernel image. Specifically, below is the relevant configuration to this challenge.π‘ With
CONFIG_STRICT_DEVMEM=n
, userspace can access every bits and bytes of the memory using/dev/mem
(including kernelspace and userspace). See this and the man page for more details.
Letβs inspect the content of the filesystem by decompressing rootfs.cpio.gz
with this script:
We then see init
script, that will be executed as an entrypoint when the kernel is booted successfully. Below is the content:
As seen above, the flag is only readable by root user. And our goal is to read the flag as an unprivileged user.
/dev/mem
? π€According to this article, /dev/mem
is a character device file that is an image of the main memory of the computer. Basically it allows us to have direct access to physical address. To interact with it, we can do mmap
first to map the physical address, then followed by read
or write
to read or write, respectively into the physical address.
Note that we have found a few keypoints before:
CAP_SYS_RAWIO
capability to access /dev/mem
./dev/mem
.So basically we have full access to the physical memory as an unprivileged user. My hypothesis is that the file system will also be contained in the physical memory. To validate my hypothesis, we need to do some debugging.
First, we need to make a binary to interact with /dev/mem
and loops infinitely to help us achieve a breakpoint in GDB where we can see the content of the mapped physical address.
We then make these scripts to debug our kernel:
Don't forget to extract the vmlinux using this script to get the kernel's actual ELF file.
Then we open two terminals. In the first terminal execute dbuild.sh
and in the other terminal, execute gdb vmlinux -x gdb.sh
to debug our kernel. We then execute our binary to trigger the physical address mapping, and breaking in our GDB. We then search the memory for the content of files in the file system by using GEF's search-pattern
.
And, voila! File system's content is available in the physical memory. Also notice that the beginning of each file is mapped at the beginning of a page (ending with 0x000), so we can just read through every page, and check if it contains CJ{
.
Below is the exploit code to read every pages:
Send the exploit to the remote instance using this python script:
And we got the flag.