Being part of the Adversary Services team at IBM, it is important to keep your skills up to date and learn new things constantly. macOS security was one field where I decided to put more effort this year to further improve my exploitation and operation skills in macOS environments.

During my research, I decided to try and discover vulnerabilities in software that I had pre-installed on my laptop, which resulted in the discovery of this vulnerability. In this article, I will go through the analysis of the vulnerability, how I discovered it, and the exploitation and disclosure process. Although we made several efforts to get the vendor to fix the vulnerability, it remains unpatched at the time of writing this blog post.

Vulnerability details

  • CVE-2023-40713
  • Affected version: Version 2.0.65 (11)
  • Impact: Privilege Escalation
  • CVSS: 7.8 — HIGH

When GOG Galaxy is installed, it creates a new file in the /Library/LaunchDaemons directory with the name of com.galaxy.ClientService.plist. This behavior results in the creation of a Launch Daemon, which is a background process running with high privileges. Usually, these processes are used as helper tools to perform privileged actions by a low privileged application.

Inspecting the PLIST file created by GOG Galaxy, it shows that an XPC service named com.gog.galaxy.ClientService is exposed by the Privileged Helper tool located in /Library/PrivilegedHelperTools/com.gog.galaxy.ClientService.

These are highlighted in the contents of the PLIST file below:

?xml version=”1.0″ encoding=”UTF-8″?>

<!DOCTYPE plist PUBLIC “-//Apple//DTD PLIST 1.0//EN”

“http://www.apple.com/DTDs/PropertyList-1.0.dtd”>

<plist version=”1.0″>

<dict>

  <key>Label</key>

  <string>com.gog.galaxy.ClientService</string>

  <key>MachServices</key>

  <dict>

    <key>com.gog.galaxy.ClientService</key>

    <true/>

  </dict>

  <key>Program</key>

  <string>/Library/PrivilegedHelperTools/com.gog.galaxy.ClientService<

/string>

  <key>ProgramArguments</key>

  <array>

  

<string>/Library/PrivilegedHelperTools/com.gog.galaxy.ClientService</string>

  </array>

</dict>

</plist>

Quick intro to XPC service

An XPC service is an inter-process communication mechanism heavily used in macOS. It allows you to create helper tools that can perform certain tasks on behalf of an application. This is typically used for tasks that run in the background or tasks that require elevated privileges. It is usually composed of the XPC service acting as a server and an application that connects to the XPC service.

The following diagram shows a connection between the application and the XPC service:

Figure 1: NSXPC architecture (Source: Apple Developer)

I will not go into details of XPC as it is a complex topic but just think of it as the usual inter-process communication where a client can call methods that are exposed by the XPC service.

Connection validation in GOG Galaxy

The ability to call methods exposed by a service running with high privileges sounds like a bad idea. An application can just connect to the XPC service, call exposed methods, and perform actions on behalf of the XPC service. Although this is possible, most applications verify the client application and only allow specific applications to call the exposed methods.

For example, in the GOG Galaxy Privileged Helper tool, the function responsible for checking if a connection is valid (shouldAcceptNewConnection) is shown below:

