Ahoana ny fomba hiarovana ny fizotran'ny asa sy ny fanitarana ny kernel ao amin'ny macOS

Manao ahoana, Habr! Androany aho dia te hiresaka momba ny fomba ahafahanao miaro ny fizotranao amin'ny fanafihana ratsy. macOSOhatra, ilaina amin'ny antivirus na rafitra backup izany, indrindra satria eo ambanin'ny macOS Misy fomba maro "hamonoana" dingana iray. Vakio eto ambany raha mila fanazavana fanampiny sy fomba fiarovana.

Ahoana ny fomba hiarovana ny fizotran'ny asa sy ny fanitarana ny kernel ao amin'ny macOS

Ny fomba mahazatra "mamono" dingana iray

Fomba iray fantatra tsara hamonoana dingana iray ny fandefasana ny famantarana SIGKILL any aminy. Ao amin'ny bash, azonao ampiasaina ny baiko mahazatra "kill -SIGKILL PID" na "pkill -9 NAME" mba hamonoana azy. Ny baiko "kill" dia efa nisy hatramin'ny andron'ny UNIX ary tsy azo ampiasaina amin'ny... macOS, fa amin'ny rafitra hafa mitovy amin'ny UNIX ihany koa.

Toy ny amin'ny rafitra mitovy amin'ny UNIX, macOS Ahafahanao misambotra ny famantarana rehetra afa-tsy roa—SIGKILL sy SIGSTOP. Hifantoka voalohany indrindra amin'ny famantarana SIGKILL ity lahatsoratra ity, izay miteraka ny fahafatesan'ny dingana.

Specificity macOS

В macOS Ny antson'ny rafitra kill ao amin'ny kernel XNU dia miantso ny fiasa psignal(SIGKILL,…). Andeha hojerentsika izay hetsika hafa ataon'ny mpampiasa ao amin'ny userspace afaka miantso ny fiasa psignal. Hanivana ireo antso mankany amin'ny fiasa psignal ao amin'ny mekanisma kernel anatiny isika (na dia mety ho tsy dia misy dikany aza izy ireo, dia havelantsika amin'ny lahatsoratra hafa izany :)) - fanamarinana sonia, hadisoana amin'ny fitadidiana, fikirakirana fivoahana/famaranana, fanitsakitsahana ny fiarovana ny rakitra, sns.

Andao hanomboka ny famerenana amin'ny fiasa sy ny antso an-tariby mifandraika amin'izany terminate_with_payloadMazava fa ankoatra ny antso famonoana mahazatra, misy fomba fiasa hafa izay manokana ho an'ny rafitra fiasana. macOS ary tsy hita ao amin'ny BSD. Mitovy ihany koa ny foto-kevitry ny fiasan'ireo antso rafitra roa ireo. Antso mivantana amin'ny fonction kernel psignal izy ireo. Mariho ihany koa fa alohan'ny hamonoana dingana iray dia misy fanamarinana "cansignal" atao—raha afaka mandefa famantarana any amin'ny dingana hafa ilay dingana. Ohatra, tsy mamela fampiharana hamono dingana rafitra ny rafitra.

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

Ny fomba mahazatra hamoronana daemons amin'ny fanombohana ny rafitra sy hifehezana ny androm-piainany dia launchd. Mariho fa ny kaody loharano dia ho an'ny dikan-teny taloha kokoa an'ny launchctl, talohan'ny macOS 10.10, ohatra amin'ny kaody no omena ho fanazavana. Ny launchctl maoderina dia mandefa famantarana any amin'ny launchd amin'ny alàlan'ny XPC, ary ny lojika launchctl dia nafindra tany aminy.

Andeha hojerentsika hoe ahoana marina ny fampitsaharana ny fampiharana. Alohan'ny handefasana ny mari-pamantarana SIGTERM, dia ezahina ajanona ny fampiharana amin'ny alàlan'ny antso an-tariby "proc_terminate".

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

Eo ambanin'ny satroka, proc_terminate, na dia eo aza ny anarany, dia afaka mandefa tsy ny psignal miaraka amin'ny SIGTERM, fa SIGKILL ihany koa.

Famonoana ankolaka - fetran'ny loharanon-karena

Tranga mahaliana kokoa dia hita amin'ny antso an-tariby hafa process_policy. Ny fampiasana mahazatra an'ity antso an-tariby ity dia ny famerana ny loharanon'ny rindranasa, toy ny fanondroana mba hamerana ny fotoanan'ny CPU sy ny fetran'ny fitadidiana mba tsy hampiadana be ny rafitra amin'ny hetsika caching rakitra. Raha toa ka nahatratra ny fetran'ny loharanon-karena ny fampiharana iray, araka ny hita amin'ny asa proc_apply_resource_actions, dia misy famantarana SIGKILL alefa any amin'ny dingana.

Na dia mety hamono dingana iray aza ity antson'ny rafitra ity, tsy nojeren'ny rafitra araka ny tokony ho izy ny zon'ny dingana miantso ny antso an-tariby. Tena manamarina nisy, fa ampy ny mampiasa ny saina hafa PROC_POLICY_ACTION_SET mba hialana amin'ity fepetra ity.

Noho izany, raha "mametra" ny fetran'ny fampiasana CPU ianao (ohatra, mamela ny 1 ns fotsiny handeha), dia azonao atao ny mamono ny dingana rehetra ao amin'ny rafitra. Noho izany, ny malware dia afaka mamono ny dingana rehetra amin'ny rafitra, anisan'izany ny fizotran'ny antivirus. Mahaliana ihany koa ny vokatra mitranga rehefa mamono dingana iray miaraka amin'ny pid 1 (launchctl) - panic kernel rehefa manandrana manamboatra ny famantarana SIGKILL :)

