Giunsa pagpanalipod ang mga proseso ug mga extension sa kernel sa macOS

Hello, Habr! Karon gusto nakong hisgutan kung giunsa nimo mapanalipdan ang mga proseso gikan sa mga pag-atake sa mga tig-atake sa macOS. Pananglitan, kini mapuslanon alang sa usa ka antivirus o backup nga sistema, labi na tungod kay ubos sa macOS adunay daghang mga paagi sa "pagpatay" sa usa ka proseso. Basaha ang bahin niini ug mga pamaagi sa pagpanalipod sa ilawom sa pagputol.

Giunsa pagpanalipod ang mga proseso ug mga extension sa kernel sa macOS

Ang klasiko nga paagi sa "pagpatay" sa usa ka proseso

Usa ka ilado nga paagi sa "pagpatay" sa usa ka proseso mao ang pagpadala sa usa ka signal sa SIGKILL sa proseso. Pinaagi sa bash mahimo nimong tawagan ang standard nga "kill -SIGKILL PID" o "pkill -9 NAME" aron patyon. Ang "pagpatay" nga sugo nahibal-an na sukad sa mga adlaw sa UNIX ug magamit dili lamang sa macOS, kondili usab sa ubang mga sistema nga sama sa UNIX.

Sama sa mga sistema nga sama sa UNIX, gitugotan ka sa macOS nga ma-intercept ang bisan unsang signal sa usa ka proseso gawas sa duha - SIGKILL ug SIGSTOP. Kini nga artikulo mag-una nga magpunting sa signal sa SIGKILL isip usa ka signal nga hinungdan sa usa ka proseso nga gipatay.

mga detalye sa macOS

Sa macOS, ang kill system call sa XNU kernel nagtawag sa psignal(SIGKILL,...) function. Atong sulayan nga tan-awon kung unsa ang ubang mga aksyon sa user sa userspace nga matawag sa psignal function. Atong wagtangon ang mga tawag sa psignal function sa internal nga mga mekanismo sa kernel (bisan tuod kini dili importante, apan ibilin nato kini alang sa laing artikulo 🙂 - pag-verify sa pirma, mga sayup sa memorya, exit/terminate handling, mga paglapas sa pagpanalipod sa file, ug uban pa.

Atong sugdan ang pagrepaso gamit ang function ug ang katugbang nga tawag sa sistema terminate_with_payload. Makita nga dugang sa klasiko nga tawag sa pagpatay, adunay usa ka alternatibo nga pamaagi nga espesipiko sa macOS operating system ug dili makita sa BSD. Ang mga prinsipyo sa operasyon sa duha ka tawag sa sistema parehas usab. Direkta sila nga mga tawag sa kernel function psignal. Timan-i usab nga sa wala pa pagpatay sa usa ka proseso, usa ka "cansignal" nga pagsusi ang gihimo - kung ang proseso makapadala usa ka signal sa lain nga proseso; ang sistema wala magtugot sa bisan unsang aplikasyon sa pagpatay sa mga proseso sa sistema, pananglitan.

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

gilusad

Ang standard nga paagi sa paghimo og mga daemon sa pagsugod sa sistema ug pagkontrol sa ilang tibuok kinabuhi gilusad. Palihug timan-i nga ang mga tinubdan alang sa daan nga bersyon sa launchctl hangtod sa macOS 10.10, gihatag ang mga pananglitan sa code alang sa mga katuyoan sa paghulagway. Ang moderno nga launchctl nagpadala ug mga signal sa paglansad pinaagi sa XPC, ang launchctl nga lohika gibalhin niini.

Atong tan-awon kung giunsa paghunong ang mga aplikasyon. Sa wala pa ipadala ang SIGTERM signal, ang aplikasyon gisulayan nga hunongon gamit ang "proc_terminate" nga tawag sa sistema.

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

Ubos sa hood, ang proc_terminate, bisan pa sa ngalan niini, makapadala dili lamang sa psignal nga adunay SIGTERM, kondili usab sa SIGKILL.

Dili Direktang Pagpatay - Limitasyon sa Kapanguhaan

Ang usa ka mas makapaikag nga kaso makita sa lain nga tawag sa sistema proseso_patakaran. Usa ka komon nga paggamit niini nga sistema nga tawag mao ang paglimite sa mga kapanguhaan sa aplikasyon, sama sa usa ka tig-indeks nga limitahan ang oras sa CPU ug mga quota sa memorya aron ang sistema dili kaayo mapahinay sa mga kalihokan sa pag-cache sa file. Kung ang usa ka aplikasyon nakaabot sa iyang limitasyon sa kapanguhaan, ingon sa makita gikan sa proc_apply_resource_actions function, usa ka signal sa SIGKILL ang ipadala sa proseso.

Bisan kung kini nga sistema sa tawag mahimo’g makapatay sa usa ka proseso, ang sistema wala magsusi sa mga katungod sa proseso nga nagtawag sa tawag sa sistema. Sa tinuod nagsusi naglungtad, apan igo na nga gamiton ang alternatibong bandila nga PROC_POLICY_ACTION_SET aron malaktawan kini nga kondisyon.

Busa, kung imong "limitahan" ang quota sa paggamit sa CPU sa aplikasyon (pananglitan, gitugotan lang ang 1 ns nga modagan), nan mahimo nimong patyon ang bisan unsang proseso sa sistema. Sa ingon, ang malware makapatay sa bisan unsang proseso sa sistema, lakip ang proseso sa antivirus. Makapainteres usab ang epekto nga mahitabo sa pagpatay sa usa ka proseso nga adunay pid 1 (launchctl) - kernel panic sa pagsulay sa pagproseso sa signal sa SIGKILL :)