-(char)listener:(void *)arg2 shouldAcceptNewConnection:(void *)arg3 {

    r14 = self;

    rax = [arg3 retain];

    r15 = rax;

    if ([r14 areRequirementsValidForProcessId:[rax processIdentifier]] !=

0x0) {

            rax = [NSXPCInterface

interfaceWithProtocol:@protocol(ClientServiceProtocol)];

            rax = [rax retain];

            [r15 setExportedInterface:rax];

            [rax release];

            [r15 setExportedObject:r14];

            rbx = 0x1;

            [r15 resume];

            

  [REDACTED]

The application calls the areRequirementsValidForProcessId function with the processIdentifier parameter which is the PID of the connecting process. If this function returns 0, it will export the object and allow the connection, otherwise, it will exit.

Reviewing the areRequirementsValidForProcessId function, it receives the processID as a parameter, copies the security attributes of the process using the PID and checks them against the following security requirements:

[REDACTED]


void galaxy::service_library::Logger::Info<char const*>(“Validating
signature of calling process at path {}.”, 0x33);

rax = SecRequirementCreateWithString(@”identifier \”com.gog.galaxy\” and
anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /*
exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */
and certificate leaf[subject.OU] = \”9WS36Q8886\”“, 0x0, &var_48);

[REDACTED]

The security check itself is valid as it checks if the package identifier is com.gog.galaxy, if the certification is a valid Apple certificate, and if the team identifier is 9WS36Q8886 (which is the team identifier for GOG Galaxy).

The PID re-use problem

The problem exists because all these checks are performed against a PID which is not safe. In macOS, PIDs can be reused and we can even replace current executables with a different process with posix_spawn() while keeping the old PID. This was originally published on Warcon 18 in the presentation, Don’t Trust the PID (PDF).

This attack is based on a race condition where an exploit is going to send several messages to the XPC service and just after that, execute posix_spawn with the binary that fulfills all the security requirements to replace the malicious binary PID. By queuing a lot of messages, the time between the message processing and process validation will allow the exploit to replace the exploit PID with the real application validating the connection.

The following image shows a graphical representation of the attack:

Figure 2: Race condition when queuing XPC messages (Source: IBM)

Exposed methods of the Privileged Helper tool

Although we can manipulate the Privileged Helper and invoke any exposed methods, it is not useful unless these methods offer an opportunity for exploitation. The protocol used between the XPC service and client was called ClientServiceProtocol.

This protocol exposed the following methods:

 

– (void)requestShutdown; – (void)removeOldClientService; 


– (void)fillProcessInformationForPids:(NSArray *)arg1 authorization: (NSData
*)arg2 withReply:(void (^)(NSArray *))arg3; 


– (void)createFolderAtPath:(NSString *)arg1 authorization:(NSData *)arg2
withReply:(void (^)(NSError *))arg3; 

– (void)renameClientBundleAtPath:(NSString *)arg1 withReply:(void (^)
(NSError *))arg2; 

– (void)changeFolderPermissionsAtPath:(NSString *)arg1 authorization:
(NSData *)arg2 withReply:(void (^)(NSError *))arg3; 

– (void)getVersionWithReply:(void (^)(NSString *))arg1;

While multiple methods were exposed, the most interesting one was changeFolderPermissionsAtPath, which required three arguments.

  1. Arg1 – Authorization data
  2. Arg2 – The path to change permissions to
  3. Arg3 – An array for the response

The function first checks the authorization data which can be bypassed by creating an authorization structure without any rights. After authorization is checked, the function performs a variety of actions, but the most important is calling the chmod function. The chmod function is called with the path provided in arg2 and 0x1ff, which makes any targeted file globally readable, writable, and executable.

-(void)changeFolderPermissionsAtPath:(void *)arg2 authorization:(void *)arg3

withReply:(void *)arg4 {

    r13 = [arg2 retain];

    r14 = [arg3 retain];

    var_C8 = [arg4 retain];

    rax = objc_retainAutorelease(r13); <—- RAX is initated from r13, which

is initiated from arg2

    

    var_F8 = rax;

[REDACTED]

    rax = [NSFileManager defaultManager];

    rax = [rax retain];

    r13 = rax;

    var_E8 = [[rax subpathsAtPath:var_F8] retain];

    rax = objc_retainAutorelease(var_F8);

    var_E0 = rax;

    rax = [rax UTF8String];

    rax = chmod(rax, 0x1ff); <— Permissions are changed using chmod

    var_B4 = rax;

    

    if (rax == 0x0) goto loc_1000c1be9;

 

 [REDACTED]

As a low-privileged user, we can communicate with the XPC service and change the permissions of any file in the system. This can be used to abuse the system in several ways, such as by modifying a Launch Daemon to execute a malicious binary when the daemon is loaded. However, this method requires a restart, so a better alternative is to modify the /etc/pam.d/login file.

The /etc/pam.d/login file is a configuration file for the Pluggable Authentication Modules (PAM) system on macOS. It contains the default authentication configuration for all services that use PAM. Modifying the auth entries to use the pam_permit.so module will allow any authentication attempt to succeed. This means that we will be able to run sudo on the target machine without entering a password.

Original File:

sh-3.2# cat /etc/pam.d/login

# login: auth account password session

auth       optional       pam_krb5.so use_kcminit

auth       optional       pam_ntlm.so try_first_pass

auth       optional       pam_mount.so try_first_pass

auth       required       pam_opendirectory.so try_first_pass

account    required       pam_nologin.so

account    required       pam_opendirectory.so

password   required       pam_opendirectory.so

session    required       pam_launchd.so
session    required       pam_uwtmp.so
session    optional       pam_mount.so
sh-3.2#

Replaced File:

sh-3.2# cat /etc/pam.d/login

# login: auth account password session

auth       optional       pam_permit.so

auth       optional       pam_permit.so

auth       optional       pam_permit.so

auth       required       pam_permit.so

account    required       pam_nologin.so

account    required       pam_opendirectory.so

password   required       pam_opendirectory.so

session    required       pam_launchd.so

session    required       pam_uwtmp.so

session    optional       pam_mount.so

sh-3.2#

Exploitation steps

Here are the required steps to successfully exploit the vulnerability:

  1. Connect to the XPC through forked processes and replace the child processes with the legitimate binary.
  2. Call the changeFolderPermissionsAtPath method that is exposed by the XPC modifying permissions of the /etc/pam.d/login file.
  3. Replace the login file with one that allows authentication without password.
  4. Escalate to root running sudo su.

We chose not to release the exploit code for this vulnerability, as it is still a 0-day. However, we have provided all the information needed to reproduce the vulnerability.

Demo

Defensive considerations

Adversaries abuse XPC services to execute malicious code, perform application white-listing bypass, and escalate privileges. On macOS, applications can leverage XPC services to send messages to the XPC service daemon, which runs with root privileges on the system. These attacks often take advantage of improper XPC client validation and poor input validation to allow code to be executed with elevated privileges.

Securing XPC can be challenging as it requires secure coding practices from the application vendor such as enabling the hardened runtime for XPC services and notarizing the application. Organizations can and should look for unsigned XPC client services and understand the risks associated with their operation in the environment. Additionally, monitoring for processes that make suspicious calls to processes with elevated privileges could be an early indication of this type of attack.

Disclosure timeline

Below is the disclosure timeline:

  • 25 November 2022 — Vulnerability reported to GOG Galaxy
  • 25 November 2022 — GOG Galaxy Support team responds saying details have been passed to the security team.
  • 01 December 2022 — Asking for an update
  • 01 December 2022 — GOG Galaxy Support team responds saying no updates were received from the security team.
  • 09 December 2022 — Asking for update
  • 09 December 2022 — GOG Galaxy Support team responds saying no updates were received from the security team.
  • 12 January 2023 — Asking for an update, no response from GOG Galaxy Support team 08 February 2023 — Asking for an update
  • 16 February 2023 — GOG Galaxy Support team responds saying no updates were received from the security team
  • 06 March 2023 — Vendor was notified that we plan on publishing and advisory as 90 days have passed since reporting the vulnerability.
  • June 2023 — Disclosure

To learn how IBM X-Force can help you with anything regarding cybersecurity including incident response, threat intelligence, or offensive security services schedule a meeting here.

If you are experiencing cybersecurity issues or an incident, contact X-Force to help: US hotline 1-888-241-9812 | Global hotline (+001) 312-212-8034.

More from Adversary Services

Extending and automating NightHawk with DayBird

13 min read - NightHawk, MDSec’s commercial C2 product, has focused on operational security and detection avoidance since its initial release in December 2021. While the core functionality of the framework has been effective within the scope of these objectives, our team noticed certain features were missing as we started incorporating NightHawk into our engagements alongside our other C2 options. Most notably, there was no equivalent in NightHawk to Cobalt Strike’s Aggressor scripting platform, severely limiting automation capabilities. While I know how big of…

Critically close to zero(day): Exploiting Microsoft Kernel streaming service

10 min read - Last month Microsoft patched a vulnerability in the Microsoft Kernel Streaming Server, a Windows kernel component used in the virtualization and sharing of camera devices. The vulnerability, CVE-2023-36802, allows a local attacker to escalate privileges to SYSTEM. This blog post details my process of exploring a new attack surface in the Windows kernel, finding a 0-day vulnerability, exploring an interesting bug class, and building a stable exploit. This post doesn’t require any specialized Windows kernel knowledge to follow along, though…

Reflective call stack detections and evasions

6 min read - In a blog published this March, we explored reflective loading through the lens of an offensive security tool developer, highlighting detection and evasion opportunities along the way. This time we are diving into call stack detections and evasions, and how BokuLoader reflectively loads call stack spoofing capabilities into beacon. We created this blog and public release of BokuLoader during Dylan’s summer 2023 internship with IBM X-Force Red. While researching call stack spoofing for our in-house C2, this was one of…

Topic updates

Get email updates and stay ahead of the latest threats to the security landscape, thought leadership and research.
Subscribe today