Nola babestu prozesuak eta nukleoaren luzapenak macOS-en

Kaixo, Habr! Gaur macOS-en erasotzaileen erasoetatik prozesuak nola babes ditzakezun hitz egin nahiko nuke. Esate baterako, hau erabilgarria da birusen aurkako edo babeskopia sistema baterako, batez ere macOS-en arabera prozesu bat "hiltzeko" hainbat modu daudelako. Irakurri honi buruz eta babes-metodoak ebaki azpian.

Nola babestu prozesuak eta nukleoaren luzapenak macOS-en

Prozesu bat "hiltzeko" modu klasikoa

Prozesu bat "hiltzeko" modu ezagun bat prozesura SIGKILL seinale bat bidaltzea da. Bash-en bidez "kill -SIGKILL PID" edo "pkill -9 NAME" estandarra dei dezakezu hiltzeko. "Hil" komandoa UNIXen garaitik ezagutzen da eta macOS-en ez ezik, UNIX antzeko beste sistemetan ere eskuragarri dago.

UNIX antzeko sistemetan bezala, macOSek prozesu baterako edozein seinale atzemateko aukera ematen dizu, bi izan ezik: SIGKILL eta SIGSTOP. Artikulu hau SIGKILL seinalea izango da nagusiki prozesu bat hiltzea eragiten duen seinale gisa.

macOS berezitasunak

MacOS-en, XNU nukleoan hiltzeko sistema deiak psignal(SIGKILL,...) funtzioa deitzen du. Saia gaitezen ikusten psignal funtzioak erabiltzaile-espazioko beste erabiltzaile-ekintzei dei diezaiekeen. Ezabatu ditzagun psignal funtziorako deiak nukleoaren barne-mekanismoetan (nahiz eta hutsalak izan daitezkeen, beste artikulu baterako utziko ditugu πŸ™‚ - sinadura egiaztatzea, memoria-akatsak, irteera/amaiera kudeatzea, fitxategien babes-urraketak, etab. .

Hasi gaitezen berrikuspena funtzioarekin eta dagokion sistema-deiarekin amaitu_kargarekin. Ikusten denez, hiltze-dei klasikoaz gain, macOS sistema eragileari berariazkoa den eta BSD-n aurkitzen ez den ikuspegi alternatibo bat dagoela ikus daiteke. Bi sistema-deien funtzionamendu-printzipioak ere antzekoak dira. Nukleoko psignal funtziorako deiak zuzenak dira. Kontuan izan, halaber, prozesu bat hil aurretik, "cansignal" egiaztapena egiten dela: prozesuak beste prozesu bati seinale bat bidal dezakeen ala ez; sistemak ez du onartzen inolako aplikaziorik sistemaren prozesuak hiltzen, adibidez.

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);
	}
...
}

martxan jarri

Sistema abiaraztean deabruak sortzeko eta haien bizitza kontrolatzeko modu estandarra abiarazi da. Kontuan izan iturriak launchctl-ren bertsio zaharrekoak direla macOS 10.10era arte, kode-adibideak helburu ilustratiboetarako ematen direla. Launkctl modernoak launchd seinaleak bidaltzen ditu XPC bidez, launchctl logika bertara eraman da.

Ikus dezagun aplikazioak nola gelditzen diren. SIGTERM seinalea bidali aurretik, aplikazioa gelditzen saiatzen da "proc_terminate" sistema-deia erabiliz.

<launchctl src/core.c>
...
	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));
		} 
...
<>

Kanpaiaren azpian, proc_terminate-k, izena duen arren, SIGTERM-ekin psignal ez ezik, SIGKILL ere bidal dezake.

Zeharkako hilketa - Baliabideen muga

Kasu interesgarriagoa beste sistema-dei batean ikus daiteke prozesua_politika. Sistema-dei honen erabilera arrunta aplikazioen baliabideak mugatzea da, esate baterako, indexagailu batek CPU denbora eta memoria-kuotak mugatzea, fitxategien cache-jardueren ondorioz sistema nabarmen moteldu ez dadin. Aplikazio bat baliabideen mugara iritsi bada, proc_apply_resource_actions funtzioan ikus daitekeen bezala, SIGKILL seinale bat bidaltzen da prozesura.

Sistema-dei honek prozesu bat hil dezakeen arren, sistemak ez zituen behar bezala egiaztatu sistema-deia deitzen zuen prozesuaren eskubideak. Egia esan, egiaztatzen existitu zen, baina nahikoa da PROC_POLICY_ACTION_SET bandera alternatiboa erabiltzea baldintza hau saihesteko.

Hori dela eta, aplikazioaren CPU erabilera-kuota "mugatzen" baduzu (adibidez, 1 ns bakarrik exekutatzen utzi), orduan sistemako edozein prozesu akabatu dezakezu. Horrela, malwareak sistemako edozein prozesu hil dezake, birusen aurkako prozesua barne. Interesgarria da prozesu bat pid 1 (launchctl) hiltzean gertatzen den efektua ere - nukleoaren izua SIGKILL seinalea prozesatzen saiatzean :)