Giunsa pagpanalipod ang mga proseso ug mga extension sa kernel sa macOS

Unsaon pagsulbad ang problema?

Ang labing prangka nga paagi aron mapugngan ang usa ka proseso nga mapatay mao ang pag-ilis sa function pointer sa lamesa sa tawag sa sistema. Ikasubo, kini nga pamaagi dili hinungdanon sa daghang mga hinungdan.

Una, ang simbolo nga nagkontrol sa lokasyon sa memorya sa sysent dili lamang pribado sa simbolo sa XNU kernel, apan dili makita sa mga simbolo sa kernel. Kinahanglan nimong gamiton ang heuristic nga mga pamaagi sa pagpangita, sama sa dinamikong pag-disassemble sa function ug pagpangita og pointer niini.

Ikaduha, ang istruktura sa mga entri sa lamesa nagdepende sa mga bandila diin gihugpong ang kernel. Kung ang CONFIG_REQUIRES_U32_MUNGING nga bandila gideklarar, ang gidak-on sa istruktura mausab - usa ka dugang nga field ang idugang sy_arg_munge32. Kinahanglan nga maghimo ug dugang nga pagsusi aron mahibal-an kung unsang bandila ang gihugpong sa kernel, o sa laing paagi, susihon ang mga pointer sa function batok sa mga nahibal-an.

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
                                         */
};

Maayo na lang, sa modernong mga bersyon sa macOS, ang Apple naghatag usa ka bag-ong API alang sa pagtrabaho sa mga proseso. Ang Endpoint Security API nagtugot sa mga kliyente sa pagtugot sa daghang mga hangyo sa ubang mga proseso. Sa ingon, mahimo nimong babagan ang bisan unsang signal sa mga proseso, lakip ang signal sa SIGKILL, gamit ang nahisgutan nga API.

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

Sa susama, ang usa ka MAC Policy mahimong marehistro sa kernel, nga naghatag usa ka paagi sa pagpanalipod sa signal (policy proc_check_signal), apan ang API dili opisyal nga gisuportahan.

Proteksyon sa extension sa kernel

