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 Mandatory Access Control Framework, que é um sistema de segurança embutido no sistema operacional para ajudar a proteger seu computador. Ele funciona estabelecendo regras rigorosas sobre quem ou o que pode acessar certas partes do sistema, como arquivos, aplicativos e recursos do sistema. Ao impor essas regras automaticamente, o MACF garante que apenas usuários e processos autorizados possam realizar ações específicas, reduzindo o risco de acesso não autorizado ou atividades maliciosas.
Observe que o MACF não toma realmente nenhuma decisão, pois apenas intercepta ações, deixando as decisões para os módulos de política (extensões do kernel) que chama, como AppleMobileFileIntegrity.kext
, Quarantine.kext
, Sandbox.kext
, TMSafetyNet.kext
e mcxalr.kext
.
O processo realiza uma syscall/mach trap
A função relevante é chamada dentro do kernel
A função chama o MACF
O MACF verifica os módulos de política que solicitaram para interceptar essa função em sua política
O MACF chama as políticas relevantes
As políticas indicam se permitem ou negam a ação
A Apple é a única que pode usar o KPI do MAC Framework.
O MACF usa rótulos que, em seguida, as políticas verificam se devem conceder algum acesso ou não. O código da declaração da estrutura dos rótulos pode ser encontrado aqui, que é então usado dentro da struct ucred
em aqui na parte cr_label
. O rótulo contém flags e um número de slots que podem ser usados pelas políticas do MACF para alocar ponteiros. Por exemplo, o Sandbox apontará para o perfil do contêiner.
Uma Política do MACF define regras e condições a serem aplicadas em certas operações do kernel.
Uma extensão do kernel poderia configurar uma estrutura mac_policy_conf
e, em seguida, registrá-la chamando mac_policy_register
. A partir daqui:
É fácil identificar as extensões do kernel que configuram essas políticas verificando as chamadas para mac_policy_register
. Além disso, verificando a desassemblagem da extensão, também é possível encontrar a struct mac_policy_conf
utilizada.
Observe que as políticas MACF podem ser registradas e desregistradas também dinamicamente.
Um dos principais campos da mac_policy_conf
é o mpc_ops
. Este campo especifica quais operações a política está interessada. Note que existem centenas delas, então é possível zerar todas e, em seguida, selecionar apenas aquelas que a política está interessada. De aqui:
Quase todos os hooks serão chamados de volta pelo MACF quando uma dessas operações for interceptada. No entanto, os hooks mpo_policy_*
são uma exceção porque mpo_hook_policy_init()
é um callback chamado durante o registro (após mac_policy_register()
) e mpo_hook_policy_initbsd()
é chamado durante o registro tardio, uma vez que o subsistema BSD tenha sido inicializado corretamente.
Além disso, o hook mpo_policy_syscall
pode ser registrado por qualquer kext para expor uma interface de chamada estilo ioctl privada. Assim, um cliente de usuário poderá chamar mac_syscall
(#381) especificando como parâmetros o nome da política com um código inteiro e argumentos opcionais.
Por exemplo, o Sandbox.kext
usa isso com frequência.
Verificando o __DATA.__const*
do kext, é possível identificar a estrutura mac_policy_ops
usada ao registrar a política. É possível encontrá-la porque seu ponteiro está em um deslocamento dentro de mpo_policy_conf
e também devido à quantidade de ponteiros NULL que estarão naquela área.
Além disso, também é possível obter a lista de kexts que configuraram uma política despejando da memória a estrutura _mac_policy_list
, que é atualizada com cada política que é registrada.
O MACF é inicializado muito cedo. Ele é configurado na bootstrap_thread
do XNU: após ipc_bootstrap
, uma chamada para mac_policy_init()
, que inicializa a mac_policy_list
, e momentos depois mac_policy_initmach()
é chamado. Entre outras coisas, essa função obterá todos os kexts da Apple com a chave AppleSecurityExtension
em seu Info.plist, como ALF.kext
, AppleMobileFileIntegrity.kext
, Quarantine.kext
, Sandbox.kext
e TMSafetyNet.kext
, e os carrega.
É comum encontrar chamadas para o MACF definidas em código como: blocos condicionais #if CONFIG_MAC
. Além disso, dentro desses blocos, é possível encontrar chamadas para mac_proc_check*
, que chama o MACF para verificar permissões para realizar certas ações. Além disso, o formato das chamadas do MACF é: mac_<object>_<opType>_opName
.
O objeto é um dos seguintes: bpfdesc
, cred
, file
, proc
, vnode
, mount
, devfs
, ifnet
, inpcb
, mbuf
, ipq
, pipe
, sysv[msg/msq/shm/sem]
, posix[shm/sem]
, socket
, kext
.
O opType
geralmente é check, que será usado para permitir ou negar a ação. No entanto, também é possível encontrar notify, que permitirá que o kext reaja à ação dada.
Você pode encontrar um exemplo em https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/kern/kern_mman.c#L621:
Então, é possível encontrar o código de mac_file_check_mmap
em https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/security/mac_file.c#L174
Que chama o macro MAC_CHECK
, cujo código pode ser encontrado em https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/security/mac_internal.h#L261
Qual irá percorrer todas as políticas mac registradas chamando suas funções e armazenando a saída dentro da variável de erro, que só poderá ser substituída por mac_error_select
por códigos de sucesso, então se qualquer verificação falhar, a verificação completa falhará e a ação não será permitida.
No entanto, lembre-se de que nem todos os callouts do MACF são usados apenas para negar ações. Por exemplo, mac_priv_grant
chama o macro MAC_GRANT, que concederá o privilégio solicitado se qualquer política responder com um 0:
Essas chamadas são destinadas a verificar e fornecer (dezenas de) privilegios definidos em bsd/sys/priv.h.
Algum código do kernel chamaria priv_check_cred()
de bsd/kern/kern_priv.c com as credenciais KAuth do processo e um dos códigos de privilégio que chamará mac_priv_check
para ver se alguma política nega a concessão do privilégio e, em seguida, chama mac_priv_grant
para ver se alguma política concede o privilegio
.
Esse hook permite interceptar todas as chamadas de sistema. Em bsd/dev/[i386|arm]/systemcalls.c
é possível ver a função declarada unix_syscall
, que contém este código:
Qual verificará no bitmask do processo chamador se a syscall atual deve chamar mac_proc_check_syscall_unix
. Isso ocorre porque as syscalls são chamadas com tanta frequência que é interessante evitar chamar mac_proc_check_syscall_unix
toda vez.
Observe que a função proc_set_syscall_filter_mask()
, que define a máscara de syscalls em um processo, é chamada pelo Sandbox para definir máscaras em processos isolados.
É possível interagir com o MACF através de algumas syscalls definidas em security/mac.h:
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)