Ahoana ny fomba hiarovana ny fizotran'ny asa sy ny fanitarana ny kernel ao amin'ny macOS

Ahoana no hamahana ny olana?

Ny fomba tsotra indrindra hisorohana ny dingana tsy ho faty dia ny fanoloana ny tondro fiasa ao amin'ny latabatra antso an-tariby. Indrisy anefa fa tsy misy dikany io fomba io noho ny antony maro.

Voalohany, ny marika mifehy ny toerana fitadidian'ny sysent dia tsy mitokana ho an'ny marika kernel XNU, fa tsy hita ao amin'ny marika kernel. Tsy maintsy mampiasa fomba fikarohana heuristic ianao, toy ny famongorana ny fiasa sy ny fitadiavana tondro ao anatiny.

Faharoa, ny firafitry ny fidirana ao amin'ny tabilao dia miankina amin'ny saina izay nanangona ny kernel. Raha ambara ny saina CONFIG_REQUIRES_U32_MUNGING dia hovana ny haben'ny rafitra - hisy saha fanampiny hiampy sy_arg_munge32. Ilaina ny manao fanaraha-maso fanampiny mba hamaritana hoe iza no saina natambatra tamin'ny kernel, na koa, jereo ny tondro fiasa amin'ireo fantatra.

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

Soa ihany fa amin'ny dikan-teny maoderina macOS Manome API vaovao ho an'ny fiasana amin'ny dingana ny Apple. Ny Endpoint Security API dia ahafahan'ny mpanjifa manome alalana fangatahana maro amin'ny dingana hafa. Ohatra, ny famantarana rehetra mankany amin'ny dingana, anisan'izany ny famantarana SIGKILL, dia azo sakanana amin'ny alàlan'ny API voalaza etsy ambony.

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

Toy izany koa, ny politikan'ny MAC dia azo soratana ao amin'ny kernel, izay manome fomba fiarovana famantarana (politika proc_check_signal), saingy tsy tohanana amin'ny fomba ofisialy ny API.

Fiarovana ny fanitarana kernel

Ankoatra ny fiarovana ny fizotran'ny rafitra, ilaina ihany koa ny miaro ny fanitarana ny kernel (kext). macOS Manome rafitra ho an'ny mpamorona rindrambaiko ny IOKit mba hahafahany mamolavola mora foana ny mpamily fitaovana IOKit. Ankoatra ny fanomezana fitaovana hiasana amin'ny fitaovana, manohana ny fomba fametrahana mpamily amin'ny fampiasana ohatra kilasy C++ ny IOKit. Afaka "mahita" ohatra kilasy voasoratra anarana ny fampiharana userspace mba hametrahana fifandraisana kernel-userspace.