Dugang sa pagpanalipod sa mga proseso sa sistema, ang pagpanalipod sa kernel extension mismo (kext) gikinahanglan usab. Ang macOS naghatag usa ka balangkas alang sa mga developer aron dali nga mapalambo ang mga driver sa aparato sa IOKit. Dugang sa paghatag og mga himan alang sa pagtrabaho sa mga himan, ang IOKit naghatag og mga pamaagi alang sa pag-stack sa drayber gamit ang mga higayon sa C++ nga mga klase. Ang usa ka aplikasyon sa userspace makahimo sa "pangita" sa usa ka rehistradong instance sa klase aron magtukod og kernel-userspace nga relasyon.

Aron mahibal-an ang gidaghanon sa mga higayon sa klase sa sistema, adunay gamit sa ioclasscount.

my_kext_ioservice = 1
my_kext_iouserclient = 1

Ang bisan unsang kernel extension nga gustong magparehistro sa driver stack kinahanglang magdeklarar ug klase nga makapanunod gikan sa IOService, pananglitan my_kext_ioservice niining kasoha. Ang pagkonektar sa mga aplikasyon sa user maoy hinungdan sa paghimo ug bag-ong instance sa klase nga napanunod gikan sa IOUserClient, sa pananglitan my_kext_iouserclient.

Sa pagsulay sa pagdiskarga sa usa ka drayber gikan sa sistema (kextunload command), ang virtual function nga "bool terminate(IOOptionBits options)" gitawag. Igo na ang pagbalik sa sayup sa tawag aron tapuson kung pagsulay sa pagdiskarga aron ma-disable ang kextunload.

bool Kext::terminate(IOOptionBits options)
{

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

  return super::terminate(options);
}

Ang IsUnloadAllowed nga bandila mahimong itakda sa IOUserClient kung nagkarga. Kung adunay limitasyon sa pag-download, ang command sa kextunload ibalik ang mosunod nga output:

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.

Ang parehas nga proteksyon kinahanglan buhaton alang sa IOUserClient. Ang mga higayon sa mga klase mahimong madiskarga gamit ang IOKitLib userspace function "IOCatalogueTerminate(mach_port_t, uint32_t flag, io_name_t description);". Mahimo nimong ibalik ang sayup kung tawagan ang "terminate" nga mando hangtod ang aplikasyon sa userspace "mamatay", nga mao, ang function nga "clientDied" wala gitawag.

Pagpanalipod sa File

Aron mapanalipdan ang mga file, igo na nga gamiton ang Kauth API, nga nagtugot kanimo sa pagpugong sa pag-access sa mga file. Naghatag ang Apple og mga pahibalo sa mga developer bahin sa lainlaing mga panghitabo sa sakup; alang kanamo, hinungdanon ang mga operasyon nga KAUTH_VNODE_DELETE, KAUTH_VNODE_WRITE_DATA ug KAUTH_VNODE_DELETE_CHILD. Ang pinakasayon ​​nga paagi sa pagpugong sa pag-access sa mga file kay pinaagi sa dalan - among gigamit ang “vn_getpath” API aron makuha ang agianan paingon sa file ug itandi ang path prefix. Timan-i nga aron ma-optimize ang pagbag-o sa ngalan sa mga agianan sa folder sa file, ang sistema wala magtugot sa pag-access sa matag file, apan sa folder lamang nga gibag-o sa ngalan. Kinahanglan nga itandi ang agianan sa ginikanan ug limitahan ang KAUTH_VNODE_DELETE alang niini.

Giunsa pagpanalipod ang mga proseso ug mga extension sa kernel sa macOS

Ang disbentaha sa kini nga pamaagi mahimo’g gamay nga pasundayag samtang ang gidaghanon sa mga prefix nagdugang. Aron masiguro nga ang pagtandi dili katumbas sa O(prefix*gitas-on), diin ang prefix mao ang gidaghanon sa mga prefix, ang gitas-on mao ang gitas-on sa pisi, mahimo nimong gamiton ang deterministic finite automaton (DFA) nga gitukod pinaagi sa mga prefix.

