In this post we will have a brief view about Linux kernel pwn, what we need to do and how it works.
Actually Linux kernel pwn is similar to userland pwn, except that our target is the kernel(or kernel module). In most of the cases, the vulnerability is in custom Linux Kernel Module, LKM, which provides service to user as a part of kernel in ring0. Usually, the emulator for the task in Linux kernel pwn in CTF is qemu. And the challenge will often be deployed with the following files:
vmlinux, the Linux kernel. Sometimes it will be packed into bzImage from which you can extract the kernel. The kernel is an ELF file and you can run ROPGadget or ropper against it like common userland pwn.
Linux root file system. The compression schemes are usually cpio and gzip
A script to launch the emulator with specific configuration
Let’s go further now, some basic knowledge of operating system is required here.
Our goal
Our main goal in Linux kernel pwn is getting root privilege since the “flag” can only be accessed with root in most cases, which means privilege escalation.
Privilege escalation
First let’s take a look at the structure of process in Linux kernel.
and struct cred contains the gid and uid of the process. It’s obviously that if we can control the subjective cred of a specific process then we can achieve privilege escaltion.
Luckily, we do have serveral ways to change our credential:
Overwrite the cred in the link list of process with arbitary kernel rw.
Find the code path in kernel that can set the credential of process and perform a kernel ROP.
Also, we can control another process with root privilege and gain arbitary code exec in that process. But we will take a closer look at the last one first since it’s almost the same as ROP in userland.
Kernel ROP
We need to find a method to assign new cred to our process. Searching through the source code, we find that
Exactly what we need! So if we can find a cred for a process with root privilege then we can use the function above to assign this cred to our process(current process). Luckily, we have
When daemon is null, old will be set to init_cred
Which has all we need! So our ROP chain should be
after which we can achieve privilege escalation.
Back to userland
After we getting root privilege, we are still in kernel mode. Our main goal is spawning a root shell in userland, so we need to return to user mode with the following steps.
swapgs
iretq
Take a look at the implementation of Linux
So the layout of the stack should be
+--------------------------------+
| commit new cred to our process |
+--------------------------------+
| addr of swapgs_ret |
+--------------------------------+
| addr of iretq |
+--------------------------------+
| previous rip(spawn root shell) |
+--------------------------------+
| previous cs |
+--------------------------------+
| previous eflags |
+--------------------------------+
| previous rsp |
+--------------------------------+
| previous ss |
+--------------------------------+
ROPGadget will fail to find iretq sometimes, we can use the following command to find the gadget.