Nola babestu prozesuak eta nukleoaren luzapenak macOS-en

Nola konpondu arazoa?

Prozesu bat hiltzea ekiditeko modurik errazena sistema-deien taulan funtzio erakuslea ordezkatzea da. Zoritxarrez, metodo hau ez da hutsala arrazoi askorengatik.

Lehenik eta behin, sysent-en memoria-kokapena kontrolatzen duen ikurra ez da soilik XNU nukleoaren sinboloaren pribatua, baina ezin da nukleoaren sinboloetan aurkitu. Bilaketa-metodo heuristikoak erabili beharko dituzu, hala nola funtzioa dinamikoki desmuntatu eta bertan erakusle bat bilatzea.

Bigarrenik, taulako sarreren egitura nukleoa konpilatu den banderen araberakoa da. CONFIG_REQUIRES_U32_MUNGING bandera deklaratzen bada, egituraren tamaina aldatuko da - eremu gehigarri bat gehituko da sy_arg_munge32. Beharrezkoa da egiaztapen gehigarri bat egitea nukleoa zein banderarekin konpilatu den zehazteko, edo, bestela, funtzio-erakusleak ezagunak direnekin egiaztatu.

struct sysent {         /* system call table */
        sy_call_t       *sy_call;       /* implementing function */
#if CONFIG_REQUIRES_U32_MUNGING || (__arm__ && (__BIGGEST_ALIGNMENT__ > 4))
        sy_munge_t      *sy_arg_munge32; /* system call arguments munger for 32-bit process */
#endif
        int32_t         sy_return_type; /* system call return types */
        int16_t         sy_narg;        /* number of args */
        uint16_t        sy_arg_bytes;   /* Total size of arguments in bytes for
                                         * 32-bit system calls
                                         */
};

Zorionez, macOS-en bertsio modernoetan, Apple-k API berri bat eskaintzen du prozesuekin lan egiteko. Endpoint Security API-k bezeroei eskaera asko baimentzeko aukera ematen die beste prozesu batzuetarako. Horrela, prozesuetarako edozein seinale blokea dezakezu, SIGKILL seinalea barne, goian aipatutako APIa erabiliz.

#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;
}

Era berean, nukleoan MAC politika bat erregistratu daiteke, seinaleak babesteko metodo bat eskaintzen duena (policy proc_check_signal), baina APIa ez da ofizialki onartzen.

Kernelaren luzapenaren babesa

Sistemako prozesuak babesteaz gain, nukleoaren luzapena bera (kext) babestea ere beharrezkoa da. macOS-ek garatzaileei IOKit gailu kontrolatzaileak erraz garatzeko esparru bat eskaintzen die. Gailuekin lan egiteko tresnak eskaintzeaz gain, IOKit-ek C++ klaseen instantzien bidez kontrolatzaileak pilatzeko metodoak eskaintzen ditu. Erabiltzaile-espazioko aplikazio batek klaseko instantzia erregistratu bat "aurkitu" ahal izango du nukleo-erabiltzaile-espazio erlazioa ezartzeko.

Sistemako klase-instantzia kopurua detektatzeko, ioclasscount erabilgarritasuna dago.

my_kext_ioservice = 1
my_kext_iouserclient = 1

Gidari pilan erregistratu nahi duen nukleoaren luzapenak IOService-tik heredatzen den klase bat deklaratu behar du, kasu honetan my_kext_ioservice adibidez. Erabiltzaile-aplikazioak konektatzeak IOUserClient-etik heredatzen den klasearen instantzia berri bat sortzea eragiten du, my_kext_iouserclient adibidean.

Sistematik kontrolatzaile bat deskargatzen saiatzean (kextunload komandoa), "bool terminate(IOOptionBits options)" funtzio birtuala deitzen da. Nahikoa da deskargatzen saiatzean amaitzeko deian false itzultzea kextunload desgaitzeko.

bool Kext::terminate(IOOptionBits options)
{

  if (!IsUnloadAllowed)
  {
    // Unload is not allowed, returning false
    return false;
  }

  return super::terminate(options);
}

IsUnloadAllowed bandera IOUserClient-ek ezar dezake kargatzean. Deskarga muga bat dagoenean, kextunload komandoak irteera hau itzuliko du:

admin@admins-Mac drivermanager % sudo kextunload ./test.kext
Password:
(kernel) Can't remove kext my.kext.test; services failed to terminate - 0xe00002c7.
Failed to unload my.kext.test - (iokit/common) unsupported function.

IOUserClient-en antzeko babesa egin behar da. Klaseen instantziak deskargatu daitezke IOKitLib erabiltzaile-espazio funtzioa erabiliz "IOCatalogueTerminate(mach_port_t, uint32_t flag, io_name_t description);". False itzul dezakezu "bukatu" komandoa deitzean erabiltzaile-espazioko aplikazioa "hil" arte, hau da, "clientDied" funtzioa ez den deitzen.

Fitxategien babesa

