Im vorherigen Bild ist es möglich zu beobachten, wie die Sandbox geladen wird, wenn eine Anwendung mit dem Recht com.apple.security.app-sandbox ausgeführt wird.
Der Compiler wird /usr/lib/libSystem.B.dylib mit der Binärdatei verknüpfen.
Dann wird libSystem.B mehrere Funktionen aufrufen, bis die xpc_pipe_routine die Berechtigungen der App an securityd sendet. Securityd überprüft, ob der Prozess innerhalb der Sandbox quarantiniert werden soll, und wenn ja, wird er quarantiniert.
Schließlich wird die Sandbox mit einem Aufruf von __sandbox_ms aktiviert, der __mac_syscall aufruft.
Mögliche Umgehungen
Umgehung des Quarantäneattributs
Dateien, die von sandboxed Prozessen erstellt werden, erhalten das Quarantäneattribut, um ein Entkommen aus der Sandbox zu verhindern. Wenn es dir jedoch gelingt, einen .app-Ordner ohne das Quarantäneattribut innerhalb einer sandboxed Anwendung zu erstellen, könntest du die App-Bundle-Binärdatei auf /bin/bash verweisen lassen und einige Umgebungsvariablen in der plist hinzufügen, um open auszunutzen, um die neue App unsandboxed zu starten.
Daher kannst du im Moment, wenn du nur in der Lage bist, einen Ordner mit einem Namen, der auf .app endet, ohne ein Quarantäneattribut zu erstellen, die Sandbox umgehen, da macOS nur das Quarantäne-Attribut im .app-Ordner und in der Hauptausführungsdatei überprüft (und wir werden die Hauptausführungsdatei auf /bin/bash verweisen).
Beachte, dass, wenn ein .app-Bundle bereits autorisiert wurde, um ausgeführt zu werden (es hat ein Quarantäne-xttr mit dem autorisierten Ausführungsflag), du es auch ausnutzen könntest... es sei denn, du kannst jetzt nicht in .app-Bundles schreiben, es sei denn, du hast einige privilegierte TCC-Berechtigungen (die du in einer hohen Sandbox nicht haben wirst).
Selbst wenn eine Anwendung für die Sandbox vorgesehen ist (com.apple.security.app-sandbox), ist es möglich, die Sandbox zu umgehen, wenn sie von einem LaunchAgent (~/Library/LaunchAgents) ausgeführt wird, zum Beispiel.
Wie in diesem Beitrag erklärt, wenn du mit einer sandboxed Anwendung Persistenz erreichen möchtest, könntest du sie automatisch als LaunchAgent ausführen lassen und möglicherweise schädlichen Code über DyLib-Umgebungsvariablen injizieren.
Ausnutzung von Auto-Start-Standorten
Wenn ein sandboxed Prozess in einem Ort schreiben kann, wo später eine unsandboxed Anwendung die Binärdatei ausführen wird, kann er einfach entkommen, indem er dort die Binärdatei platziert. Ein gutes Beispiel für solche Standorte sind ~/Library/LaunchAgents oder /System/Library/LaunchDaemons.
Dafür benötigst du möglicherweise sogar 2 Schritte: Um einen Prozess mit einer weniger restriktiven Sandbox (file-read*, file-write*) auszuführen, der deinen Code tatsächlich an einem Ort schreibt, wo er unsandboxed ausgeführt wird.
Wenn du von dem sandboxed Prozess in der Lage bist, andere Prozesse zu kompromittieren, die in weniger restriktiven Sandboxes (oder gar keiner) laufen, wirst du in der Lage sein, in deren Sandboxes zu entkommen:
Diese Forschung entdeckte 2 Möglichkeiten, die Sandbox zu umgehen. Da die Sandbox aus dem Userland angewendet wird, wenn die libSystem-Bibliothek geladen wird. Wenn eine Binärdatei das Laden dieser Bibliothek vermeiden könnte, würde sie niemals sandboxed werden:
Wenn die Binärdatei vollständig statisch kompiliert wäre, könnte sie das Laden dieser Bibliothek vermeiden.
Wenn die Binärdatei keine Bibliotheken laden müsste (da der Linker auch in libSystem ist), müsste sie libSystem nicht laden.
Shellcodes
Beachte, dass sogar Shellcodes in ARM64 in libSystem.dylib verlinkt werden müssen:
# Compile itgcc-Xlinker-sectcreate-Xlinker__TEXT-Xlinker__info_plist-XlinkerInfo.plistsand.c-osand# Create a certificate for "Code Signing"# Apply the entitlements via signingcodesign-s<cert-name>--entitlementsentitlements.xmlsand
Die App wird versuchen, die Datei ~/Desktop/del.txt zu lesen, was der Sandbox nicht erlaubt.
Erstellen Sie eine Datei dort, da die Sandbox, sobald sie umgangen ist, in der Lage sein wird, sie zu lesen:
echo"Sandbox Bypassed">~/Desktop/del.txt
Lass uns die Anwendung debuggen, um zu sehen, wann der Sandbox geladen wird:
# Load app in debugginglldb./sand# Set breakpoint in xpc_pipe_routine(lldb) bxpc_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_routineframe#1: 0x000000019300cf80 libsystem_secinit.dylib`_libsecinit_appsandbox + 584frame#2: 0x00000001874199c4 libsystem_trace.dylib`_os_activity_initiate_impl + 64frame#3: 0x000000019300cce4 libsystem_secinit.dylib`_libsecinit_initializer + 80frame#4: 0x0000000193023694 libSystem.B.dylib`libSystem_initializer + 272# To avoid lldb cutting info(lldb) settingssettarget.max-string-summary-length10000# 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) registerreadx2x2=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) memoryread-fp0x000000016fdfd660-c10x16fdfd660: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) breakpointset--name__mac_syscall--condition'($x1 == 0)'(lldb) c# The 1 arg is the name of the policy, in this case "Sandbox"(lldb) memoryread-fs $x00x19300eb22:"Sandbox"## BYPASS## Due to the previous bp, the process will be stopped in:Process2517stopped* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1frame#0: 0x0000000187659900 libsystem_kernel.dylib`__mac_syscalllibsystem_kernel.dylib`:-> 0x187659900<+0>:movx16,#0x17d0x187659904<+4>:svc#0x800x187659908<+8>:b.lo0x187659928 ; <+40>0x18765990c<+12>:pacibsp# To bypass jump to the b.lo address modifying some registers first(lldb) breakpointdelete1# Remove bp(lldb) registerwrite $pc 0x187659928#b.lo address(lldb) registerwrite $x0 0x00(lldb) registerwrite $x1 0x00(lldb) registerwrite $x16 0x17d(lldb) cProcess2517resumingSandboxBypassed!Process2517exitedwithstatus=0 (0x00000000)
Selbst wenn der Sandbox umgangen wird, wird TCC den Benutzer fragen, ob er dem Prozess erlauben möchte, Dateien vom Desktop zu lesen.