Kumaha ngajaga prosés sareng ekstensi kernel dina macOS

Halo, Habr! Dinten ieu kuring hoyong ngobrol ngeunaan kumaha anjeun tiasa ngajaga prosés tina serangan ku panyerang dina macOS. Salaku conto, ieu mangpaat pikeun antipirus atanapi sistem cadangan, khususna saprak dina macOS aya sababaraha cara pikeun "maéhan" prosés. Baca ngeunaan ieu sareng metode panyalindungan handapeun cut.

Kumaha ngajaga prosés sareng ekstensi kernel dina macOS

Cara klasik pikeun "maéhan" prosés

Cara anu terkenal pikeun "maéhan" prosés nyaéta ngirim sinyal SIGKILL kana prosés éta. Ngaliwatan bash anjeun tiasa nyauran standar "maéhan -SIGKILL PID" atanapi "pkill -9 NAME" pikeun maéhan. Paréntah "maéhan" parantos dikenal ti jaman UNIX sareng sayogi henteu ngan ukur dina macOS, tapi ogé dina sistem sapertos UNIX anu sanés.

Sapertos dina sistem sapertos UNIX, macOS ngamungkinkeun anjeun ngahalangan sinyal naon waé kana prosés kecuali dua - SIGKILL sareng SIGSTOP. Artikel ieu utamana bakal difokuskeun sinyal SIGKILL salaku sinyal nu ngabalukarkeun hiji prosés maot.

spésifikasi macOS

Dina macOS, panggero sistem maéhan dina kernel XNU nyauran psignal (SIGKILL,...) fungsi. Hayu urang cobian ningali naon tindakan pangguna anu sanés dina ruang pangguna tiasa disebat ku fungsi psignal. Hayu urang nalungtik kaluar nelepon ka fungsi psignal dina mékanisme internal tina kernel (sanajan maranéhna bisa jadi non-trivial, urang bakal ninggalkeun aranjeunna keur artikel séjén 🙂 - verifikasi signature, kasalahan memori, kaluar / nanganan nanganan, palanggaran panyalindungan file, jsb .

Hayu urang mimitian ulasan kalayan fungsi sareng panggero sistem anu saluyu terminate_with_payload. Ieu tiasa ditingali yén salian telepon pembunuhan klasik, aya pendekatan alternatif anu khusus pikeun sistem operasi macOS sareng henteu kapendak dina BSD. Prinsip operasi duanana panggero sistem oge sarupa. Éta nyaéta panggero langsung ka psignal fungsi kernel. Catet ogé yén sateuacan maéhan prosés, pamariksaan "cansignal" dilakukeun - naha prosésna tiasa ngirim sinyal ka prosés anu sanés; sistem henteu ngijinkeun aplikasi pikeun maéhan prosés sistem, contona.

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

Cara standar pikeun nyiptakeun daemon dina ngamimitian sistem sareng ngontrol umurna diluncurkeun. Punten dicatet yén sumberna kanggo versi launchctl anu lami dugi ka macOS 10.10, conto kode disayogikeun pikeun tujuan ilustrasi. launchctl modern ngirimkeun sinyal launchd via XPC, logika launchctl geus dipindahkeun ka dinya.

Hayu urang tingali kumaha persisna aplikasi dieureunkeun. Saméméh ngirim sinyal SIGTERM, aplikasi ieu diusahakeun dieureunkeun ngagunakeun "proc_terminate" panggero sistem.

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

Dina tiung, proc_terminate, sanajan ngaranna, bisa ngirim teu ukur psignal kalawan SIGTERM, tapi ogé SIGKILL.

Maéhan teu langsung - Wates sumberdaya

Kasus anu langkung narik tiasa ditingali dina telepon sistem anu sanés prosés_kabijakan. Pamakéan umum tina panggero sistem ieu nyaéta pikeun ngawatesan sumber daya aplikasi, sapertos pikeun indexer ngawatesan waktos CPU sareng kuota mémori supados sistem henteu kalem sacara signifikan ku kagiatan cache file. Lamun hiji aplikasi geus ngahontal wates sumberdaya na, sakumaha bisa ditempo ti fungsi proc_apply_resource_actions, sinyal SIGKILL dikirim ka prosés.

Sanajan panggero sistem ieu berpotensi maéhan prosés, sistem teu adequately pariksa hak prosés nelepon sistem nelepon. Sabenerna mariksa aya, tapi cukup ngagunakeun bandéra alternatif PROC_POLICY_ACTION_SET pikeun ngaliwat kaayaan ieu.

Lantaran kitu, upami anjeun "ngawatesan" kuota pamakean CPU aplikasi (contona, ngan ukur 1 ns pikeun ngajalankeun), maka anjeun tiasa maéhan prosés naon waé dina sistem. Ku kituna, malware tiasa maéhan prosés naon waé dina sistem, kalebet prosés antipirus. Ogé metot nyaéta pangaruh anu lumangsung nalika maéhan prosés kalayan pid 1 (launchctl) - panik kernel nalika nyobian ngolah sinyal SIGKILL :)

