á°ááᣠáá¥á! áᬠáá°á¶áœáá ášá°áá®á á¥áá¶áœ á¥ááŽáµ áá á á á¥áá°ááœá ááá«áµ á¥áááááᢠmacOSááá³áᣠáá áááš-á«áášáµ ááá ááá á£á áá« áµááá¶áœ á áá ááᣠá á°ááá ášáá á á³áœ á£áá á¥ááá³ áááá«áµá¢ macOS á ááµá áá°áµ "áááá°á" á áá«á³ áááá¶áœ á áᢠáá°ášá᪠áášá á¥á ášáášáášá« ááŽáᜠášáá á á³áœ á«áá¥á¡á¢
á ááµá áá°áµ "áááá°á" ášáá³ááá ááááµ
á ááµá áá°áµ áááá°á ášáá³áá ááááµ ášSIGKILL ááááµ áá° á¥á± ááá ááᢠá bash ááµá¥á£ áááá°á áá°á ááá "kill -SIGKILL PID" ááá "pkill -9 NAME" áµááááœá áá áá ááœááᢠ"kill" ášááá áµááá ášá©áááµ ááá ááá® ášáá áš á²áá á ááµá¥ á¥á» á³ááá á ááµá¥á ááááᢠmacOS, ááá áá á ááᜠá©áááµ-áá°á áµááá¶áœ ááá áááá¢
áá á¥áá° á©áááµ-áá°á á²áµá°ááœá£ macOS ášáááµ á áµá°áá áááááá ášáá°áµ ááááµ á¥áá²á¥á á«áµáœááá³á - SIGKILL á¥á SIGSTOPᢠáá áœáá á ááááµ ášáá°áµ ááµá« á áá«áµášáµá ášSIGKILL ááááµ áá á«á°á©á«áá¢
áá©ááµ macOS
Ð macOS á XNU ášááá ááµá¥ á«áá ášáªá á²áµá°á á¥áª ášpsignal(SIGKILL,...) á°áá£áá áá á«áᢠá á°á áá áŠá³ ááµá¥ á«á ááᜠášá°á áá á¥ááááᜠášpsignal á°áá£áá áá á©áµ ášááœááµá ááášáµ á¥ááááᢠá ááµá£á ášášááá áá«ááá ááµá¥ áá° psignal á°áá£á ášáá°ášá á¥áªááœá á¥áá£á«áá (ááá á¥áá³á á°á« á«ááá á¢áááᣠááá áœáá á¥áá°áááá :)) - ášááá áášááá«á£ ášáá á°áš áµááµá³ áµá á°á¶áœá£ ášááá£áµ/ášááá á á«á«áᣠášááá á°á áááµ á¥á°á¶áœá£ ááá°á¢
á á ááá á¥áá³áá á á°áá£á© á¥á á á°ááá ášáµáááµ á¥áª á¥áááá ášá¥áá³áá ášááµá« á¥áª á á°ášá᪠ááŠáá¬á²áá á²áµá°á ášá°ááš á áá«á á áá«ášá¥ á¥áá³á ááá ááᢠmacOS á¥á á BSD ááµá¥ á ááááᢠášááá±á ášáµáááµ á¥áªáᜠášá á á«á áááááœá á°áá³á³á áážáᢠáá° ášááá á°áá£á psignal áá¥á°á á¥áªáᜠáážáᢠá¥áá²áá á ááµá áá°áµ ášááá°áá á ááµ "ášá«áá²ááá" áá°á» á¥áá°áá°ášá áᥠáá á - áá°á± áá° áá áá°áµ ááááµ ááá ááœá á¥áá°ááᢠáµááá± ááá³á ášáµáááµ áá°á¶áœá á¥áá²á«á á áááááá áá°áá áªá« á ááá áµáá¢
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);
}
...
}
á°áááš
á áµáááµ á áá áá á ááááµá áááá á á¥á ášá áááµ áááážáá áááá£á á ášá°ááá°á ááááµ á°ááá¯áᢠá¥á£ááá ášááá á®á± áá á®á áš launchctl áµáªáµ áááá áᥠáá áᣠášáá á ááµ macOS 10.10ᣠášá®áµ áá³ááᜠááá³á ááááᜠááá ááᢠááááá launchctl á XPC á á©á áá° ááµáááªá« áááá¶áœ ááá«áᣠá¥á launchctl ááá áá° á¥á± á°ááµá·áá¢
á ááá¬áœáᜠá¥ááŽáµ á¥áá°ááá á¥áááášáµá¢ áš SIGTERM ááááµ ášááá© á ááµá£ á ááá¬áœá á "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));
}
...
<>
á áášáá« áµáᣠproc_terminateᣠááá á¥áá³á áµá á¢áááᣠá SIGTERM á¥á» á³ááá SIGKILLáá ááá ááœááá¢
áá¥á°á á«ááá ááµá« - ášáá¥ášáµ á«á
ášá áá á áµá°á³áœ áá³á á áá ášáµáááµ á¥áª ááµá¥ áá³á ááœááᢠ. ááá ášá¥áááµ á¥áª ášá°ááá°á ášáá°áá áªá« áá¥á¶áœá ááá°á¥ ááᣠááá³á á²áá© á¥á ášááµá³áá» á®á³ áášá á ááá ááá°á¥á£ áµááá± á ááá áážáá« á¥áá áµááŽáᜠá ášáá°á ááá³ á¥áá³ááááµá¢ ášproc_apply_resource_actions á°áá£á á¥áá°áá³ášá á ááá¬áœá ášáá¥á áµ áá°á¡ áá ášá°ášá°á£ SIGKILL ááááµ áá° áá°á± ááá«áá¢
ááá á¥áá³á áá ášáµáááµ á¥áª áá°áµá ášááá°á á á á á¢áášáá á¥ááá± ášáµáááµ á¥áªáá ášáá¥á«áµ áá°áµ áá¥á¶áœá á á á ááá³ á áá£á«áᢠá á¥ááá± á áá£á«áµ áá ááá áá áá áá ááá³ áááá ášá áá«á á£áá²á« PROC_POLICY_ACTION_SET áá áá á á ááá¢
áµááá ášCPU á á áááá á®á³ á áá°áá áªá« âášáá°á¡â (ááá³á 1 ns á¥á» á¥áá²á°á« ášááá±) á á²áµá°á ááµá¥ á«ááá áááááá áá°áµ ááá°á ááœááᢠáµááá áááá ášážáš-á«áášáµ áá°áµá ášáá® á á²áµá°á áá á«ááá áááááá áá°áµ áááµá ááœááᢠá¥áá²áá áá°á±á á pid 1 (launchctl) á²ááµá ášá°ááá áá€áµ - áš SIGKILL ááááµá áááµá¬áµ á ááášáá áµ áá ášášááá ááááµ ð

