Exploits & Vulnerabilities
A Technical Analysis of CVE-2022-22583 and CVE-2022-32800
This blog entry discusses the technical details of how we exploited CVE-2022-22583 using a different method. We also tackle the technical details of CVE-2022-32800, another SIP-bypass that we discovered more recently, in this report.
On Jan. 26, 2022, Apple patched a System Integrity Protection (SIP)-bypass vulnerability in the PackageKit framework, identified as CVE-2022-22583. Apple shared the credit for this CVE between researchers Ron Hass (@ronhass7) of Perception Point and Mickey Jin (@patch1t) of Trend Micro.
After Perception Point posted a comprehensive blog entry about the vulnerability and its exploitation details, we determined that the method we used to exploit the vulnerability was different from theirs. We also discovered a new vulnerability, CVE-2022-32800, after digging deeper into CVE-2022-22583.
This blog entry discusses the technical details of how we exploited CVE-2022-22583 using a different method. We also tackle the technical details of CVE-2022-32800, another SIP-bypass that we discovered more recently, in this report.
This is the third and final entry of a series of blog entries where we discuss our SIP-related vulnerability discoveries. More details about SIP and the special daemon services’ entitlements can be found in our previous blog entry last month. We also talked about several of the more than 15 critical SIP-bypass vulnerabilities that we disclosed to Apple during the Power of Community 2022 Security Conference (POC2022).
CVE-2022-22583
We discovered this vulnerability via process monitoring. When we installed an Apple-signed software installer package (PKG) file to the root volume, we noticed that the following scripts were spawned by the privileged “system_installd” service:
/tmp/PKInstallSandbox.l57ygT/Scripts/com.apple.pkg.MXFPlugIns.yJpaxP/preinstall
/tmp/PKInstallSandbox.l57ygT/Scripts/com.apple.pkg.MXFPlugIns.yJpaxP/postinstall
Because the “system_installd” service has the special “com.apple.rootless.install.heritable” entitlement, these two scripts will be executed in a SIP-bypass context.
After seeing that these two scripts were inside the “/tmp/PKInstallSandbox.l57ygT” directory, the following questions came to mind:
- Can we modify the scripts inside the temporary location?
- Who created the temporary folder “PKInstallSandbox” with a random suffix?
- Is the newly created folder protected by SIP?
Guided by these questions, we started our investigation.
Through reversing and debugging, we found that the temporary folder was created by the “-[PKInstallSandbox prepareForCommitReturningError:]” function:
At line 16, it calls another function, “-[PKInstallSandbox _createDirectory:uniquifying:error:]”, which internally calls the API “mkdtemp” to create the folder without any restrictions.
After seeing that the “PKInstallSandbox.XXXXXX” folder was unprotected, we initially thought that it can be exploited and manipulated. However, we failed to directly modify the scripts inside the folder. This was because the subfolder “Scripts” was restricted, and it was moved from the restricted sandbox path, as we can see at line 25 in Figure 1.
There are at least two different methods to overcome this particular challenge and exploit this security issue.
The first exploit uses the mount trick. Perception Point discussed this in detail in its blog entry. Based on the investigation there, the mount trick can be done via the following steps:
- Create a virtual image file and mount it onto “/private/tmp”.
- Install an Apple-signed package with post-install scripts.
- Wait for the installer to finish the extraction of the scripts’ directory and gather the random parts of the extracted path.
- Unmount the image file. This will revert to the contents of “/private/tmp” before the extraction.
- Create the scripts directory (using the random path we obtained earlier) and deposit any script that we would want inside it.
Perception Point’s blog post also pointed out that the exploit discussed there is dependent on timing and might not succeed at all times.
Our exploit uses a different method: a symlink. This exploit can be done via the following steps:
- Monitor the creation of the “/tmp/PKInstallSandbox.XXXXXX” directory and replace it with a symlink to another “/tmp/fakebox” location to redirect the restricted scripts there.
- Once the scripts are located inside the “/tmp/fakebox”, remove the symlink and recreate the same “/tmp/PKInstallSandbox.XXXXXX” directory, then place the payload script in the “/tmp/PKInstallSandbox.XXXXXX/Scripts/pkgid.XXXXXX/” directory.
- Wait for the payload script to execute.
The full proof of concept for this exploit is uploaded on GitHub. Our proof-of-concept demonstration can also be seen in Figure 3.
Even though we are root, we can’t create a file in the restricted directory “/Library/Apple” because the SIP status is enabled. But with the help of the exploit program, we can execute arbitrary commands in a SIP-bypass context and successfully create a file in the restricted directory.
Apple’s patch for CVE-2022-22583
There is a bit of a confusion about how the “installd” service and the “system_installd” service operate. In Figure 4, we can see that the patch code, which can be seen at lines 17 and 18, makes the distinction between these two services:
For Apple-signed packages, the patch uses “OpenPath” along with its own restricted sandbox path. For other packages, it still uses a random path inside the “/tmp” directory.
Before introducing CVE-2022-32800, we need to understand some concepts related to “Install Sandbox.”
First, let’s take a look at “Sandbox Repository,” a directory returned and created by the “-[PKInstallSandboxManager _sandboxRepositoryForDestination:forSystemSoftware:create:error:]” function.
To summarize, there are four kinds of sandbox repositories:
- The installation target is the root volume “/”:
a. For Apple-signed PKGs: /Library/Apple/System/Library/InstallerSandboxes/.PKInstallSandboxManager-SystemSoftware
b. For other PKGs: /Library/InstallerSandboxes/.PKInstallSandboxManager
- The installation target is not the root volume:
a. For Apple-signed PKGs: $targetVolume/.PKInstallSandboxManager-SystemSoftware
b. For other PKGs: $targetVolume/.PKInstallSandboxManager
It should be noted that it is only when Apple-signed packages are installed to the root volume that the “Sandbox Repository” becomes restricted.
The “Sandbox Path” is used to store files such as scripts and payloads during installation.
It is a directory inside the “Sandbox Repository,” created by the “[PKInstallSandboxManager addSandboxPathForDestination:forSystemSoftware:]_block_invoke” method:
There are four kinds of sandbox paths, each with a universally unique identifier (UUID) name that indicates their specific sandbox state:
- UUID.sandbox: the first state created
- UUID.activeSandbox: the activated state; in use
- UUID.trashedSandbox: the deactivated state; to be trashed
- UUID.orphanedSandbox: the orphaned state; if the disk space is not enough, it will be cleaned up
“PKInstallSandbox” is an Objective-C class name for abstraction and encapsulation:
@interface PKInstallSandbox : NSObject <NSSecureCoding>
{
@public
NSString *_sandboxPath;
PKInstallRequest *_installRequest;
NSString *_scriptsPath;
NSString *_temporaryPath;
NSNumber *_stagedSize;
NSDate *_stageDate;
NSMutableDictionary *_scriptDirsByPackageSpecifier;
NSMutableDictionary *_bomPathsByPackageSpecifier;
NSMutableArray *_cleanupPaths;
NSDictionary *_scriptsAttributes;
NSDictionary *_temporaryAttributes;
NSSet *_previousPackageIdentifiersSharingGroupsWithSandbox;
long long _relevance;
BOOL _safeToReset;
}
+ (BOOL)supportsSecureCoding;
- (id)initWithCoder:(id)arg1;
- (id)initWithSandboxPath:(id)arg1 installRequest:(id)arg2 error:(id *)arg3;
@end
A new instance of “PKInstallSandbox” is initialized via the “-[PKInstallSandbox initWithSandboxPath:installRequest:error:]” method. This is according to a sandbox path and an install request.
Note that the instance is serializable and that the class implemented the “NSSecureCoding” protocol. The “system_installd” service can save or serialize an instance into a file named “SandboxState” inside the sandbox path via the “-[PKInstallSandboxManager saveSandboxAsStaged:]” method:
The “PKInstallSandbox” instance can also be restored or deserialized from the “SandboxState” file later via the “-[PKInstallSandboxManager _sandboxAtPath:matchingRequest:forUse:]” method:
Note that there is a check at line 57, which requires that restored install requests be deeply equal to the install request passed from the installation client. This check brings a small challenge to our exploitation procedure.
Before installation, the “system_installd” service needs to get an instance of the “PKInstallSandbox” according to the install request in the “-[PKInstallSandboxManager sandboxForRequest:created:error:]” function.
The function’s core logic is as follows:
First, it will enumerate all the folders with the “.sandbox” suffix from the “Sandbox Repository” and then restore the “PKInstallSandbox” instance from the “SandboxState” file inside.
Next, if it can’t find a “PKInstallSandbox” instance matching the install request, then it would enumerate all the folders with the “.activeSandbox” suffix and try to restore them from those locations.
Finally, if it still cannot match such a sandbox, it will create a new “Sandbox Path” and construct a new “PKInstallSandbox” instance.
CVE-2022-32800
The CVE-2022-32800 vulnerability allows an attacker to hijack the “SandboxState” file to get a SIP-bypass primitive.
The “SandboxState” file is stored in the “Sandbox Path,” which is inside the “Sandbox Repository.” In a normal scenario, the “Sandbox Repository” is restricted for Apple-signed packages.
However, if the installation destination is a DMG (disk image) volume, the “Sandbox Repository” is not restricted at all. The same is true for the “SandboxState” file. Thus, we can make a crafted “SandboxState” file to hijack the new “PKInstallSandbox” instance during the deserialization process. All the member variables of the “PKInstallSandbox” instance can then be controlled.
There are different ways to exploit the issue. In Figure 12, for example, we hijacked the member “_cleanupPaths” to get a primitive to remove arbitrary SIP-protected paths.
When the installation is finished, no matter whether it is successful or not, it will call the “-[PKInstallSandboxManager _removeSandbox:]” function to remove the sandbox and delete all the files and folders specified by the “_cleanupPaths” member.
The full proof of concept for this exploit can be found on GitHub, and a video of the demonstration can be viewed here.
Apple’s patch for CVE-2022-32800
Apple addressed this security issue in macOS 12.5.
The patch is in the “-[PKInstallSandboxManager _sandboxAtPath:matchingRequest:forUse:]” function:
As we can see in the check at line 38, it calls the “PKSIPFullyProtectedPath” function internally:
For Apple-signed packages, the “SandboxState” file is required to be trusted or restricted.
Security recommendations
To successfully protect systems against vulnerabilities, users must regularly update their operating systems. Regularly applying security patches will hinder malicious actors from exploiting vulnerabilities to elevate privileges and launch malicious attacks. As for the vulnerabilities discussed here, CVE-2022-22583 was patched in January 2022 and CVE-2022-32800 was patched in July 2022.
End users can benefit from security solutions such as the Trend Micro Antivirus for Mac and Trend Micro Protection Suites that help detect and block attacks that exploit such flaws.