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 oznacza Framework Obowiązkowej Kontroli Dostępu, który jest systemem zabezpieczeń wbudowanym w system operacyjny, aby pomóc chronić komputer. Działa poprzez ustalanie ścisłych zasad dotyczących tego, kto lub co może uzyskać dostęp do określonych części systemu, takich jak pliki, aplikacje i zasoby systemowe. Dzięki automatycznemu egzekwowaniu tych zasad, MACF zapewnia, że tylko autoryzowani użytkownicy i procesy mogą wykonywać określone działania, co zmniejsza ryzyko nieautoryzowanego dostępu lub złośliwych działań.
Należy zauważyć, że MACF nie podejmuje żadnych decyzji, ponieważ po prostu przechwytuje działania, pozostawiając decyzje modułom polityki (rozszerzenia jądra), które wywołuje, takim jak AppleMobileFileIntegrity.kext
, Quarantine.kext
, Sandbox.kext
, TMSafetyNet.kext
i mcxalr.kext
.
Proces wykonuje syscall/mach trap
Odpowiednia funkcja jest wywoływana wewnątrz jądra
Funkcja wywołuje MACF
MACF sprawdza moduły polityki, które zażądały podpięcia tej funkcji w swojej polityce
MACF wywołuje odpowiednie polityki
Polityki wskazują, czy zezwalają na działanie, czy je odrzucają
Apple jest jedyną firmą, która może korzystać z KPI Framework MAC.
MACF używa etykiet, które następnie polityki sprawdzają, czy powinny przyznać dostęp, czy nie. Kod deklaracji struktury etykiet można znaleźć tutaj, która jest następnie używana wewnątrz struct ucred
w tutaj w części cr_label
. Etykieta zawiera flagi i liczbę slotów, które mogą być używane przez polityki MACF do alokacji wskaźników. Na przykład Sanbox będzie wskazywał na profil kontenera.
Polityka MACF definiuje zasady i warunki, które mają być stosowane w określonych operacjach jądra.
Rozszerzenie jądra może skonfigurować strukturę mac_policy_conf
, a następnie zarejestrować ją, wywołując mac_policy_register
. Z tutaj:
Łatwo jest zidentyfikować rozszerzenia jądra konfigurowane przez te polityki, sprawdzając wywołania do mac_policy_register
. Co więcej, sprawdzając dezasemblację rozszerzenia, można również znaleźć używaną strukturę mac_policy_conf
.
Należy zauważyć, że polityki MACF mogą być rejestrowane i deregisterowane również dynamicznie.
Jednym z głównych pól mac_policy_conf
jest mpc_ops
. To pole określa, które operacje interesują politykę. Należy zauważyć, że jest ich setki, więc możliwe jest wyzerowanie wszystkich z nich, a następnie wybranie tylko tych, którymi polityka jest zainteresowana. Z tutaj:
Almost all the hooks will be called back by MACF when one of those operations are intercepted. However, mpo_policy_*
hooks are an exception because mpo_hook_policy_init()
is a callback called upon registration (so after mac_policy_register()
) and mpo_hook_policy_initbsd()
is called during late registration once the BSD subsystem has initialised properly.
Moreover, the mpo_policy_syscall
hook can be registered by any kext to expose a private ioctl style call interface. Then, a user client will be able to call mac_syscall
(#381) specifying as parameters the policy name with an integer code and optional arguments.
For example, the Sandbox.kext
uses this a lot.
Checking the kext's __DATA.__const*
is possible to identify the mac_policy_ops
structure used when registering the policy. It's possible to find it because its pointer is at an offset inside mpo_policy_conf
and also because the amount of NULL pointers that will be in that area.
Moreover, it's also possible to get the list of kexts that have configured a policy by dumping from memory the struct _mac_policy_list
which is updated with every policy that is registered.
MACF is initialised very soon. It's set up in XNU's bootstrap_thread
: after ipc_bootstrap
a call to mac_policy_init()
which initializes the mac_policy_list
and moments later mac_policy_initmach()
is called. Among other things, this function will get all the Apple kexts with the AppleSecurityExtension
key in their Info.plist like ALF.kext
, AppleMobileFileIntegrity.kext
, Quarantine.kext
, Sandbox.kext
and TMSafetyNet.kext
and loads them.
It's common to find callouts to MACF defined in code like: #if CONFIG_MAC
conditional blocks. Moreover, inside these blocks it's possible to find calls to mac_proc_check*
which calls MACF to check for permissions to perform certain actions. Moreover, the format of the MACF callouts is: mac_<object>_<opType>_opName
.
The object is one of the following: bpfdesc
, cred
, file
, proc
, vnode
, mount
, devfs
, ifnet
, inpcb
, mbuf
, ipq
, pipe
, sysv[msg/msq/shm/sem]
, posix[shm/sem]
, socket
, kext
.
The opType
is usually check which will be used to allow or deny the action. However, it's also possible to find notify
, which will allow the kext to react to the given action.
You can find an example in https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/kern/kern_mman.c#L621:
Then, it's possible to find the code of mac_file_check_mmap
in https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/security/mac_file.c#L174
Który wywołuje makro MAC_CHECK
, którego kod można znaleźć pod adresem https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/security/mac_internal.h#L261
Które przejdzie przez wszystkie zarejestrowane polityki mac, wywołując ich funkcje i przechowując wynik w zmiennej error, która będzie mogła być nadpisywana tylko przez mac_error_select
za pomocą kodów sukcesu, więc jeśli jakiekolwiek sprawdzenie się nie powiedzie, całe sprawdzenie się nie powiedzie, a akcja nie będzie dozwolona.
Jednak pamiętaj, że nie wszystkie wywołania MACF są używane tylko do odrzucania działań. Na przykład mac_priv_grant
wywołuje makro MAC_GRANT, które przyzna żądane uprawnienie, jeśli jakakolwiek polityka odpowie 0:
Te wywołania mają na celu sprawdzenie i przyznanie (dziesiątek) uprawnień zdefiniowanych w bsd/sys/priv.h.
Niektóre kody jądra wywołają priv_check_cred()
z bsd/kern/kern_priv.c z poświadczeniami KAuth procesu oraz jednym z kodów uprawnień, co spowoduje wywołanie mac_priv_check
, aby sprawdzić, czy jakakolwiek polityka odmawia przyznania uprawnienia, a następnie wywołuje mac_priv_grant
, aby sprawdzić, czy jakakolwiek polityka przyznaje uprawnienie
.
Ten hak pozwala na przechwytywanie wszystkich wywołań systemowych. W bsd/dev/[i386|arm]/systemcalls.c
można zobaczyć zadeklarowaną funkcję unix_syscall
, która zawiera ten kod:
Który sprawdzi w wywołującym procesie bitmask, czy bieżące wywołanie systemowe powinno wywołać mac_proc_check_syscall_unix
. Dzieje się tak, ponieważ wywołania systemowe są wywoływane tak często, że warto unikać wywoływania mac_proc_check_syscall_unix
za każdym razem.
Zauważ, że funkcja proc_set_syscall_filter_mask()
, która ustawia bitmaski wywołań systemowych w procesie, jest wywoływana przez Sandbox w celu ustawienia masek na procesach w piaskownicy.
Możliwe jest interakcja z MACF za pomocą niektórych wywołań systemowych zdefiniowanych w security/mac.h:
Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE) Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)