áœáá©á á¥ááŽáµ ááá³áµ áá»áá?
áá°áµá ááá°áá ááášáášá á á£á ááá ááááµ á áµáááµ á¥áª á áá ášá¥ ááµá¥ á«ááá ášá°áá£á á áá áá°á«áµ ááᢠá áá«á³áá ááá³, áá áᎠáá¥á áááá«á¶áœ ááá á áá°áá.
á ááááªá« ᣠášáá á°áš áµááµá³ áŠá³á ášáááá ááááµ áš XNU kernel ášáá ááááµ á¥á» á³ááá á ášááá áááá¶áœ ááµá¥á ááá á ááœááᢠáá©áªáµá²á ášááá ááŽááœá áá áá á áá¥á ᣠááá³áᣠášá°áá£áá á°áááá ááá³áµ á¥á á ááµá¡ á ááá ááááá¢
á ááá°á á°ášá, á á áá ášá¡ ááµá¥ á«ááµ ášááá¢á«áᜠááá á ášááá á á°á ááášá£ážá á£áá²á«áᜠáá ááá°áá. ášCONFIG_REQUIRES_U32_MUNGING á£áá²á« ášá³ááᣠášááá á© áá á ááášá«á - á°ášá᪠ááµá áá³ášáá . ášááá á ášáµáá á£áá²á« á¥áá°á°á áááš á°ášá᪠áášááá« ááµášá á áµááá áá, á¥áá° á áá«á, ášáá³áááµ áá ášá°áá£á á ááá«áŸáœá á«ášááá¡.
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
*/
};
á¥áá° á¥áµá ááᣠá áááá áµáªá¶áœ macOS á áá ášáá°á¶áœ áá áááµá«áµ á á²áµ á€áá á á«ááá£áᢠášEndpoint Security API á°áá áᜠáááᜠáá°á¶áœ á¥á á¥á«áááœá á¥áá²áá á± á«áµáœáážááᢠááá³áᣠáá° áá°á¶áœ ášááá± ááážáá áááá¶áœá£ ášSIGKILL ááááµá ášáá®á£ ášáá ášá°á áá°áá á€áá á á áá áá áá³áá± ááœááá¢
#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;
}
á á°áá³á³áᣠᚠMAC ááá² á ášááá ááµá¥ ááááᥠááœááᣠáá á ášá²ááá á¥á á ááŽá áá°á£á (áááªá« proc_check_signal) áá á€áá á á áá á áá°áááá¢
ášášááá áá«ááá« á¥á á
á áµááá± ááµá¥ áá°á¶áœá ášáá á á á á°ášá᪠ášášááá áá«ááá« (á¬ááµáµ) á¥á«á±á áá á á á áµááá ááᢠmacOS IOKit ááá¢áᜠášIOKit áá³áªá« ááááœá á ááá á¥áá²á«ááá ášáá«áµáœá áááá á«ááá£áᢠášáá³áªá«áᜠáá áááµá«áµ áá³áªá«ááœá ášáá ášá¥ á á°ášá᪠IOKit ášC++ ááá á á¥áá¶áœá á áá áá ášá áœášáá«áªáᜠáá°á«ášá¥ ááŽááœá áá°áááᢠášá°á áá áŠá³ áá°áá áªá« ášášááá-á°á áá áŠá³ áááááµá ááááµášáµ ášá°áááá ášááá áá³áá "ááááµ" ááœááá¢
ášioclasscount ááááá« á á ááµ á¥áááµ ááµá¥ á«ááµá ášááá á áá£ááᜠá¥ááµ áááá á áá¢
my_kext_ioservice = 1
my_kext_iouserclient = 1
á á¹áá© ááá áááááᥠášáááá ááááá ášášááá á á¥á« ášá ááŠá€áµ á áááááµ ášááááµ áááá ááá á áá áµ ááá³á my_kext_ioservice á áá áá³á áá ášá°á áá áá°áá áªá«ááœá áááááµ ášIOUserClient ášá°áášá° ááá á á²áµ ááá³á my_kext_iouserclient á¥áá²áá á á«á°áááᢠ.
áŸáá©á ášá²áµá°á áááášáµ á²ááá© (áš kextunload áµááá) ááá£á á°áá£á "áŠá ááášá¥ (IOOptionBits á áá«á®áœ)" áá£áá. kextunload á ááá°áášá áááášáµ á ááášáá áµ áá ášááášá¡ á°áá£á á¥áª áá áá°áµ ááááµ á á ááá¢
bool Kext::terminate(IOOptionBits options)
{
if (!IsUnloadAllowed)
{
// Unload is not allowed, returning false
return false;
}
return super::terminate(options);
}
áš IsUnloadAllowed á£áá²á« á IOUserClient áááá ááœááᢠááá± á²áá°á¥ áš 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.
áIOUserClient á°áá³á³á á¥á á áá°ášá á áá áµá¢ ášááá áá³ááᜠIOKitLib ášá°á áá áŠá³ á°áá£áá á áá áá ááášáµ áá»áá "IOCatalogueTerminate(mach_port_t, uint32_t flag, io_name_t áááá«)"ᢠášá°á áá áŠá³ á ááá¬áœá "ááá³á" áááµá "clientDied" á°áá£á á¥áµá«áá°á á« áµášáµ áá° "ááášá¥" áµá¥áá á áá°ášá á¥áª áá ášáážáµ ááááµ áá»áá::
ášááá á¥á á
ááááœá ááá á á ášááááœá áá³ášá» áááá°á¥ ášáá«áµáœáááµá áš Kauth API áá áá á á ááᢠá áá á ášá á«á£á¢á áµáá ášá°áá«á© ááµá°á¶áœ áá³ááá«ááœá áááá¢áᜠá«ááá£áᣠKAUTH_VNODE_DELETEᣠKAUTH_VNODE_WRITE_DATA á¥á KAUTH_VNODE_DELETE_CHILD áµá«áᜠáá¥á á áµááá áážáᢠášáááᜠáá³ášá»á áááá°á¥ ááá ááááµ ááááµ áá - áá° ááá ášáááµá°áá ááááµ áááááµ á¥á ášáááá±á á áµá á á¥á« áááááá áš"vn_getpath" API á¥áá ááááᢠášá áá á±á«ááœá á áááᜠááášáá áááá»ážáµ áµááá± áá¥á«áá³áá± ááá áá³ášá» á áá°á¥á ááá áá ášá°á°ášáá á áá á«á± á¥á» áááá áᥠáá áᢠášááá ááááµá ááá³á°á á¥á áá¥á± KAUTH_VNODE_DELETE ááá°á¥ á áµááá ááá¢