Mba hamantarana ny isan'ny kilasy ao amin'ny rafitra dia misy ny ioclasscount utility.

my_kext_ioservice = 1
my_kext_iouserclient = 1

Ny fanitarana kernel rehetra izay te hisoratra anarana amin'ny stack mpamily dia tsy maintsy manambara kilasy iray mandova avy amin'ny IOService, ohatra my_kext_ioservice amin'ity tranga ity.

Rehefa manandrana manala mpamily avy amin'ny rafitra (baiko kextunload), dia antsoina ny fiasa virtoaly "bool terminate (IOOptionBits options)". Ampy ny mamerina diso amin'ny fiantsoana hampitsahatra rehefa manandrana manaisotra ny kextunload.

bool Kext::terminate(IOOptionBits options)
{

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

  return super::terminate(options);
}

Ny saina IsUnloadAllowed dia azo apetraka amin'ny IOUserClient rehefa mandefa. Rehefa misy fetran'ny fampidinana dia hamerina ity vokatra manaraka ity ny baiko kextunload:

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.

Ny fiarovana toy izany dia tsy maintsy atao ho an'ny IOUserClient. Ny ohatra amin'ny kilasy dia azo alaina amin'ny fampiasana ny IOKitLib userspace function "IOCatalogueTerminate(mach_port_t, uint32_t flag, io_name_t description);". Azonao atao ny mamerina diso rehefa miantso ny baiko "farafaharatsiny" mandra-pahafatin'ny rindranasa mpampiasaspace, izany hoe tsy antsoina ny fiasa "clientDied".

Fiarovana ny rakitra

Mba hiarovana ny rakitra dia ampy ny mampiasa ny Kauth API, izay ahafahanao mametra ny fidirana amin'ny rakitra. Apple dia manome fampandrenesana ho an'ny mpamorona momba ny hetsika isan-karazany amin'ny sehatra; ho anay dia zava-dehibe ny hetsika KAUTH_VNODE_DELETE, KAUTH_VNODE_WRITE_DATA ary KAUTH_VNODE_DELETE_CHILD. Ny fomba tsotra indrindra hamerana ny fidirana amin'ny rakitra dia amin'ny alàlan'ny lalana - mampiasa ny API "vn_getpath" izahay mba hahazoana ny lalana mankany amin'ny rakitra ary mampitaha ny tovan'ny lalana. Mariho fa mba hanamafisana ny fanovana anarana ny lalan'ny lahatahiry rakitra, ny rafitra dia tsy manome alalana ny fidirana amin'ny rakitra tsirairay, fa ny fampirimana izay novana anarana ihany. Ilaina ny mampitaha ny lalan'ny ray aman-dreny ary mametra ny KAUTH_VNODE_DELETE ho azy.

Ahoana ny fomba hiarovana ny fizotran'ny asa sy ny fanitarana ny kernel ao amin'ny macOS

Ny tsy fahampian'ity fomba fiasa ity dia mety ho ambany ny fahombiazany satria mitombo ny isan'ny prefix. Mba hahazoana antoka fa tsy mitovy amin'ny O(prefix*length) ny fampitahana, izay ny prefix dia ny isan'ny prefixes, ny halavany dia ny halavan'ny tady, azonao atao ny mampiasa automaton finite deterministic (DFA) naorin'ny prefixes.

Andeha isika handinika fomba fanamboarana DFA ho an'ny andiana prefixes. Manomboka ny cursors amin'ny fiandohan'ny prefix tsirairay. Raha manondro toetra iray ihany ny cursors rehetra, dia ampitomboy tarehintsoratra iray ny cursor tsirairay ary tadidio fa ny halavan'ny andalana iray dia lehibe kokoa amin'ny iray. Raha misy cursor roa misy marika samy hafa dia zarao ho vondrona ny cursors araka ny marika tondroiny ary avereno ny algorithm ho an'ny vondrona tsirairay.