Atong tagdon ang usa ka paagi sa paghimo og DFA alang sa gihatag nga set sa prefix. Gisugdan namon ang mga cursor sa sinugdanan sa matag prefix. Kung ang tanan nga mga cursor nagpunting sa parehas nga karakter, unya dugangi ang matag cursor sa usa ka karakter ug hinumdomi nga ang gitas-on sa parehas nga linya mas dako sa usa. Kung adunay duha ka mga cursor nga adunay lainlaing mga simbolo, bahina ang mga cursor sa mga grupo sumala sa simbolo nga ilang gitudlo ug balika ang algorithm sa matag grupo.

Sa una nga kaso (ang tanan nga mga karakter sa ilawom sa mga cursor parehas), nakakuha kami usa ka estado sa DFA nga adunay usa ra nga pagbalhin sa parehas nga linya. Sa ikaduha nga kaso, nakakuha kami usa ka lamesa sa mga pagbalhin sa gidak-on nga 256 (gidaghanon sa mga karakter ug labing kadaghan nga mga grupo) hangtod sa sunod nga mga estado nga nakuha pinaagi sa recursively nga pagtawag sa function.

Atong tan-awon ang usa ka pananglitan. Para sa usa ka hugpong sa mga prefix (“/foo/bar/tmp/”, “/var/db/foo/”, “/foo/bar/aba/”, “foo/bar/aac/”) makuha nimo ang mosunod DFA. Ang numero nagpakita lamang sa mga transisyon paingon sa ubang mga estado; ang ubang mga transisyon dili mahimong kataposan.

Giunsa pagpanalipod ang mga proseso ug mga extension sa kernel sa macOS

Kung moagi sa mga estado sa DKA, mahimong adunay 3 ka kaso.

  1. Naabot na ang kataposang kahimtang - giprotektahan ang dalan, gilimitahan namo ang mga operasyon KAUTH_VNODE_DELETE, KAUTH_VNODE_WRITE_DATA ug KAUTH_VNODE_DELETE_CHILD
  2. Ang katapusan nga kahimtang wala maabot, apan ang dalan "natapos" (ang null terminator naabot) - ang dalan usa ka ginikanan, gikinahanglan nga limitahan ang KAUTH_VNODE_DELETE. Timan-i nga kung ang vnode usa ka folder, kinahanglan nimong idugang ang '/' sa katapusan, kung dili mahimo nga limitahan kini sa file nga "/foor/bar/t", nga dili husto.
  3. Ang kataposang kahimtang wala maabot, ang dalan wala matapos. Walay bisan usa sa mga prefix nga motakdo niini, wala kami nagpaila sa mga pagdili.

konklusyon

Ang katuyoan sa mga solusyon sa seguridad nga gihimo mao ang pagdugang sa lebel sa seguridad sa tiggamit ug sa iyang datos. Sa usa ka bahin, kini nga katuyoan nakab-ot pinaagi sa pag-uswag sa produkto sa software sa Acronis, nga nagsira sa mga kahuyangan diin ang operating system mismo "huyang". Sa laing bahin, dili nato pasagdan ang pagpalig-on niadtong mga aspeto sa seguridad nga mahimong mapauswag sa bahin sa OS, ilabi na kay ang pagsira sa maong mga kahuyangan makadugang sa atong kaugalingong kalig-on isip produkto. Ang pagkahuyang gitaho sa Apple Product Security Team ug naayo sa macOS 10.14.5 (https://support.apple.com/en-gb/HT210119).

Giunsa pagpanalipod ang mga proseso ug mga extension sa kernel sa macOS

Ang tanan mahimo ra kung ang imong utility opisyal nga na-install sa kernel. Sa ato pa, wala’y ingon nga mga lungag alang sa gawas ug dili gusto nga software. Bisan pa, ingon sa imong makita, bisan ang pagpanalipod sa mga lehitimong programa sama sa antivirus ug backup nga mga sistema nanginahanglan trabaho. Apan karon ang mga bag-ong produkto sa Acronis alang sa macOS adunay dugang nga proteksyon batok sa pagdiskarga gikan sa sistema.

Source: www.habr.com

Idugang sa usa ka comment