ášá
áµá-á
á¥á«áᜠá¥ááµ á²ášáá ášáá
á á«ááµ áá³á± á°á«á á áááá ááá ááœááᢠááœáœá© ášáŠ (á
áµá á
á¥á« * ááááµ) áá á¥á©á á ááááá ááášááᥠá
áµá á
á¥á« ášá
áµá-á
á¥á«áᜠá¥ááµá£ áááá± ášáá¥ášáááá ááááµ ášáá á£á á
áµá-á
á¥á«áᜠáá ášá°ááᣠáá«á¥ áááµ á áá¶ááµá¶á (DFA) áá áá ááœááá¢
áá°áá°á á áµá-á á¥á«áᜠá²á€áဠášáááá£áµ ááŽá á áµá¡á áµá¢ á á¥á«áá³áá± á áµá á á¥á« ááááªá« áá á ááááœá á¥ááµááá«áá. ááá á áááᜠáá° á ááµ á áááµ á£á ᪠ášáá«áááá± ášáá á¥á«áá³áá±á á áá á á ááµ ááá á¥áášáá«áá á¥á ášá ááµ ááµáá ááááµ á ááµ á á ááµ á¥áá°áá áᥠá¥ááµá³áá³áá. áááµ á áááᜠá«á, ášáµá á«ááµ ááááᜠášá°áá«á© áážá, á áááá¹á á á°á áááµ á£á ᪠áá°ášáµ á á¡áµá á¥áášáááá á¥á áá¥á«áá³áá± á¡áµá á áááªááá á¥áá°áááá.
á ááááªá«á ááá³ (ášá áááá¹ áµá á«á ááá ááááᜠá°áá³á³á áážá), ášá²á€áဠááá³á á¥ááááá, á á°áá³á³á ááµáá áá á ááµ áœááá á¥á» áá á«áá. á ááá°áá áá³á áá 256 áá á (ášááááᜠá¥ááµ á¥á ášáá°áá ášá¡áµáᜠá¥ááµ) áá° á°ášá³á ááá¶áœ ášáážááášáá á áá ášá¥ á¥ááááá á¢
á ááµ áá³á á¥áááášáµá¢ áá áµá-á á¥á«áᜠáµá¥áµá¥ ("/foo/bar/tmp/"ᣠ"/var/db/foo/", "/foo/bar/aba/", "foo/bar/aac/")ᣠášáášá°áá á²á€áဠááœáá ááááµ. áµáá ášáá«á³ášá áá° ááᜠááá¶áœ ášáá°ášá áœááá®áœá á¥á» ááᣠááᜠáœááá®áœ ášáášášá» ááá á ááœááá¢

