macOS MACF
Reading time: 10 minutes
tip
Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za udukuzi kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.
Basic Information
MACF inamaanisha Mandatory Access Control Framework, ambayo ni mfumo wa usalama uliojengwa ndani ya mfumo wa uendeshaji kusaidia kulinda kompyuta yako. Inafanya kazi kwa kuweka kanuni kali kuhusu nani au nini kinaweza kufikia sehemu fulani za mfumo, kama vile faili, programu, na rasilimali za mfumo. Kwa kutekeleza kanuni hizi kiotomatiki, MACF inahakikisha kwamba ni watumiaji na michakato walioidhinishwa pekee wanaweza kufanya vitendo maalum, kupunguza hatari ya ufikiaji usioidhinishwa au shughuli mbaya.
Kumbuka kwamba MACF haifanyi maamuzi yoyote kwani inachukua tu hatua, inawaachia maamuzi moduli za sera (kernel extensions) inazopiga simu kama AppleMobileFileIntegrity.kext
, Quarantine.kext
, Sandbox.kext
, TMSafetyNet.kext
na mcxalr.kext
.
Flow
- Mchakato unafanya syscall/mach trap
- Kazi husika inaitwa ndani ya kernel
- Kazi inaita MACF
- MACF inakagua moduli za sera ambazo zilitaka kuunganisha kazi hiyo katika sera zao
- MACF inaita sera husika
- Sera zinaonyesha kama zinaruhusu au kukataa hatua hiyo
caution
Apple ndiye pekee anayeweza kutumia KPI ya MAC Framework.
Labels
MACF inatumia labels ambazo sera zitakazokagua ikiwa zinapaswa kutoa ufikiaji fulani au la. Kanuni ya tamko la muundo wa labels inaweza kupatikana hapa, ambayo inatumika ndani ya struct ucred
katika hapa katika sehemu ya cr_label
. Label ina bendera na nambari ya slots ambazo zinaweza kutumika na sera za MACF kutoa viashiria. Kwa mfano, Sanbox itakuwa na kiashiria kwa wasifu wa kontena.
MACF Policies
Sera ya MACF inafafanua kanuni na masharti yanayopaswa kutumika katika operesheni fulani za kernel.
Kupanua kernel kunaweza kuunda muundo wa mac_policy_conf
na kisha kujiandikisha kwa kuita mac_policy_register
. Kutoka hapa:
#define mpc_t struct mac_policy_conf *
/**
@brief Mac policy configuration
This structure specifies the configuration information for a
MAC policy module. A policy module developer must supply
a short unique policy name, a more descriptive full name, a list of label
namespaces and count, a pointer to the registered enty point operations,
any load time flags, and optionally, a pointer to a label slot identifier.
The Framework will update the runtime flags (mpc_runtime_flags) to
indicate that the module has been registered.
If the label slot identifier (mpc_field_off) is NULL, the Framework
will not provide label storage for the policy. Otherwise, the
Framework will store the label location (slot) in this field.
The mpc_list field is used by the Framework and should not be
modified by policies.
*/
/* XXX - reorder these for better aligment on 64bit platforms */
struct mac_policy_conf {
const char *mpc_name; /** policy name */
const char *mpc_fullname; /** full name */
const char **mpc_labelnames; /** managed label namespaces */
unsigned int mpc_labelname_count; /** number of managed label namespaces */
struct mac_policy_ops *mpc_ops; /** operation vector */
int mpc_loadtime_flags; /** load time flags */
int *mpc_field_off; /** label slot */
int mpc_runtime_flags; /** run time flags */
mpc_t mpc_list; /** List reference */
void *mpc_data; /** module data */
};
Ni rahisi kubaini nyongeza za kernel zinazoweka sera hizi kwa kuangalia simu za mac_policy_register
. Zaidi ya hayo, kuangalia disassemble ya nyongeza pia inawezekana kupata mac_policy_conf
struct inayotumika.
Kumbuka kwamba sera za MACF zinaweza kuandikishwa na kuondolewa pia dynamically.
Moja ya maeneo makuu ya mac_policy_conf
ni mpc_ops
. Huu uwanja unaelezea ni shughuli zipi sera inavutiwa nazo. Kumbuka kwamba kuna mamia yao, hivyo inawezekana kuweka sifuri kwa zote kisha kuchagua zile tu ambazo sera inavutiwa nazo. Kutoka hapa:
struct mac_policy_ops {
mpo_audit_check_postselect_t *mpo_audit_check_postselect;
mpo_audit_check_preselect_t *mpo_audit_check_preselect;
mpo_bpfdesc_label_associate_t *mpo_bpfdesc_label_associate;
mpo_bpfdesc_label_destroy_t *mpo_bpfdesc_label_destroy;
mpo_bpfdesc_label_init_t *mpo_bpfdesc_label_init;
mpo_bpfdesc_check_receive_t *mpo_bpfdesc_check_receive;
mpo_cred_check_label_update_execve_t *mpo_cred_check_label_update_execve;
mpo_cred_check_label_update_t *mpo_cred_check_label_update;
[...]
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 Initialization
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.
MACF Callouts
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:
int
mmap(proc_t p, struct mmap_args *uap, user_addr_t *retval)
{
[...]
#if CONFIG_MACF
error = mac_file_check_mmap(vfs_context_ucred(ctx),
fp->fp_glob, prot, flags, file_pos + pageoff,
&maxprot);
if (error) {
(void)vnode_put(vp);
goto bad;
}
#endif /* MAC */
[...]
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_file_check_mmap(struct ucred *cred, struct fileglob *fg, int prot,
int flags, uint64_t offset, int *maxprot)
{
int error;
int maxp;
maxp = *maxprot;
MAC_CHECK(file_check_mmap, cred, fg, NULL, prot, flags, offset, &maxp);
if ((maxp | *maxprot) != *maxprot) {
panic("file_check_mmap increased max protections");
}
*maxprot = maxp;
return error;
}
Ambayo inaita MAC_CHECK
macro, ambayo msimbo wake unaweza kupatikana katika https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/security/mac_internal.h#L261
/*
* MAC_CHECK performs the designated check by walking the policy
* module list and checking with each as to how it feels about the
* request. Note that it returns its value via 'error' in the scope
* of the caller.
*/
#define MAC_CHECK(check, args...) do { \
error = 0; \
MAC_POLICY_ITERATE({ \
if (mpc->mpc_ops->mpo_ ## check != NULL) { \
DTRACE_MACF3(mac__call__ ## check, void *, mpc, int, error, int, MAC_ITERATE_CHECK); \
int __step_err = mpc->mpc_ops->mpo_ ## check (args); \
DTRACE_MACF2(mac__rslt__ ## check, void *, mpc, int, __step_err); \
error = mac_error_select(__step_err, error); \
} \
}); \
} while (0)
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.
tip
Hata hivyo, kumbuka kwamba si MACF callouts zote zinatumika tu kukataa vitendo. Kwa mfano, mac_priv_grant
inaita macro MAC_GRANT, ambayo itatoa kibali kilichotakiwa ikiwa sera yoyote itajibu kwa 0:
/*
* MAC_GRANT performs the designated check by walking the policy
* module list and checking with each as to how it feels about the
* request. Unlike MAC_CHECK, it grants if any policies return '0',
* and otherwise returns EPERM. Note that it returns its value via
* 'error' in the scope of the caller.
*/
#define MAC_GRANT(check, args...) do { \
error = EPERM; \
MAC_POLICY_ITERATE({ \
if (mpc->mpc_ops->mpo_ ## check != NULL) { \
DTRACE_MACF3(mac__call__ ## check, void *, mpc, int, error, int, MAC_ITERATE_GRANT); \
int __step_res = mpc->mpc_ops->mpo_ ## check (args); \
if (__step_res == 0) { \
error = 0; \
} \
DTRACE_MACF2(mac__rslt__ ## check, void *, mpc, int, __step_res); \
} \
}); \
} while (0)
priv_check & priv_grant
Hizi callas zinakusudia kuangalia na kutoa (mifumo ya) privileges zilizofafanuliwa katika bsd/sys/priv.h.
Baadhi ya msimbo wa kernel ungeita priv_check_cred()
kutoka bsd/kern/kern_priv.c kwa KAuth credentials za mchakato na moja ya msimbo wa privileges ambayo itaita mac_priv_check
kuona ikiwa sera yoyote inakataa kutoa kibali na kisha inaita mac_priv_grant
kuona ikiwa sera yoyote inatoa privilege
.
proc_check_syscall_unix
Hii hook inaruhusu kukamata wito wote wa mfumo. Katika bsd/dev/[i386|arm]/systemcalls.c
inawezekana kuona kazi iliyoelezwa unix_syscall
, ambayo ina msimbo huu:
#if CONFIG_MACF
if (__improbable(proc_syscall_filter_mask(proc) != NULL && !bitstr_test(proc_syscall_filter_mask(proc), syscode))) {
error = mac_proc_check_syscall_unix(proc, syscode);
if (error) {
goto skip_syscall;
}
}
#endif /* CONFIG_MACF */
Ambayo itakagua katika mchakato unaoitwa bitmask ikiwa syscall ya sasa inapaswa kuita mac_proc_check_syscall_unix
. Hii ni kwa sababu syscalls zinaitwa mara nyingi hivyo ni muhimu kuepuka kuita mac_proc_check_syscall_unix
kila wakati.
Kumbuka kwamba kazi proc_set_syscall_filter_mask()
, ambayo huweka bitmask syscalls katika mchakato inaitwa na Sandbox kuweka masks kwenye michakato iliyowekwa kwenye sandbox.
Syscalls za MACF zilizofichuliwa
Inawezekana kuingiliana na MACF kupitia baadhi ya syscalls zilizofafanuliwa katika security/mac.h:
/*
* Extended non-POSIX.1e interfaces that offer additional services
* available from the userland and kernel MAC frameworks.
*/
#ifdef __APPLE_API_PRIVATE
__BEGIN_DECLS
int __mac_execve(char *fname, char **argv, char **envv, mac_t _label);
int __mac_get_fd(int _fd, mac_t _label);
int __mac_get_file(const char *_path, mac_t _label);
int __mac_get_link(const char *_path, mac_t _label);
int __mac_get_pid(pid_t _pid, mac_t _label);
int __mac_get_proc(mac_t _label);
int __mac_set_fd(int _fildes, const mac_t _label);
int __mac_set_file(const char *_path, mac_t _label);
int __mac_set_link(const char *_path, mac_t _label);
int __mac_mount(const char *type, const char *path, int flags, void *data,
struct mac *label);
int __mac_get_mount(const char *path, struct mac *label);
int __mac_set_proc(const mac_t _label);
int __mac_syscall(const char *_policyname, int _call, void *_arg);
__END_DECLS
#endif /*__APPLE_API_PRIVATE*/
Marejeo
tip
Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za udukuzi kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.