Most kernel-related privilege escalation techniques are based on code execution or control flow hijacking, while some others are data-oriented attacks. The DirtyCred technique is one of such attacks, which contains two sub-techniques: process cred swapping and file permission check bypass. By stealing a high privilege cred or writing read-only files, attackers can obtain root privilege, thus have no need to struggle with kernel vulnerability mitigations.
As the authors said, DirtyCred is inspired from the DirtyPipe vulnerability (CVE-2022-0847). The name DirtyPipe is a successor of DirtyCoW (CVE-2016-5195). BTW, I have one post on container breakout leveraging DirtyPipe and another post on experiment from remote user land PWN to container breakout via DirtyCoW.
In this post, we will walk through the paper to be familiar with DirtyCred. As DirtyCred is a powerful technique that can be used in exploitation against lots of kernel vulnerabilities, we are not going to detail how to exploit real-world vulnerabilities based on it, otherwise this post would become very long. The actual exploitations will be introduced in future articles.
BTW, I want to talk about post titles. As you can see, some titles of my paper reading notes are prefixed with ‘Paper |’, while the others are not, even if they are reading notes as well. My convention is very simple: if the subject in one paper I read is practical and I will do some experiments or reproductions, the title of the related post will be prefixed with the real topic like ‘Linux Kernel PWN |’; if not, the title will be prefixed with ‘Paper |’, which is more general.
2. Paper Information
|Title||DirtyCred: Escalating Privilege in Linux Kernel|
|Author(s)||Zhenpeng Lin, Yuhang Wu, Xinyu Xing|
|Published in||2022 ACM SIGSAC Conference on Computer and Communications Security (CCS)|
DirtyCred was also presented on Blackhat USA 2022.
3. The DirtyCred Idea
Many kernel protections have been put forward to prevent ret2usr and its successors, which make kernel exploitations harder and harder. Last year, the DirtyPipe vulnerability presents the benefit of the data-only (or so-called data-oriented) attacks, which could natively bypass or even neglect most of the existing kernel protections. However, DirtyPipe is just a specific vulnerability that can be easily patched.
Comparatively, DirtyCred proposed in this paper is a more general exploit technique, which can be widely applied in lots of Linux kernel heap memory corruption vulnerabilities. The idea is very intuitive: try to replace a low privileged kernel credential object with a higher one by triggering these heap-related vulnerabilities.
According to the Linux kernel document, credentials refer to those kernel properties containing privilege information, which are implemented as kernel objects, including ‘cred’, ‘file’ and ‘inode’. DirtyCred relies on the first two objects. To be more exact, DirtyCred is composed of two sub-techniques:
- Process cred swapping. The attacker tries to allocate new high privileged cred objects, hold a pointer pointing to one of these objects by triggering vulnerabilities and manage to use it as the cred of current process.
- File permission check bypass. The attacker firstly opens a writable file, and tries to write into it. At the time after the permission check but before the actual write operation happes, the attacker frees the file object associated with the opened file by triggering the vulnerability, and then opens a read-only file to allocate a privileged file object to reclaim the freed memory slot. Finally, the write operation will be conducted in the read-only file.
Theoretically speaking, either of them can be used to escalate privilege. However, there are still some differences:
The process cred swapping way can be used to regain all capabilities. As a result, it would facilitate container breakout to a high degree. Lots of techniques are available to escape from a container when you have full capabilities. The paper authors take abuse of the notify_on_release mechanism of Linux Cgroups for example. Note that in some specific environments like Docker, only being equipped with CAP_SYS_ADMIN is not enough. The enabled-by-default LSMs like Seccomp and AppArmor would thwart the breakout. But in environments like Kubernetes, where these LSMs are not enabled by default, the foregoing technique works. Anyway, the more capabilities you have, the more possibility you get.
BTW, in some cases actually you can escape from containers when holding some capabilities, even if Seccomp and AppArmor are enabled. I will share such techniques in future posts :-)
However, it is not very clear to conduct container breakout with the second sub-technique. Actually it is feasible: you can overwrite the read-only mounted runC program with the file permission check bypass technique, in order to escape to the host. Another article of mine on DirtyPipe details this way. Unfortunately, this seems to be the single method (runC overwriting) when using this sub-technique to escape, as the container filesystem is separated from the host’s by default.
It seems that the second sub-technique is easier to use. If you can modify the content of a sensitive file (e.g., /etc/passwd), you will win. However, for the first one, how can you use the privileged cred object as the current process or any other attack-controlled processes? Note that you have a cred pointer in the same slab cache of the vulnerable object, while the task_struct objects are located in dedicated slab caches. Furthermore, in the GitHub repository published by the authors, the two demonstrations are both about the file permission check bypass technique. No process cred swapping technique PoC has been published yet.
After reading some materials and talking with Yunsong, I tend to believe that cross-cache attack is needed to reuse the privileged cred object.
4. Technical Overview & Challenges
Researchers present the exploit process of CVE-2021-4154 to illustrate DirtyCred:
This exploitation process is somehow intuitive, as CVE-2021-4154 can be used to directly free a file object. However, for many kernel vulnerabilities, there are three challenges to apply DirtyCred:
- DirtyCred needs an invalid-free capability to deallocate a low-privileged object. Therefore, some approaches are needed to pivot vulnerability’s capability to invalid-free for vulnerabilities with different capabilities.
- DirtyCred needs to hold on to the actual file writing after completing the permission check ad prior to the file object swap.
- DirtyCred needs to be able to allocate high-privileged objects.
5. Solutions to the Challenges
This is the most important part of DirtyCred. Now let’s see how it resolves these challenges.
5.1 Pivoting Vulnerability Capability
There are many types of kernel vulnerabilities. As DirtyCred is applied to exploit heap-based memory corruption vulnerabilities, researchers analysed how to pivot OOB (out of bound) write, UAF (use after free) write and DF (double free) vulnerabilities.
5.1.1 Pivoting OOB & UAF Write
Given an OOB or UAF with capability of overwriting data in a cache, DirtyCred first identifies one type of victim object sharing the same cache and containing a pointer referencing a credential object, allocates such objects where overwriting happens and modify the last two non-zero bytes of the foregoing pointer within one of the victim objects to zero using the vulnerability’s capability. The process is shown below:
After nullifying the non-zero bytes of the pointer, it references to the beginning of a memory page where another credential object resides. Then the attack can free the victim object and occupy the freed spot with heap spraying to get the dangling pointer referencing to the credential object. As we have talked before, cross-cache attack may be needed to leverage this dangling pointer.
5.1.2 Pivoting DF
The approach to pivot double free vulnerabilities is a little more complex. As general caches and dedicated caches are isolated in Linux kernel, cross-cache memory manipulation is needed, in order to get a pointer referencing to a high-privileged credential object.
As the diagram below shows, the attacker firstly (a) allocates many objects and a vulnerable object in the cache where the vulnerability occurs, (b) free the vulnerable object through by triggering the vulnerability, (c) allocate a new vulnerability object to fill the freed slot, (d) free the new vulnerable object by triggering the vulnerability again, (e) release other objects in the same cache, (f) allocate credential objects within the same page, (g) trigger a free operation through one of the remaining pointers (note that this free may begin from the middle of one credential object ), and finally (h) allocate one credential object to occupy the freed slot:
After these steps, the attacker holds one remaining pointer referencing to the very beginning of one credential object. Then object swap could be conducted for privilege escalation.
5.2 Extending Time Window
Remember that DirtyCred needs to perform a file object swap between the permission check and the actual write operation. Normally, the time window is too short for a successful file object swap, which is composed of a series of steps like triggering the vulnerability and heap manipulation.
5.2.1 Alternative Exploitation of Userfaultfd & FUSE
DirtyCred utilizes several techniques to extend the time window. Two of these techniques are userfaultfd and FUSE. We have learnt exploitation of userfaultfd and exploitation of FUSE before, so here I will skip the details.
As the paper says, before kernel version v4.13, the
writev syscall used by DirtyCred firstly checks permissions and then imports data to be written from user space. In this way, DirtyCred can swap the file object when the kernel execution is paused between check and import.
However, the import is moved ahead of the permission check after kernel version v4.13, which means the former pause will not work. To solve this problem, researchers find that when writing (after the permission check), the high-level interface
generic_perform_write of Linux filesystem will trigger a page fault for the userspace data before the invocation of the actual write operation of a concrete filesystem (e.g., ext4), where DirtyCred can pause the kernel execution using userfaultfd.
5.2.2 Exploitation of Lock in Filesystem
Another way to extend the time windows is to leverage the lock mechanism of filesystem. A filesystem doest not allow two processes to write the same file at the same time. The attacker can spawn two processes A and B, and let A hold the lock by writing much data. B will pass the permission check and wait until the lock is released. The lock waiting time is sufficient for file object swap.
5.3 Allocating Privileged Object
The last part of puzzle is how to allocate privileged credential objects. This is relatively easy. In the paper, researchers put forward two ways to achieve it.
5.3.1 Allocation from User Space
For the cred object, the idea is to trigger executions of SUID programs such as su, ping, sudo, mount, pkexec, etc. For the file object, the attacker can just open sensitive files owned by root in read-only mode.
5.3.2 Allocation from Kernel Space
This method involves creation of privilege kernel threads. Two approaches are proposed: the first is to trigger the kernel to spawn privileged threads internally, e.g., by committing more works; the second is to invoke the user mode helpers, which we have talked about before.
The authors use automated method to find objects that encloses credential objects and can be allocated on kernel heap when requested by user space programs. The left table of the diagram below shows the matched objects in different memory caches:
For the experiment, researchers selected heap-based memory corruption CVEs of Linux kernel reported after 2019. The exploit result is shown in the right part of the diagram above. The authors also provided some demonstrations and ExPs.
7. Defense Against DirtyCred
An effective approach is to prevent the swap of credentials with different privilege level. Following this idea, researchers propose a defense solution that creates caches for high privileged objects in the virtual memory region and leaves the low privileged objects in the normal memory area, in order to isolate high privielged and low privileged objects.
In this post, we share the DirtyCred technique from the related paper, which could be used to escalate privilege effectively. We don’t go into details on specific vulnerabilities in this post, but in the future.
With more and more mitigations proposed against kernel exploitation, DirtyCred serves as an inspiring signal for researchers to come up with more techniques to bypass the defense and achieve the goal. Also, more powerful protections need to be mounted to defend against latest exploit techniques.