á á²á€áဠááá¶áœ ááµá¥ á áá«ááá áµ áá, 3 áá³á®áœ ááá© ááœáá.
- ášáášášá»á ááá³ áá á°áá·á - áááá± ášá°á á á ááᣠááááá¹á áááµá¡ KAUTH_VNODE_DELETEᣠKAUTH_VNODE_WRITE_DATA á¥á KAUTH_VNODE_DELETE_CHILD
- ášáášášá»á ááá³ á áá°ášá°á ááá áá á±á«á "á ááá" ( á£á¶ á°áááá°á á°áá·á) - áááá± ááá ááᣠKAUTH_VNODE_DELETE ááá°á¥ á áá áµá¢ ááµá³áá»á vnode á áá ášáá áá° áášášá»á '/' áášá á áá¥á á áá ááá« áá á ááá "/foor/bar/t" áá áááµá¥ ááœááᣠáá áµááá á áá°ááá¢
- ášáášášá»á áááµ á áá°ášá°á, áááá± á áááá. ášáµááá á áµá á á¥á« ášá°á°á á áá á ááááµáᣠáá°áŠáœá á ááµá°ááá áá¢
áá°áá°áá«
ášá°á áááµ áááµáááœá ášáááááµ áᥠáá°á áááᜠá¥á ááášááá»ážá ášá°á áááµ á°ášáá áá³á°á ááᢠáá áᥠášáá³á«á á áŠáá¬á²áá á²áµá°á ááµá¥ á«ááµá á°ááááá¶áœ ášááá³áá ášá áá®ááµ á¶ááµáá á ááááµ ááᢠá áá á á©áᣠá á°ááá á¥áá°áá á«á á°ááááá¶áœá ááááµ á¥áá° áááµ ášá«á³áœáá ášáááá á á á áµááášáá á OS á á©á áá»á»á ášááœááµá ášá°á áááµ ááœá³áᜠáá áášá áœá áááµ ášáá¥ááᢠá°ááááá± áá áá áááµ á°á áááµ á¡áµá áªáááµ á°á°ááá á¥á á macOS 10.14.5 (https://support.apple.com/en-gb/HT210119)á¢

áá
áá áášááá ášááœáá ááááá«á á ášááá ááµá¥ á áá ášá°á«á á¥á» ááᢠáá
áááµ ááá«á á¥á áááááá á¶ááµáá®áœ á¥áá°áá
á áááµ ááá°á¶áœ ášáá áááµ ááᢠááá ááᣠá¥áá°áá³á©áµá£ á¥áá° ážáš-á«áášáµ á¥á ášáá á£á áá« áµááá¶áœ á«á á
áá áá®áá«ááœá áá á á
á¥áá³á ášá°áá°á á¥ášáµ áá áááᢠá áá ááᣠá á³á²áµ ášá áá®ááµ ááá¶áœ á macOS ášáµááá± áá ášááášáµ á°ášá᪠á¥á á ááášááá¢
ááá: hab.com