Amin'ny tranga voalohany (ny endri-tsoratra rehetra eo ambanin'ny cursors dia mitovy), dia mahazo fanjakana DFA izay tsy misy afa-tsy tetezamita iray amin'ny andalana iray ihany. Amin'ny tranga faharoa, dia mahazo latabatra fifindran'ny habe 256 (isan'ny tarehin-tsoratra sy isan'ny vondrona ambony indrindra) mankany amin'ny fanjakana manaraka azo amin'ny fiantsoana miverimberina ilay asa.

Andeha isika hijery ohatra iray. Ho an'ny andiana prefixes (“/foo/bar/tmp/”, “/var/db/foo/”, “/foo/bar/aba/”, “foo/bar/aac/”) dia azonao atao ireto manaraka ireto DFA. Asehon'io tarehimarika io ihany ny fifindrana mankany amin'ny fanjakana hafa; tsy ho farany ny tetezamita hafa.

Ahoana ny fomba hiarovana ny fizotran'ny asa sy ny fanitarana ny kernel ao amin'ny macOS

Rehefa mandalo ny fanjakana DKA dia mety misy tranga 3.

  1. Tonga ny fanjakana farany - voaaro ny lalana, feranay ny asa KAUTH_VNODE_DELETE, KAUTH_VNODE_WRITE_DATA ary KAUTH_VNODE_DELETE_CHILD
  2. Tsy tonga ny fanjakana farany, fa ny lalana dia "nifarana" (tonga ny terminator null) - ray aman-dreny ny lalana, ilaina ny mametra ny KAUTH_VNODE_DELETE. Mariho fa raha laha-tahiry ny vnode dia mila manampy '/' ianao amin'ny farany, raha tsy izany dia mety hametra izany amin'ny rakitra "/foor/bar/t", izay diso.
  3. Tsy tonga ny fanjakana farany, tsy nifarana ny lalana. Tsy misy prefix mifanandrify amin'ity iray ity, tsy mampiditra fameperana izahay.

famaranana

Ny tanjon'ny fampivoarana vahaolana momba ny fiarovana dia ny hampitombo ny haavon'ny fiarovana ho an'ny mpampiasa sy ny angon-drakitra ananan'izy ireo. Tratra amin'ny alàlan'ny fampivoarana ny rindrambaiko Acronis io tanjona io, izay mamaha ireo fahalemena ao amin'ny rafitra fiasana mihitsy. Etsy ankilany, tsy tokony hohadinointsika ny fanamafisana ireo lafiny fiarovana izay azo hatsaraina eo amin'ny lafiny OS, indrindra satria ny fanakatonana ireo fahalemena ireo dia mampitombo ny faharetantsika amin'ny maha-vokatra antsika. Notaterina tamin'ny Ekipa Fiarovana Vokatra Apple ny fahalemena ary nohavaozina tamin'ny macOS 10.14.5 (https://support.apple.com/en-gb/HT210119).

Ahoana ny fomba hiarovana ny fizotran'ny asa sy ny fanitarana ny kernel ao amin'ny macOS

Izany rehetra izany dia azo atao raha toa ka napetraka ara-dalàna ao amin'ny kernel ny fitaovanao. Midika izany fa tsy misy lavaka toy izany ho an'ny rindrambaiko ivelany sy tsy ilaina. Na izany aza, araka ny hitanao, na dia ny fiarovana ny programa ara-dalàna toy ny antivirus sy ny rafitra backup aza dia mitaky ezaka. Saingy ankehitriny, ireo vokatra Acronis vaovao ho an'ny macOS hanana fiarovana fanampiny amin'ny fanesorana entana avy amin'ny rafitra.

Source: www.habr.com

Mividiana fampiantranoana azo antoka ho an'ny tranokala misy fiarovana DDoS, mpizara VPS VDS 🔥 Mividiana fampiantranoana tranonkala azo antoka miaraka amin'ny fiarovana DDoS, mpizara VPS VDS | ProHoster