Tere, Habr! TĂ€na sooviksin rÀÀkida sellest, kuidas saab kaitsta protsesse kurjategijate sissetungi eest macOS-is. NĂ€iteks on see kasulik viirusetĂ”rje vĂ”i backup-sĂŒsteemi jaoks, eriti arvestades, et macOS-is on mitmeid viise protsessi "tappa". Loe edasi selle ja kaitsemeetodite kohta allpool.
Klassikaline viis protsessi "tapmiseks"
KĂ”igile tuntud viis protsessi "tapmiseks" on saata SIGKILL signaal protsessile. Bash'is saab tavaliste kĂ€skudega "kill -SIGKILL PID" vĂ”i "pkill -9 NAME" protsessi tappa. KĂ€sk "kill" on tuntud juba UNIXi aegadest ja on saadaval mitte ainult macOS-is, vaid ka teistes UNIX-i sarnastes sĂŒsteemides.
Nagu UNIX-i sarnastes sĂŒsteemides, vĂ”imaldab macOS ka protsessile saata mis tahes signaale, vĂ€lja arvatud kaks â SIGKILL ja SIGSTOP. Selles artiklis kĂ€sitleme esmajoones SIGKILL signaali, mis on signaal, mis pĂ”hjustab protsessi tapmise.
macOS-i omadused
macOS-is kutsub sĂŒsteemikĂ”ne kill XNU tuumas esile funktsiooni psignal(SIGKILL,âŠ). Proovime vaadata, milliseid muid kasutaja toiminguid kasutajaruumis vĂ”ib psignal funktsiooni esile kutsuda. JĂ€tame kĂ”rvale psignali funktsiooni kutsed tuuma sisemiste mehhanismide tĂ”ttu (kuigi need vĂ”ivad olla mittetriviaalsed, kuid jĂ€tame need teise artikli jaoks đ â allkirja kontroll, mĂ€lu vead, exit/terminate töötlemine, failikaitse rikkumise jne.
Alustame ĂŒlevaadet funktsiooni ja vastava sĂŒsteemikĂ”ne kohta . On nĂ€ha, et lisaks klassikalisele kill-kutsumisele on olemas alternatiivne lĂ€henemine, mis on spetsiifiline macOS operatsioonisĂŒsteemile ja mida ei leidu BSD-s. MĂ”lema sĂŒsteemikĂ”ne tööpĂ”himĂ”tted on samuti sarnased. Need on otsesed kĂ”ned tuuma funktsioonile psignal. JĂ€tame tĂ€helepanuta, et enne protsessi tapmist toimub kontroll "cansignal" â kas protsess vĂ”ib saata signaali teisele protsessile, sĂŒsteem ei luba ĂŒkskĂ”ik millisel rakendusel tappa sĂŒsteemiprotsesse nĂ€iteks.
static int
terminate_with_payload_internal(struct proc *cur_proc, int target_pid, uint32_t reason_namespace,
uint64_t reason_code, user_addr_t payload, uint32_t payload_size,
user_addr_t reason_string, uint64_t reason_flags)
{
...
target_proc = proc_find(target_pid);
...
if (!cansignal(cur_proc, cur_cred, target_proc, SIGKILL)) {
proc_rele(target_proc);
return EPERM;
}
...
if (target_pid == cur_proc->p_pid) {
* psignal_thread_with_reason() will pend a SIGKILL on the specified thread or
* return if the thread and/or task are already terminating. Either way, the
* current thread won't return to userspace.
*
psignal_thread_with_reason(target_proc, current_thread(), SIGKILL, signal_reason);
} else {
psignal_with_reason(target_proc, SIGKILL, signal_reason);
}
...
}
launchd
Tavaliselt kasutatakse sĂŒsteemi kĂ€ivitamiseks ja deemonite eluea kontrollimiseks launchd. Tahan mĂ€rkida, et alltoodud originaalid viitavad vanale versioonile launchctl enne macOS 10.10, koodinĂ€ited on esitatud illustreerimiseks. Kaasaegne launchctl saadab signaalid launchd-le lĂ€bi XPC, launchctl-i loogika on sinna ĂŒle viidud.
Vaadakem, kuidas tĂ€pselt rakendusi peatada. Enne SIGTERM signaali saatmist proovib rakendusi peatada sĂŒsteemi kĂ”ne âproc_terminateâ kaudu.
...
error = proc_terminate(j->p, &sig);
if (error) {
job_log(j, LOG_ERR | LOG_CONSOLE, "Could not terminate job: %d: %s", error, strerror(error));
job_log(j, LOG_NOTICE | LOG_CONSOLE, "Using fallback option to terminate job...");
error = kill2(j->p, SIGTERM);
if (error) {
job_log(j, LOG_ERR, "Could not signal job: %d: %s", error, strerror(error));
}
...
Kuigi proc_terminate vÔib oma nime jÀrgi saata mitte ainult psignali koos SIGTERM'iga, vaid ka SIGKILL'iga.
Kaudne tapmine â ressursipiirangud
Huvitavam juhtum vĂ”ib ilmneda teises sĂŒsteemi kĂ”nes . Tavaotstarbel kasutatakse seda sĂŒsteemi kĂ”net rakenduste ressursipiirangute jaoks, nĂ€iteks indekseerijale seatakse piirang protsessori aja ja mĂ€lu kvoodi peale, et sĂŒsteem ei aeglustuks oluliselt failide vahemĂ€lu toimingute tĂ”ttu. Kui rakendus saavutab ressursipiirangu, nagu vĂ”ib nĂ€ha funktsioonis proc_apply_resource_actions, saadetakse protsessile signaal SIGKILL.
Kuigi see sĂŒsteemi kĂ”ne vĂ”ib potentsiaalselt tappa protsessi, ei kontrollinud sĂŒsteem piisavalt selle protsessi Ă”igusi, kes sĂŒsteemi kĂ”net tegi. Tegelikult toimus kontroll , kuid piisab alternatiivse lipu PROC_POLICY_ACTION_SET kasutamisest selle tingimuse vĂ€ltimiseks.
Siit, kui "piirata" CPU kasutamise kvooti rakendusele (nĂ€iteks lubada töötada ainult ĂŒhel ns-l), siis saab igasĂŒsteemi protsessi tappa. Nii saab pahavara tappa igasuguseid protsesse sĂŒsteemis, sealhulgas ka viirusevastase protsessi. Samuti on huvitav efekt, mis tekib protsessi tapmisel pid 1 (launchctl) â kernel panic, kui proovida töödelda SIGKILL signaali đ

Kuidas probleemi lahendada?
KĂ”ige otsesem viis protsessi tapmise keelamiseks on sĂŒsteem kutsumise tabelis funktsiooni osutaja asendamine. Kahjuks on see meetod paljuski mittetavaline.
Esiteks, sĂŒmbol, mis vastutab sysent'i asukoha eest mĂ€lus, on mitte ainult XNU tuuma privaatne sĂŒmbol, vaid seda ei saa leida ka tuuma sĂŒmbolitest. Peame kasutama heuristikameetodeid, nĂ€iteks funktsiooni dĂŒnaamilist disassembliimist ja osutaja otsimist selles.
Teiseks, tabeli kirje struktuur sĂ”ltub lippudest, millega tuuma on kokku pandud. Kui on kuulutatud lipp CONFIG_REQUIRES_U32_MUNGING, siis struktuuri suurus muutub â lisatakse tĂ€iendav vĂ€li. . Peame tegema tĂ€iendava kontrolli selle ĂŒle, millise lipuga tuum on kompileeritud, nĂ€iteks kontrollida osutajaid funktsioonidele tuntud osutajate vahel.
struct sysent {
/* sĂŒsteemikutsumise tabel */
sy_call_t *sy_call; /* teostava funktsiooni osutaja */
#if CONFIG_REQUIRES_U32_MUNGING || (__arm__ && (__BIGGEST_ALIGNMENT__ > 4))
sy_munge_t *sy_arg_munge32; /* sĂŒsteemikutsumise argumendi muudatus 32-bitise protsessi jaoks */
#endif
int32_t sy_return_type; /* sĂŒsteemikutsumise tagastusliigid */
int16_t sy_narg; /* argumendide arv */
uint16_t sy_arg_bytes; /* Argumendide kogusuurus baitidena 32-bitistes sĂŒsteemikutsumistes */
};
Ănneks pakub Apple kaasaegsetes macOS'i versioonides uut API-d protsesside haldamiseks. Endpoint Security API vĂ”imaldab klientidel autoriseerida mitmeid pĂ€ringuid teistele protsessidele. Nii on vĂ”imalik blokeerida kĂ”ik signaalid protsessidele, sealhulgas SIGKILL signaali ĂŒlaltoodud API abil.
#include <bsm/libbsm.h>
#include <EndpointSecurity/EndpointSecurity.h>
#include <unistd.h>
int main(int argc, const char * argv[]) {
es_client_t* cli = nullptr;
{
auto res = es_new_client(&cli, ^(es_client_t * client, const es_message_t * message) {
switch (message->event_type) {
case ES_EVENT_TYPE_AUTH_SIGNAL:
{
auto& msg = message->event.signal;
auto target = msg.target;
auto& token = target->audit_token;
auto pid = audit_token_to_pid(token);
printf("signal '%d' sent to pid '%d'n", msg.sig, pid);
es_respond_auth_result(client, message, pid == getpid() ? ES_AUTH_RESULT_DENY : ES_AUTH_RESULT_ALLOW, false);
}
break;
default:
break;
}
});
}
{
es_event_type_t evs[] = { ES_EVENT_TYPE_AUTH_SIGNAL };
es_subscribe(cli, evs, sizeof(evs) / sizeof(*evs));
}
printf("%dn", getpid());
sleep(60); // could be replaced with other waiting primitive
es_unsubscribe_all(cli);
es_delete_client(cli);
return 0;
}
Sarnaselt on tuumas vÔimalik registreerida MAC Policy, mis pakub meetodi signaalide kaitsmiseks (policy proc_check_signal), kuid API-d ei toetata ametlikult.
Tuuma laiendi kaitse
Lisaks sĂŒsteemi protsesside kaitsmisele on vajalik ka tuumalaienemise (kext) enda kaitse. macOS pakub arendajatele IOKit seadme draiverite mugavaks arendamiseks raamistikku. IOKit mitte ainult ei paku vahendeid seadmete haldamiseks, vaid tagab ka draiverite virnastamise meetodid C++ klasside eksemplaride abil. Userspace'i rakendus suudab "leida" registreeritud klassi eksemplari, et luua side kernel-user space'iga.
Klasside eksemplaride arvu leidmiseks sĂŒsteemis on saadaval utiliit ioclasscount.
my_kext_ioservice = 1
my_kext_iouserclient = 1
Iga tuumalaienemine, mis soovib registreerida end draiverite virnas, peab kuulutama klassi, mis on pĂ€randatud IOService'ist, nĂ€iteks my_kext_ioservice antud juhul. Kohandatud rakenduste ĂŒhendamine kutsub esile uue klassi eksemplari loomise, mis on pĂ€randatud IOUserClient'ist, nĂ€ites my_kext_iouserclient.
Draiveri sĂŒsteemist vĂ€ljakandmise katse (kĂ€sk kextunload) kutsub esile virtuaalse funktsiooni "bool terminate(IOOptionBits options)". Piisab, kui tagastada false terminate-funktsiooni kutsumise kaudu, et keelata kextunload.
bool Kext::terminate(IOOptionBits options)
{
if (!IsUnloadAllowed)
{
// VĂ€lja laadimine ei ole lubatud, tagastame false
return false;
}
return super::terminate(options);
}
IsUnloadAllowed lipp vÔib olla seadistatud IOUserClient'i poolt laadimise ajal. Kui laadimine on piiratud, tagastab kÀsk kextunload jÀrgmise vÀljundi:
admin@admins-Mac drivermanager % sudo kextunload ./test.kext
Parool:
(kernel) Ei saa eemaldada kext my.kext.test; teenused ei suutnud lÔpetada - 0xe00002c7.
EbaÔnnestus my.kext.test vÀljaloadimine - (iokit/common) toetamata funktsioon.
Sarnane kaitse tuleb teostada ka IOUserClient'i jaoks. Klasside eksemplaride vÀljaladimine on vÔimalik userspace'i funktsiooni IOKitLib abil "IOCatalogueTerminate(mach_port_t, uint32_t flag, io_name_t description);". VÔib tagastada false kÀskluse "terminate" kutsumise ajal, kuni userspace'i rakendus ei "sure", st kuni ei kutsuta funktsiooni "clientDied".
Failide kaitse
Failide kaitsmiseks piisab Kauth API kasutamisest, mis vĂ”imaldab piirata failidele juurdepÀÀsu. Apple annab arendajatele teateid erinevate sĂŒndmuste kohta ulatuses, mille jaoks on meie jaoks olulised toimingud KAUTH_VNODE_DELETE, KAUTH_VNODE_WRITE_DATA ja KAUTH_VNODE_DELETE_CHILD. Failidele juurdepÀÀsu piiramine on kĂ”ige lihtsam tee kaudu â kasutame API-d âvn_getpathâ faili tee saamiseks ja vĂ”rdsustame tee prefiksit. Tuleb mĂ€rkida, et kaustade ja failide nimede muutmise optimeerimise eesmĂ€rgil ei autoriseeri sĂŒsteem juurdepÀÀsu igale failile, vaid ainult kaustale, mida muudetakse. On vajalik vĂ”rrelda vanema tee ja piirata KAUTH_VNODE_DELETE selle jaoks.

Selle lĂ€henemise puuduseks vĂ”ib olla madal jĂ”udlus, kui prefiksite arv suureneb. Selleks, et vĂ”rreldud ei oleks O(prefix*length), kus prefix â prefiksite arv, length â stringi pikkus, saab kasutada mÀÀratletud lĂ”ppautomaat (DKA), mis on ehitatud prefiksite pĂ”hjal.
Vaatleme DKA ehitamise viisi antud prefiksite kogumile. Algatame kursoreid iga prefiksi alguses. Kui kĂ”ik kursored osutavad samale sĂŒmbolile, siis tĂ”stame iga kursori ĂŒhe sĂŒmboli vĂ”rra ja mĂ€letame, et sama pikkuse rida on suurem ĂŒhesed. Kui on kaks kursorit, mille all olevad sĂŒmbolid erinevad, jagame kursoreid gruppideks sĂŒmboli jĂ€rgi, millele nad osutavad, ja kordame algoritmi iga grupi jaoks.
Esimesel juhul (kui kĂ”ik sĂŒmbolid kursoreid all on samad) saame DKA oleku, millel on ainult ĂŒks ĂŒleminek sama pika rea juurde. Teisel juhul saame ĂŒleminekute tabeli, mille suurus on 256 (sĂŒmbolite arv ja maksimaalne gruppide arv) jĂ€rgmistele olekutele, mis saadakse funktsiooni rekursiivsel kutsel.
Vaatleme nĂ€idet. Antud prefiksite kogumi (â/foo/bar/tmp/â, â/var/db/foo/â, â/foo/bar/aba/â, âfoo/bar/aac/â) korral saab DKA-d. Joonisel on esitatud ainult ĂŒleminekud, mis viivad teistesse olekutesse, teised ĂŒleminekud ei ole lĂ”plikud.

DKA olekute lÀbimise kÀigus vÔib esineda 3 juhtumit.
- Oleme jĂ”udnud lĂ”ppolekusse â tee on kaitstud, piirame toimingute KAUTH_VNODE_DELETE, KAUTH_VNODE_WRITE_DATA ja KAUTH_VNODE_DELETE_CHILD teostamist.
- LĂ”ppseisundit ei saavutatud, kuid tee "lĂ”ppes" (null-terminaator saavutati) â tee on vanem, KAUTH_VNODE_DELETE tuleb piirata. Oluline on mĂ€rkida, et kui vnode on kaust, tuleb lĂ”ppu lisada â/â, sest vastasel juhul vĂ”ib piirang kehtida failile â/foor/bar/tâ, mis ei ole Ă”ige.
- LĂ”ppseisundit ei saavutatud, tee ei lĂ”petanud. Ăkski eelnevatest ei vasta antud, piiranguid ei kehtestata.
KokkuvÔte
Arendatavate turvaratsete eesmĂ€rk on tĂ”sta kasutaja ja tema andmete turvalisuse taset. Ăhelt poolt saavutatakse see eesmĂ€rk Acronis tarkvara arendamisega, mis katab need haavatavused, kus operatsioonisĂŒsteem ise on ânĂ”rkâ. Teiselt poolt ei tohi alahinnata ka OS kĂŒlje turvaelementide tugevdamist, kuna selliste haavatavuste likvideerimine suurendab meie toote vastupidavust. Haavatavus teavitati Apple'i toote turvameeskonnale ja see parandati macOS 10.14.5 versioonis (https://support.apple.com/en-gb/HT210119).

Seda kĂ”ike saab teha ainult siis, kui teie tööriist on ametlikult installitud sĂŒsteemi. Ehkki vĂ€listel ja soovimatutel tarkvaradel ei ole selliseid tagavee tee. Kuidas aga nĂ€ha, isegi Ă”igustatud programmide, nagu viirusetĂ”rje ja varundussĂŒsteemide kaitsmiseks peab vaeva nĂ€gema. Kuid nĂŒĂŒd on Acronis uued tooted macOS-i jaoks varustatud tĂ€iendava kaitsega sĂŒsteemist laadimise eest.
Allikas: habr.com
