Analyzing an Old Bug and Discovering CVE-2021-30995
On April 26, 2021 Apple patched CVE-2021-1740, which was a vulnerable function inside the system daemon process cfprefsd (these types of processes usually run in the background and handle system tasks). The bug could have been exploited to read arbitrary files, write arbitrary files, and get root privilege escalation. It was addressed in Apple’s Security Update 2021-002 (Catalina) for a variety of Apple operating systems, including iOS and macOS. However, in early August 2021, Zhipeng Huo, Yuebin Sun, and Chuanda Ding (all from XuanwuLab) presented an exploitation demonstration for the vulnerability during the DEF CON 29 security conference. Their presentation was called “Caught you – reveal and exploit IPC logic bugs inside Apple”.
While studying the slides, I found that the patch for CVE-2021-1740 was still vulnerable to arbitrary file read exploits. Apple fixed this flaw, and on September 20, 2021 assigned CVE-2021-30855 to the second patch.
However, I found that the second patch was still vulnerable to arbitrary file write and root privilege escalation. This vulnerability issue was brought forward and addressed on December 13, 2021, with Apple assigning CVE-2021-30995 as the third patch (credited to this author). Apple released Security Update 2021-008 (Catalina) to secure their affected products, so any users who installed these updates should be protected.
The report detailed below shows the investigation of the original vulnerability, and the process that led me to discover CVE-2021-30995.
Tracking the patching history
To fully investigate the vulnerability first reported in April, we should illustrate how an attack could work. The key logic of the vulnerable function [CFPDSource cloneAndOpenPropertyListWithoutDrainingPendingChangesOrValidatingPlist] is:
If the controllable plist file size is larger than 1MB, then it will be cloned to a temporary file with a random name and return the file descriptor of the new cloned one.
The arbitrary file write attack from the XuanwuLab researchers’ DefCon slides show that it replaced the fixed file name of the dst_path with a symbolic link before the API call clonefile.
After getting the primitive of arbitrary file write, there are some known ways to get root privilege escalation. One simple method involves the use of periodic scripts, outlined by Csaba Fitzl.
For the issues with the second patch, we can see the new API call fclonefileat at line 25 (in Figure 1). The target directory fd is -2, and v6 is the full path of the temporary plist file. So, I found that I could replace the target parent directory with a symbolic link to an arbitrary directory.