Kumaha ngajaga prosés sareng ekstensi kernel dina macOS

Kumaha ngabéréskeun masalahna?

Cara anu paling gampang pikeun nyegah prosés maot nyaéta ngagantikeun pointer fungsi dina tabel panggero sistem. Hanjakal, metoda ieu non-trivial pikeun loba alesan.

Kahiji, simbol nu ngatur lokasi memori sysent urang teu ngan swasta pikeun simbol kernel XNU, tapi teu bisa kapanggih dina simbol kernel. Anjeun kedah nganggo metode pamilarian heuristik, sapertos ngabongkar fungsi sacara dinamis sareng milarian pointer di jerona.

Bréh, struktur éntri dina tabél gumantung kana bandéra nu kernel ieu disusun. Upami bendera CONFIG_REQUIRES_U32_MUNGING dinyatakeun, ukuran strukturna bakal robih - widang tambahan bakal ditambah sy_arg_munge32. Perlu ngalaksanakeun pamariksaan tambahan pikeun nangtoskeun bandéra mana kernel anu disusun, atanapi alternatipna, pariksa petunjuk fungsi ngalawan anu dipikanyaho.

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

Untungna, dina versi modéren macOS, Apple nyayogikeun API énggal pikeun damel sareng prosés. The Endpoint Security API ngamungkinkeun para klien pikeun otorisasi seueur pamundut kana prosés anu sanés. Ku kituna, anjeun tiasa meungpeuk sagala sinyal kana prosés, kaasup sinyal SIGKILL, ngagunakeun API-disebutkeun di luhur.

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

Nya kitu, Kawijakan MAC tiasa didaptarkeun dina kernel, anu nyayogikeun metode panyalindungan sinyal (policy proc_check_signal), tapi API henteu dirojong sacara resmi.

Perlindungan extension kernel

Salian ngajagi prosés dina sistem, ngajagi extension kernel sorangan (kext) ogé diperyogikeun. macOS nyadiakeun kerangka pikeun pamekar pikeun gampang ngamekarkeun supir alat IOKit. Salian nyadiakeun parabot pikeun gawé bareng alat, IOKit nyadiakeun métode pikeun supir stacking maké instansi tina C ++ kelas. Hiji aplikasi dina userspace bakal tiasa "manggihan" hiji conto didaptarkeun kelas pikeun ngadegkeun hubungan kernel-pamaké.

Pikeun ngadeteksi jumlah instansi kelas dina sistem, aya utiliti ioclasscount.

my_kext_ioservice = 1
my_kext_iouserclient = 1

Sakur ekstensi kernel anu hoyong ngadaptar sareng tumpukan supir kedah ngadéklarasikeun kelas anu diwariskeun ti IOService, contona my_kext_ioservice dina hal ieu. Nyambungkeun aplikasi pamaké ngabalukarkeun kreasi hiji conto anyar kelas nu inherits ti IOUserClient, dina conto my_kext_iouserclient.

Nalika nyobian ngabongkar momotan supir tina sistem (paréntah kextunload), fungsi virtual "bool terminate (pilihan IOOptionBits)" disebut. Ieu cukup pikeun balik palsu dina panggero pikeun ngeureunkeun nalika nyobian ngabongkar momotanana pikeun nganonaktipkeun kextunload.

bool Kext::terminate(IOOptionBits options)
{

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

  return super::terminate(options);
}

Bandéra IsUnloadAllowed tiasa diatur ku IOUserClient nalika ngamuat. Nalika aya wates undeuran, paréntah kextunload bakal mulangkeun kaluaran ieu:

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.

Perlindungan anu sami kedah dilakukeun pikeun IOUserClient. Instance kelas tiasa dibongkar nganggo fungsi ruang pangguna IOKitLib "IOCatalogueTerminate (mach_port_t, bandéra uint32_t, déskripsi io_name_t);". Anjeun tiasa uih deui palsu nalika nelepon paréntah "terminate" dugi aplikasi userspace "maot", nyaeta, fungsi "clientDied" teu disebut.

Protéksi file