Fitxategiak babesteko, nahikoa da Kauth APIa erabiltzea, fitxategietarako sarbidea mugatzeko aukera ematen duena. Apple-k garatzaileei esparruko hainbat gertaeren inguruko jakinarazpenak eskaintzen dizkie; guretzat, KAUTH_VNODE_DELETE, KAUTH_VNODE_WRITE_DATA eta KAUTH_VNODE_DELETE_CHILD eragiketak garrantzitsuak dira. Fitxategietarako sarbidea mugatzeko modurik errazena bidearen bidez da - "vn_getpath" APIa erabiltzen dugu fitxategiaren bidea lortzeko eta bide-aurrizkia alderatzeko. Kontuan izan fitxategi-karpeten bideen izena aldatzea optimizatzeko, sistemak ez duela baimentzen fitxategi bakoitzerako sarbidea, baizik eta izena aldatu den karpeta bera bakarrik. Beharrezkoa da bide nagusia alderatzea eta horretarako KAUTH_VNODE_DELETE mugatzea.

Nola babestu prozesuak eta nukleoaren luzapenak macOS-en

Ikuspegi honen desabantaila errendimendu baxua izan daiteke aurrizki kopurua handitzen den heinean. Konparazioa O (aurrizkia*luzera) berdina ez dela ziurtatzeko, non aurrizkia aurrizki kopurua den, luzera katearen luzera den, aurrizkiek eraikitako automata finitu deterministikoa (DFA) erabil dezakezu.

Demagun aurrizki multzo jakin baterako DFA bat eraikitzeko metodo bat. Kurtsoreak aurrizki bakoitzaren hasieran hasieratzen ditugu. Kurtsore guztiek karaktere bera adierazten badute, handitu kurtsore bakoitza karaktere bat eta gogoratu lerro beraren luzera bat handiagoa dela. Ikur ezberdineko bi kurtsore badaude, zatitu kurtsoreak taldetan seinalatzen duten sinboloaren arabera eta errepikatu algoritmoa talde bakoitzeko.

Lehenengo kasuan (kurtsoreen azpiko karaktere guztiak berdinak dira), lerro berean trantsizio bakarra duen DFA egoera lortuko dugu. Bigarren kasuan, 256 tamainako trantsizioen taula bat lortuko dugu (karaktere-kopurua eta gehieneko talde-kopurua) funtzioari errekurtsiboki deituz lortutako ondorengo egoeretarako.

Ikus dezagun adibide bat. Aurrizki multzo baterako (β€œ/foo/bar/tmp/”, β€œ/var/db/foo/”, β€œ/foo/bar/aba/”, β€œfoo/bar/aac/”) honako hau lor dezakezu DFA. Irudiak beste egoera batzuetara daramaten trantsizioak bakarrik erakusten ditu; beste trantsizioak ez dira behin betikoak izango.

Nola babestu prozesuak eta nukleoaren luzapenak macOS-en

DKA estatuetatik igarotzean, 3 kasu egon daitezke.

  1. Azken egoerara iritsi da - bidea babestuta dago, KAUTH_VNODE_DELETE, KAUTH_VNODE_WRITE_DATA eta KAUTH_VNODE_DELETE_CHILD eragiketak mugatzen ditugu.
  2. Azken egoerara ez zen iritsi, baina "bukatu" bidea (bukaera nulura iritsi zen) - bidea gurasoa da, KAUTH_VNODE_DELETE mugatu behar da. Kontuan izan vnode karpeta bat bada, amaieran '/' gehitu behar duzula, bestela "/foor/bar/t" fitxategira mugatu daitekeela, okerra dena.
  3. Azken egoerara ez zen iritsi, bidea ez zen amaitu. Aurrizkietako bat ere ez dator bat honekin, ez dugu murrizketarik jartzen.

Ondorioa

Garatzen ari diren segurtasun irtenbideen helburua erabiltzailearen eta bere datuen segurtasun maila handitzea da. Alde batetik, helburu hori Acronis software produktuaren garapenarekin lortzen da, sistema eragilea bera "ahul" dagoen ahultasun horiek ixten dituena. Bestalde, ez dugu alde batera utzi behar OSaren aldetik hobetu daitezkeen segurtasun-alderdi horiek indartzea, batez ere ahultasun horiek ixteak gure produktu gisa egonkortasuna areagotzen duelako. Ahultasuna Apple Produktuen Segurtasun Taldeari jakinarazi zitzaion eta macOS 10.14.5-en konpondu da (https://support.apple.com/en-gb/HT210119).

Nola babestu prozesuak eta nukleoaren luzapenak macOS-en

Hau guztia zure utilitatea nukleoan ofizialki instalatuta badago soilik egin daiteke. Hau da, ez dago halako zirrikiturik kanpoko eta nahi gabeko softwarerako. Hala ere, ikus dezakezun bezala, programa legitimoak babesteak ere, hala nola birusen aurkako eta babeskopia sistemak, lana eskatzen du. Baina orain macOSerako Acronis produktu berriek babes gehigarria izango dute sistematik deskargatzeko.

Iturria: www.habr.com

Gehitu iruzkin berria