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.
- 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.
- Arg1 – Authorization data
- Arg2 – The path to change permissions to
- 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:
- Connect to the XPC through forked processes and replace the child processes with the legitimate binary.
- Call the changeFolderPermissionsAtPath method that is exposed by the XPC modifying permissions of the /etc/pam.d/login file.
- Replace the login file with one that allows authentication without password.
- 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.
Managing Security Consultant, X-Force Red Adversary Simulation, IBM