Pikeun ngajaga file, cukup nganggo Kauth API, anu ngamungkinkeun anjeun ngawatesan aksés kana file. Apple nyayogikeun pangembang béwara ngeunaan sagala rupa acara dina lingkup; pikeun kami, operasi KAUTH_VNODE_DELETE, KAUTH_VNODE_WRITE_DATA sareng KAUTH_VNODE_DELETE_CHILD penting. Cara panggampangna pikeun ngawatesan aksés kana file nyaéta ku jalur - kami nganggo "vn_getpath" API pikeun kéngingkeun jalur kana file sareng ngabandingkeun awalan jalur. Catet yén pikeun ngaoptimalkeun ngarobih nami jalur folder file, sistem henteu masihan otorisasi aksés ka unggal file, tapi ngan ukur kana folder anu parantos diganti. Perlu ngabandingkeun jalur indungna sareng ngawatesan KAUTH_VNODE_DELETE pikeun éta.

Kumaha ngajaga prosés sareng ekstensi kernel dina macOS

Karugian tina pendekatan ieu tiasa kinerja rendah sabab jumlah awalan nambahan. Pikeun mastikeun yén babandinganana henteu sarua jeung O(awalan*panjang), dimana awalan nyaéta jumlah awalan, panjangna panjang string, anjeun tiasa nganggo deterministic finite automaton (DFA) diwangun ku awalan.

Hayu urang nganggap metode pikeun ngawangun DFA pikeun set prefiks. Urang initialize kursor di awal unggal awalan. Upami sadaya kursor nunjuk ka karakter anu sami, teras ningkatkeun unggal kursor ku hiji karakter sareng émut yén panjang garis anu sami langkung ageung ku hiji. Upami aya dua kursor kalayan simbol anu béda, bagikeun kursor kana grup dumasar kana simbol anu ditunjuk sareng malikan algoritma pikeun unggal grup.

Dina kasus nu pertama (sadayana karakter dina kursor sarua), urang meunang kaayaan DFA nu boga ngan hiji transisi sapanjang garis sarua. Dina kasus kadua, urang meunang tabel transisi ukuranana 256 (jumlah karakter jeung jumlah maksimum grup) ka kaayaan saterusna diala ku recursively nelepon fungsi.

Hayu urang nempo hiji conto. Pikeun sakumpulan awalan ("/foo/bar/tmp/", "/var/db/foo/", "/foo/bar/aba/", "foo/bar/aac/") anjeun tiasa nampi ieu di handap. DFA. Angka éta ngan ukur nunjukkeun transisi anu nuju ka nagara-nagara sanés; transisi sanés moal final.

Kumaha ngajaga prosés sareng ekstensi kernel dina macOS

Nalika ngaliwatan nagara bagian DKA, meureun aya 3 kasus.

  1. Kaayaan ahir parantos dihontal - jalanna ditangtayungan, urang ngawatesan operasi KAUTH_VNODE_DELETE, KAUTH_VNODE_WRITE_DATA sareng KAUTH_VNODE_DELETE_CHILD
  2. Kaayaan ahir teu ngahontal, tapi jalur "réngsé" (null terminator ieu ngahontal) - jalur indungna, perlu pikeun ngawatesan KAUTH_VNODE_DELETE. Catet yén upami vnode mangrupikeun polder, anjeun kedah nambihan '/' dina tungtungna, upami henteu tiasa ngawatesan kana file "/foor/bar/t", anu henteu leres.
  3. Kaayaan ahir teu kahontal, jalur teu mungkas. Henteu aya awalan anu cocog sareng ieu, kami henteu ngenalkeun larangan.

kacindekan

Tujuan tina solusi kaamanan anu dikembangkeun nyaéta pikeun ningkatkeun tingkat kaamanan pangguna sareng datana. Di hiji sisi, tujuan ieu dihontal ku pamekaran produk parangkat lunak Acronis, anu nutup kerentanan anu mana sistem operasina sorangan "lemah". Di sisi anu sanés, urang henteu kedah ngalalaworakeun nguatkeun aspék kaamanan anu tiasa ditingkatkeun dina sisi OS, khususna saprak nutup kerentanan sapertos kitu ningkatkeun stabilitas urang salaku produk. Kerentanan ieu dilaporkeun ka Tim Kaamanan Produk Apple sareng parantos dibenerkeun dina macOS 10.14.5 (https://support.apple.com/en-gb/HT210119).

Kumaha ngajaga prosés sareng ekstensi kernel dina macOS

Sadaya ieu ngan tiasa dilakukeun upami utilitas anjeun parantos dipasang sacara resmi kana kernel. Nyaéta, teu aya celah sapertos pikeun parangkat lunak éksternal sareng anu teu dihoyongkeun. Nanging, sakumaha anu anjeun tingali, bahkan ngajagi program anu sah sapertos antipirus sareng sistem cadangan peryogi padamelan. Tapi ayeuna produk Acronis anyar pikeun macOS bakal gaduh panyalindungan tambahan tina ngabongkar muat tina sistem.

sumber: www.habr.com

Tambahkeun komentar