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 означає Систему обов'язкового контролю доступу, яка є системою безпеки, вбудованою в операційну систему для захисту вашого комп'ютера. Вона працює, встановлюючи суворі правила щодо того, хто або що може отримати доступ до певних частин системи, таких як файли, програми та системні ресурси. Завдяки автоматичному виконанню цих правил, MACF забезпечує, що лише авторизовані користувачі та процеси можуть виконувати певні дії, зменшуючи ризик несанкціонованого доступу або шкідливих дій.
Зверніть увагу, що MACF насправді не приймає жодних рішень, оскільки вона лише перехоплює дії, залишаючи рішення модулям політики (розширенням ядра), які вона викликає, таким як AppleMobileFileIntegrity.kext
, Quarantine.kext
, Sandbox.kext
, TMSafetyNet.kext
та mcxalr.kext
.
Процес виконує syscall/mach trap
Відповідна функція викликається всередині ядра
Функція викликає MACF
MACF перевіряє модулі політики, які запросили підключити цю функцію у своїй політиці
MACF викликає відповідні політики
Політики вказують, чи дозволяють або забороняють дію
Apple є єдиною компанією, яка може використовувати KPI MAC Framework.
MACF використовує мітки, які потім політики перевіряють, чи повинні вони надати доступ чи ні. Код оголошення структури міток можна знайти тут, який потім використовується всередині struct ucred
тут в частині cr_label
. Мітка містить прапори та кількість слотів, які можуть бути використані політиками MACF для виділення вказівників. Наприклад, Sanbox вказуватиме на профіль контейнера.
Політика MACF визначає правила та умови, які застосовуються до певних операцій ядра.
Розширення ядра може налаштувати структуру mac_policy_conf
, а потім зареєструвати її, викликавши mac_policy_register
. З тут:
Легко ідентифікувати розширення ядра, які налаштовують ці політики, перевіряючи виклики до mac_policy_register
. Більше того, перевіряючи дизасемблювання розширення, також можна знайти використану структуру mac_policy_conf
.
Зверніть увагу, що політики MACF можуть бути зареєстровані та скасовані також динамічно.
Одним з основних полів mac_policy_conf
є mpc_ops
. Це поле вказує, які операції цікавлять політику. Зверніть увагу, що їх сотні, тому можливо обнулити всі з них, а потім вибрати лише ті, які цікавлять політику. З тут:
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
Який викликає макрос MAC_CHECK
, код якого можна знайти за посиланням https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/security/mac_internal.h#L261
Який пройде через всі зареєстровані політики mac, викликаючи їх функції та зберігаючи вихідні дані в змінній помилки, яка може бути перевизначена лише mac_error_select
кодами успіху, тому якщо будь-яка перевірка не пройде, вся перевірка зазнає невдачі, і дія не буде дозволена.
Однак пам'ятайте, що не всі виклики MACF використовуються лише для відмови в діях. Наприклад, mac_priv_grant
викликає макрос MAC_GRANT, який надасть запитувану привілегію, якщо будь-яка політика відповість 0:
Ці виклики призначені для перевірки та надання (десятків) привілеїв, визначених у bsd/sys/priv.h.
Деякий код ядра викликатиме priv_check_cred()
з bsd/kern/kern_priv.c з KAuth обліковими даними процесу та одним з кодів привілеїв, який викликатиме mac_priv_check
, щоб перевірити, чи будь-яка політика забороняє надання привілею, а потім викликатиме mac_priv_grant
, щоб перевірити, чи будь-яка політика надає привілей
.
Цей хук дозволяє перехоплювати всі системні виклики. У bsd/dev/[i386|arm]/systemcalls.c
можна побачити оголошену функцію unix_syscall
, яка містить цей код:
Який перевірить у викликаючому процесі бітову маску, чи слід поточному системному виклику викликати mac_proc_check_syscall_unix
. Це пов'язано з тим, що системні виклики викликаються так часто, що цікаво уникати виклику mac_proc_check_syscall_unix
щоразу.
Зверніть увагу, що функція proc_set_syscall_filter_mask()
, яка встановлює бітову маску системних викликів у процесі, викликається Sandbox для встановлення масок на пісочницях.
Можливо взаємодіяти з MACF через деякі системні виклики, визначені в security/mac.h:
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)