mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
242 lines
14 KiB
Markdown
242 lines
14 KiB
Markdown
# macOS MACF
|
|
|
|
{{#include ../../../banners/hacktricks-training.md}}
|
|
|
|
## Osnovne informacije
|
|
|
|
**MACF** označava **Okvir obaveznog pristupa**, što je bezbednosni sistem ugrađen u operativni sistem kako bi pomogao u zaštiti vašeg računara. Funkcioniše tako što postavlja **stroga pravila o tome ko ili šta može pristupiti određenim delovima sistema**, kao što su datoteke, aplikacije i sistemski resursi. Sprovodeći ova pravila automatski, MACF osigurava da samo ovlašćeni korisnici i procesi mogu izvršavati određene radnje, smanjujući rizik od neovlašćenog pristupa ili zlonamernih aktivnosti.
|
|
|
|
Napomena da MACF zapravo ne donosi nikakve odluke jer samo **presreće** radnje, ostavljajući odluke **modulima politike** (kernel ekstenzijama) koje poziva kao što su `AppleMobileFileIntegrity.kext`, `Quarantine.kext`, `Sandbox.kext`, `TMSafetyNet.kext` i `mcxalr.kext`.
|
|
|
|
### Tok
|
|
|
|
1. Proces izvršava syscall/mach trap
|
|
2. Relevantna funkcija se poziva unutar kernela
|
|
3. Funkcija poziva MACF
|
|
4. MACF proverava module politike koji su zatražili da se ta funkcija poveže u njihovoj politici
|
|
5. MACF poziva relevantne politike
|
|
6. Politike označavaju da li dozvoljavaju ili odbacuju radnju
|
|
|
|
> [!CAUTION]
|
|
> Apple je jedini koji može koristiti MAC Framework KPI.
|
|
|
|
### Oznake
|
|
|
|
MACF koristi **oznake** koje zatim politike koriste da provere da li treba da odobre neki pristup ili ne. Kod deklaracije strukture oznaka može se [pronaći ovde](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/security/_label.h), koja se zatim koristi unutar **`struct ucred`** u [**ovde**](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/sys/ucred.h#L86) u delu **`cr_label`**. Oznaka sadrži zastavice i broj **slotova** koji se mogu koristiti od strane **MACF politika za dodeljivanje pokazivača**. Na primer, Sanbox će se povezati sa profilom kontejnera.
|
|
|
|
## MACF politike
|
|
|
|
MACF politika definiše **pravila i uslove koji se primenjuju u određenim kernel operacijama**.
|
|
|
|
Kernel ekstenzija može konfigurisati `mac_policy_conf` strukturu i zatim je registrovati pozivajući `mac_policy_register`. Od [ovde](https://opensource.apple.com/source/xnu/xnu-2050.18.24/security/mac_policy.h.auto.html):
|
|
```c
|
|
#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 */
|
|
};
|
|
```
|
|
Lako je identifikovati kernel ekstenzije koje konfigurišu ove politike proverom poziva na `mac_policy_register`. Štaviše, proverom disasembla ekstenzije takođe je moguće pronaći korišćenu `mac_policy_conf` strukturu.
|
|
|
|
Napomena da se MACF politike mogu registrovati i deregistrovati takođe **dinamički**.
|
|
|
|
Jedno od glavnih polja `mac_policy_conf` je **`mpc_ops`**. Ovo polje specificira koje operacije politika zanima. Napomena da ih ima stotine, tako da je moguće postaviti sve na nulu, a zatim izabrati samo one koje politiku zanimaju. Od [ovde](https://opensource.apple.com/source/xnu/xnu-2050.18.24/security/mac_policy.h.auto.html):
|
|
```c
|
|
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;
|
|
[...]
|
|
```
|
|
Skoro svi hook-ovi će biti pozvani od strane MACF kada se jedna od tih operacija presretne. Međutim, **`mpo_policy_*`** hook-ovi su izuzetak jer je `mpo_hook_policy_init()` callback koji se poziva prilikom registracije (dakle, nakon `mac_policy_register()`) i `mpo_hook_policy_initbsd()` se poziva tokom kasne registracije kada je BSD podsystem pravilno inicijalizovan.
|
|
|
|
Štaviše, **`mpo_policy_syscall`** hook može biti registrovan od strane bilo kog kext-a da izloži privatni **ioctl** stil poziva **interface**. Tada će korisnički klijent moći da pozove `mac_syscall` (#381) navodeći kao parametre **ime politike** sa celobrojnim **kodom** i opcionim **argumentima**.\
|
|
Na primer, **`Sandbox.kext`** to često koristi.
|
|
|
|
Proverom **`__DATA.__const*`** kext-a moguće je identifikovati `mac_policy_ops` strukturu koja se koristi prilikom registracije politike. Moguće je pronaći jer je njen pokazivač na offset-u unutar `mpo_policy_conf` i takođe zbog broja NULL pokazivača koji će biti u toj oblasti.
|
|
|
|
Štaviše, takođe je moguće dobiti listu kext-ova koji su konfigurisali politiku dump-ovanjem iz memorije strukture **`_mac_policy_list`** koja se ažurira sa svakom registrovanom politikom.
|
|
|
|
## MACF Inicijalizacija
|
|
|
|
MACF se inicijalizuje vrlo brzo. Postavlja se u XNU-ovom `bootstrap_thread`: nakon `ipc_bootstrap` poziva na `mac_policy_init()` koji inicijalizuje `mac_policy_list`, a trenutak kasnije se poziva `mac_policy_initmach()`. Između ostalog, ova funkcija će dobiti sve Apple kext-ove sa `AppleSecurityExtension` ključem u njihovom Info.plist kao što su `ALF.kext`, `AppleMobileFileIntegrity.kext`, `Quarantine.kext`, `Sandbox.kext` i `TMSafetyNet.kext` i učitati ih.
|
|
|
|
## MACF Pozivi
|
|
|
|
Uobičajeno je pronaći pozive ka MACF definisane u kodu kao: **`#if CONFIG_MAC`** uslovni blokovi. Štaviše, unutar ovih blokova moguće je pronaći pozive na `mac_proc_check*` koji poziva MACF da **proveri dozvole** za izvršavanje određenih akcija. Takođe, format MACF poziva je: **`mac_<object>_<opType>_opName`**.
|
|
|
|
Objekat je jedan od sledećih: `bpfdesc`, `cred`, `file`, `proc`, `vnode`, `mount`, `devfs`, `ifnet`, `inpcb`, `mbuf`, `ipq`, `pipe`, `sysv[msg/msq/shm/sem]`, `posix[shm/sem]`, `socket`, `kext`.\
|
|
`opType` je obično check koji će se koristiti za dozvoljavanje ili odbijanje akcije. Međutim, takođe je moguće pronaći `notify`, koji će omogućiti kext-u da reaguje na datu akciju.
|
|
|
|
Možete pronaći primer u [https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/kern/kern_mman.c#L621](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/kern/kern_mman.c#L621):
|
|
|
|
<pre class="language-c"><code class="lang-c">int
|
|
mmap(proc_t p, struct mmap_args *uap, user_addr_t *retval)
|
|
{
|
|
[...]
|
|
#if CONFIG_MACF
|
|
<strong> error = mac_file_check_mmap(vfs_context_ucred(ctx),
|
|
</strong> fp->fp_glob, prot, flags, file_pos + pageoff,
|
|
&maxprot);
|
|
if (error) {
|
|
(void)vnode_put(vp);
|
|
goto bad;
|
|
}
|
|
#endif /* MAC */
|
|
[...]
|
|
</code></pre>
|
|
|
|
Zatim, moguće je pronaći kod `mac_file_check_mmap` u [https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/security/mac_file.c#L174](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/security/mac_file.c#L174)
|
|
```c
|
|
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;
|
|
}
|
|
```
|
|
Koji poziva `MAC_CHECK` makro, čiji se kod može naći u [https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/security/mac_internal.h#L261](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/security/mac_internal.h#L261)
|
|
```c
|
|
/*
|
|
* 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)
|
|
```
|
|
Koji će proći kroz sve registrovane mac politike pozivajući njihove funkcije i čuvajući izlaz unutar promenljive error, koja će biti prepisiva samo od strane `mac_error_select` pomoću kodova uspeha, tako da ako bilo koja provera ne uspe, cela provera će propasti i akcija neće biti dozvoljena.
|
|
|
|
> [!TIP]
|
|
> Međutim, zapamtite da se ne koriste svi MACF pozivi samo za odbijanje akcija. Na primer, `mac_priv_grant` poziva makro [**MAC_GRANT**](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/security/mac_internal.h#L274), koji će odobriti traženu privilegiju ako bilo koja politika odgovori sa 0:
|
|
>
|
|
> ```c
|
|
> /*
|
|
> * MAC_GRANT vrši određenu proveru prolazeći kroz listu
|
|
> * modula politika i proveravajući sa svakim kako se oseća u vezi
|
|
> * sa zahtevom. Za razliku od MAC_CHECK, odobrava ako bilo koja politika vrati '0',
|
|
> * a inače vraća EPERM. Napomena: vraća svoju vrednost putem
|
|
> * 'error' u opsegu pozivaoca.
|
|
> */
|
|
> #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
|
|
|
|
Ovi pozivi su namenjeni za proveru i pružanje (desetina) **privilegija** definisanih u [**bsd/sys/priv.h**](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/sys/priv.h).\
|
|
Neki kernel kod bi pozvao `priv_check_cred()` iz [**bsd/kern/kern_priv.c**](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/kern/kern_priv.c) sa KAuth kredencijalima procesa i jednim od kodova privilegija koji će pozvati `mac_priv_check` da vidi da li neka politika **odbija** davanje privilegije, a zatim poziva `mac_priv_grant` da vidi da li neka politika odobrava `privilegiju`.
|
|
|
|
### proc_check_syscall_unix
|
|
|
|
Ova kuka omogućava presretanje svih sistemskih poziva. U `bsd/dev/[i386|arm]/systemcalls.c` moguće je videti deklarisanu funkciju [`unix_syscall`](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/dev/arm/systemcalls.c#L160C1-L167C25), koja sadrži ovaj kod:
|
|
```c
|
|
#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 */
|
|
```
|
|
Koji će proveriti u pozivnom procesu **bitmasku** da li trenutni syscall treba da pozove `mac_proc_check_syscall_unix`. To je zato što se syscalls pozivaju tako često da je zanimljivo izbeći pozivanje `mac_proc_check_syscall_unix` svaki put.
|
|
|
|
Napomena da funkcija `proc_set_syscall_filter_mask()`, koja postavlja bitmasku syscalls u procesu, se poziva od strane Sandbox-a da postavi maske na sandboxed procesima.
|
|
|
|
## Izloženi MACF syscalls
|
|
|
|
Moguće je interagovati sa MACF kroz neke syscalls definisane u [security/mac.h](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/security/mac.h#L151):
|
|
```c
|
|
/*
|
|
* 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*/
|
|
```
|
|
## Reference
|
|
|
|
- [**\*OS Internals Volume III**](https://newosxbook.com/home.html)
|
|
|
|
{{#include ../../../banners/hacktricks-training.md}}
|