macOS MACF - Mandatory Access Control Framework
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
MACF significa Marco de Control de Acceso Obligatorio, que es un sistema de seguridad integrado en el sistema operativo para ayudar a proteger su computadora. Funciona estableciendo reglas estrictas sobre quién o qué puede acceder a ciertas partes del sistema, como archivos, aplicaciones y recursos del sistema. Al hacer cumplir estas reglas automáticamente, MACF asegura que solo los usuarios y procesos autorizados puedan realizar acciones específicas, reduciendo el riesgo de acceso no autorizado o actividades maliciosas.
Tenga en cuenta que MACF realmente no toma decisiones, ya que solo intercepta acciones, deja las decisiones a los módulos de política (extensiones del kernel) que llama como AppleMobileFileIntegrity.kext
, Quarantine.kext
, Sandbox.kext
, TMSafetyNet.kext
y mcxalr.kext
.
El proceso realiza una llamada al syscall/trampa mach
Se llama a la función relevante dentro del kernel
La función llama a MACF
MACF verifica los módulos de política que solicitaron enganchar esa función en su política
MACF llama a las políticas relevantes
Las políticas indican si permiten o deniegan la acción
Apple es el único que puede usar el KPI del Marco MAC.
MACF utiliza etiquetas que luego las políticas comprobarán si deben otorgar algún acceso o no. El código de la declaración de la estructura de etiquetas se puede encontrar aquí, que luego se utiliza dentro de la struct ucred
en aquí en la parte de cr_label
. La etiqueta contiene banderas y un número de slots que pueden ser utilizados por las políticas de MACF para asignar punteros. Por ejemplo, Sanbox apuntará al perfil del contenedor.
Una Política de MACF define reglas y condiciones que se aplicarán en ciertas operaciones del kernel.
Una extensión del kernel podría configurar una estructura mac_policy_conf
y luego registrarla llamando a mac_policy_register
. Desde aquí:
Es fácil identificar las extensiones del kernel que configuran estas políticas al verificar las llamadas a mac_policy_register
. Además, al revisar el desensamblado de la extensión, también es posible encontrar la estructura mac_policy_conf
utilizada.
Tenga en cuenta que las políticas de MACF también se pueden registrar y anular dinámicamente.
Uno de los principales campos de mac_policy_conf
es mpc_ops
. Este campo especifica qué operaciones le interesan a la política. Tenga en cuenta que hay cientos de ellas, por lo que es posible establecer todas en cero y luego seleccionar solo las que le interesan a la política. Desde aquí:
Casi todos los hooks serán llamados por MACF cuando una de esas operaciones sea interceptada. Sin embargo, los hooks mpo_policy_*
son una excepción porque mpo_hook_policy_init()
es un callback llamado al registrarse (después de mac_policy_register()
) y mpo_hook_policy_initbsd()
se llama durante el registro tardío una vez que el subsistema BSD se ha inicializado correctamente.
Además, el hook mpo_policy_syscall
puede ser registrado por cualquier kext para exponer una llamada de estilo ioctl interface privada. Luego, un cliente de usuario podrá llamar a mac_syscall
(#381) especificando como parámetros el nombre de la política con un código entero y argumentos opcionales.
Por ejemplo, el Sandbox.kext
utiliza esto mucho.
Revisando el __DATA.__const*
del kext es posible identificar la estructura mac_policy_ops
utilizada al registrar la política. Es posible encontrarla porque su puntero está en un desplazamiento dentro de mpo_policy_conf
y también debido a la cantidad de punteros NULL que habrá en esa área.
Además, también es posible obtener la lista de kexts que han configurado una política volcando de la memoria la estructura _mac_policy_list
que se actualiza con cada política que se registra.
MACF se inicializa muy pronto. Se configura en el bootstrap_thread
de XNU: después de ipc_bootstrap
se llama a mac_policy_init()
que inicializa la mac_policy_list
y momentos después se llama a mac_policy_initmach()
. Entre otras cosas, esta función obtendrá todos los kexts de Apple con la clave AppleSecurityExtension
en su Info.plist como ALF.kext
, AppleMobileFileIntegrity.kext
, Quarantine.kext
, Sandbox.kext
y TMSafetyNet.kext
y los carga.
Es común encontrar llamadas a MACF definidas en el código como: bloques condicionales #if CONFIG_MAC
. Además, dentro de estos bloques es posible encontrar llamadas a mac_proc_check*
que llama a MACF para verificar permisos para realizar ciertas acciones. Además, el formato de las llamadas de MACF es: mac_<object>_<opType>_opName
.
El objeto es uno de los siguientes: bpfdesc
, cred
, file
, proc
, vnode
, mount
, devfs
, ifnet
, inpcb
, mbuf
, ipq
, pipe
, sysv[msg/msq/shm/sem]
, posix[shm/sem]
, socket
, kext
.
El opType
suele ser check que se utilizará para permitir o denegar la acción. Sin embargo, también es posible encontrar notify
, que permitirá al kext reaccionar a la acción dada.
Puedes encontrar un ejemplo en https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/kern/kern_mman.c#L621:
Luego, es posible encontrar el código de mac_file_check_mmap
en https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/security/mac_file.c#L174
El cual está llamando al macro MAC_CHECK
, cuyo código se puede encontrar en https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/security/mac_internal.h#L261
Which will go over all the registered mac policies calling their functions and storing the output inside the error variable, which will only be overridable by mac_error_select
by success codes so if any check fails the complete check will fail and the action won't be allowed.
Sin embargo, recuerda que no todos los llamados de MACF se utilizan solo para denegar acciones. Por ejemplo, mac_priv_grant
llama al macro MAC_GRANT, que otorgará el privilegio solicitado si alguna política responde con un 0:
Estas llamadas están destinadas a verificar y proporcionar (decenas de) privilegios definidos en bsd/sys/priv.h.
Algún código del kernel llamaría a priv_check_cred()
desde bsd/kern/kern_priv.c con las credenciales KAuth del proceso y uno de los códigos de privilegios que llamará a mac_priv_check
para ver si alguna política niega otorgar el privilegio y luego llama a mac_priv_grant
para ver si alguna política otorga el privilegio
.
Este gancho permite interceptar todas las llamadas al sistema. En bsd/dev/[i386|arm]/systemcalls.c
es posible ver la función declarada unix_syscall
, que contiene este código:
Que verificará en el bitmask del proceso que llama si la syscall actual debería llamar a mac_proc_check_syscall_unix
. Esto se debe a que las syscalls se llaman con tanta frecuencia que es interesante evitar llamar a mac_proc_check_syscall_unix
cada vez.
Tenga en cuenta que la función proc_set_syscall_filter_mask()
, que establece el bitmask de las syscalls en un proceso, es llamada por Sandbox para establecer máscaras en procesos en sandbox.
Es posible interactuar con MACF a través de algunas syscalls definidas en security/mac.h:
Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE) Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)