Last active
February 14, 2024 02:13
-
-
Save Brandon7CC/14cd97458629ca045774cb767d476e59 to your computer and use it in GitHub Desktop.
Hook the CoreAnalytics sendEvent function call made by endpointsecurityd to uncover event subscriptions.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Author: Brandon Dalton (Red Canary Threat Research) | |
Date: 2023-12-07 | |
Summary: This script attempts to instrument the `sendEvent:event:` method of the ESCoreAnalytics class. | |
- Download this script | |
- Target: You're targeting `endpointsecurityd`, so grab its PID: `sudo launchctl list | grep endpointsecurityd` | |
- To run: `sudo frida -p $PID -l es_coreanalytics_event_subs.js` | |
*/ | |
const eventTypeMapping = { | |
// Complete mapping based on es_event_type_t enumeration | |
0: 'ES_EVENT_TYPE_AUTH_EXEC', | |
1: 'ES_EVENT_TYPE_AUTH_OPEN', | |
2: 'ES_EVENT_TYPE_AUTH_KEXTLOAD', | |
3: 'ES_EVENT_TYPE_AUTH_MMAP', | |
4: 'ES_EVENT_TYPE_AUTH_MPROTECT', | |
5: 'ES_EVENT_TYPE_AUTH_MOUNT', | |
6: 'ES_EVENT_TYPE_AUTH_RENAME', | |
7: 'ES_EVENT_TYPE_AUTH_SIGNAL', | |
8: 'ES_EVENT_TYPE_AUTH_UNLINK', | |
9: 'ES_EVENT_TYPE_NOTIFY_EXEC', | |
10: 'ES_EVENT_TYPE_NOTIFY_OPEN', | |
11: 'ES_EVENT_TYPE_NOTIFY_FORK', | |
12: 'ES_EVENT_TYPE_NOTIFY_CLOSE', | |
13: 'ES_EVENT_TYPE_NOTIFY_CREATE', | |
14: 'ES_EVENT_TYPE_NOTIFY_EXCHANGEDATA', | |
15: 'ES_EVENT_TYPE_NOTIFY_EXIT', | |
16: 'ES_EVENT_TYPE_NOTIFY_GET_TASK', | |
17: 'ES_EVENT_TYPE_NOTIFY_KEXTLOAD', | |
18: 'ES_EVENT_TYPE_NOTIFY_KEXTUNLOAD', | |
19: 'ES_EVENT_TYPE_NOTIFY_LINK', | |
20: 'ES_EVENT_TYPE_NOTIFY_MMAP', | |
21: 'ES_EVENT_TYPE_NOTIFY_MPROTECT', | |
22: 'ES_EVENT_TYPE_NOTIFY_MOUNT', | |
23: 'ES_EVENT_TYPE_NOTIFY_UNMOUNT', | |
24: 'ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN', | |
25: 'ES_EVENT_TYPE_NOTIFY_RENAME', | |
26: 'ES_EVENT_TYPE_NOTIFY_SETATTRLIST', | |
27: 'ES_EVENT_TYPE_NOTIFY_SETEXTATTR', | |
28: 'ES_EVENT_TYPE_NOTIFY_SETFLAGS', | |
29: 'ES_EVENT_TYPE_NOTIFY_SETMODE', | |
30: 'ES_EVENT_TYPE_NOTIFY_SETOWNER', | |
31: 'ES_EVENT_TYPE_NOTIFY_SIGNAL', | |
32: 'ES_EVENT_TYPE_NOTIFY_UNLINK', | |
33: 'ES_EVENT_TYPE_NOTIFY_WRITE', | |
34: 'ES_EVENT_TYPE_AUTH_FILE_PROVIDER_MATERIALIZE', | |
35: 'ES_EVENT_TYPE_NOTIFY_FILE_PROVIDER_MATERIALIZE', | |
36: 'ES_EVENT_TYPE_AUTH_FILE_PROVIDER_UPDATE', | |
37: 'ES_EVENT_TYPE_NOTIFY_FILE_PROVIDER_UPDATE', | |
38: 'ES_EVENT_TYPE_AUTH_READLINK', | |
39: 'ES_EVENT_TYPE_NOTIFY_READLINK', | |
40: 'ES_EVENT_TYPE_AUTH_TRUNCATE', | |
41: 'ES_EVENT_TYPE_NOTIFY_TRUNCATE', | |
42: 'ES_EVENT_TYPE_AUTH_LINK', | |
43: 'ES_EVENT_TYPE_NOTIFY_LOOKUP', | |
44: 'ES_EVENT_TYPE_AUTH_CREATE', | |
45: 'ES_EVENT_TYPE_AUTH_SETATTRLIST', | |
46: 'ES_EVENT_TYPE_AUTH_SETEXTATTR', | |
47: 'ES_EVENT_TYPE_AUTH_SETFLAGS', | |
48: 'ES_EVENT_TYPE_AUTH_SETMODE', | |
49: 'ES_EVENT_TYPE_AUTH_SETOWNER', | |
50: 'ES_EVENT_TYPE_AUTH_CHDIR', | |
51: 'ES_EVENT_TYPE_NOTIFY_CHDIR', | |
52: 'ES_EVENT_TYPE_AUTH_GETATTRLIST', | |
53: 'ES_EVENT_TYPE_NOTIFY_GETATTRLIST', | |
54: 'ES_EVENT_TYPE_NOTIFY_STAT', | |
55: 'ES_EVENT_TYPE_NOTIFY_ACCESS', | |
56: 'ES_EVENT_TYPE_AUTH_CHROOT', | |
57: 'ES_EVENT_TYPE_NOTIFY_CHROOT', | |
58: 'ES_EVENT_TYPE_AUTH_UTIMES', | |
59: 'ES_EVENT_TYPE_NOTIFY_UTIMES', | |
60: 'ES_EVENT_TYPE_AUTH_CLONE', | |
61: 'ES_EVENT_TYPE_NOTIFY_CLONE', | |
62: 'ES_EVENT_TYPE_NOTIFY_FCNTL', | |
63: 'ES_EVENT_TYPE_AUTH_GETEXTATTR', | |
64: 'ES_EVENT_TYPE_NOTIFY_GETEXTATTR', | |
65: 'ES_EVENT_TYPE_AUTH_LISTEXTATTR', | |
66: 'ES_EVENT_TYPE_NOTIFY_LISTEXTATTR', | |
67: 'ES_EVENT_TYPE_AUTH_READDIR', | |
68: 'ES_EVENT_TYPE_NOTIFY_READDIR', | |
69: 'ES_EVENT_TYPE_AUTH_DELETEEXTATTR', | |
70: 'ES_EVENT_TYPE_NOTIFY_DELETEEXTATTR', | |
71: 'ES_EVENT_TYPE_AUTH_FSGETPATH', | |
72: 'ES_EVENT_TYPE_NOTIFY_FSGETPATH', | |
73: 'ES_EVENT_TYPE_NOTIFY_DUP', | |
74: 'ES_EVENT_TYPE_AUTH_SETTIME', | |
75: 'ES_EVENT_TYPE_NOTIFY_SETTIME', | |
76: 'ES_EVENT_TYPE_NOTIFY_UIPC_BIND', | |
77: 'ES_EVENT_TYPE_AUTH_UIPC_BIND', | |
78: 'ES_EVENT_TYPE_NOTIFY_UIPC_CONNECT', | |
79: 'ES_EVENT_TYPE_AUTH_UIPC_CONNECT', | |
80: 'ES_EVENT_TYPE_AUTH_EXCHANGEDATA', | |
81: 'ES_EVENT_TYPE_AUTH_SETACL', | |
82: 'ES_EVENT_TYPE_NOTIFY_SETACL', | |
83: 'ES_EVENT_TYPE_NOTIFY_PTY_GRANT', | |
84: 'ES_EVENT_TYPE_NOTIFY_PTY_CLOSE', | |
85: 'ES_EVENT_TYPE_AUTH_PROC_CHECK', | |
86: 'ES_EVENT_TYPE_NOTIFY_PROC_CHECK', | |
87: 'ES_EVENT_TYPE_AUTH_GET_TASK', | |
88: 'ES_EVENT_TYPE_AUTH_SEARCHFS', | |
89: 'ES_EVENT_TYPE_NOTIFY_SEARCHFS', | |
90: 'ES_EVENT_TYPE_AUTH_FCNTL', | |
91: 'ES_EVENT_TYPE_AUTH_IOKIT_OPEN', | |
92: 'ES_EVENT_TYPE_AUTH_PROC_SUSPEND_RESUME', | |
93: 'ES_EVENT_TYPE_NOTIFY_PROC_SUSPEND_RESUME', | |
94: 'ES_EVENT_TYPE_NOTIFY_CS_INVALIDATED', | |
95: 'ES_EVENT_TYPE_NOTIFY_GET_TASK_NAME', | |
96: 'ES_EVENT_TYPE_NOTIFY_TRACE', | |
97: 'ES_EVENT_TYPE_NOTIFY_REMOTE_THREAD_CREATE', | |
98: 'ES_EVENT_TYPE_AUTH_REMOUNT', | |
99: 'ES_EVENT_TYPE_NOTIFY_REMOUNT', | |
100: 'ES_EVENT_TYPE_AUTH_GET_TASK_READ', | |
101: 'ES_EVENT_TYPE_NOTIFY_GET_TASK_READ', | |
102: 'ES_EVENT_TYPE_NOTIFY_GET_TASK_INSPECT', | |
103: 'ES_EVENT_TYPE_NOTIFY_SETUID', | |
104: 'ES_EVENT_TYPE_NOTIFY_SETGID', | |
105: 'ES_EVENT_TYPE_NOTIFY_SETEUID', | |
106: 'ES_EVENT_TYPE_NOTIFY_SETEGID', | |
107: 'ES_EVENT_TYPE_NOTIFY_SETREUID', | |
108: 'ES_EVENT_TYPE_NOTIFY_SETREGID', | |
109: 'ES_EVENT_TYPE_AUTH_COPYFILE', | |
110: 'ES_EVENT_TYPE_NOTIFY_COPYFILE', | |
111: 'ES_EVENT_TYPE_NOTIFY_AUTHENTICATION', | |
112: 'ES_EVENT_TYPE_NOTIFY_XP_MALWARE_DETECTED', | |
113: 'ES_EVENT_TYPE_NOTIFY_XP_MALWARE_REMEDIATED', | |
114: 'ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGIN', | |
115: 'ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGOUT', | |
116: 'ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOCK', | |
117: 'ES_EVENT_TYPE_NOTIFY_LW_SESSION_UNLOCK', | |
118: 'ES_EVENT_TYPE_NOTIFY_SCREENSHARING_ATTACH', | |
119: 'ES_EVENT_TYPE_NOTIFY_SCREENSHARING_DETACH', | |
120: 'ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGIN', | |
121: 'ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGOUT', | |
122: 'ES_EVENT_TYPE_NOTIFY_LOGIN_LOGIN', | |
123: 'ES_EVENT_TYPE_NOTIFY_LOGIN_LOGOUT', | |
124: 'ES_EVENT_TYPE_NOTIFY_BTM_LAUNCH_ITEM_ADD', | |
125: 'ES_EVENT_TYPE_NOTIFY_BTM_LAUNCH_ITEM_REMOVE', | |
126: 'ES_EVENT_TYPE_NOTIFY_PROFILE_ADD', | |
127: 'ES_EVENT_TYPE_NOTIFY_PROFILE_REMOVE', | |
128: 'ES_EVENT_TYPE_NOTIFY_SU', | |
129: 'ES_EVENT_TYPE_NOTIFY_AUTHORIZATION_PETITION', | |
130: 'ES_EVENT_TYPE_NOTIFY_AUTHORIZATION_JUDGEMENT', | |
131: 'ES_EVENT_TYPE_NOTIFY_SUDO', | |
132: 'ES_EVENT_TYPE_NOTIFY_OD_GROUP_ADD', | |
133: 'ES_EVENT_TYPE_NOTIFY_OD_GROUP_REMOVE', | |
134: 'ES_EVENT_TYPE_NOTIFY_OD_GROUP_SET', | |
135: 'ES_EVENT_TYPE_NOTIFY_OD_MODIFY_PASSWORD', | |
136: 'ES_EVENT_TYPE_NOTIFY_OD_DISABLE_USER', | |
137: 'ES_EVENT_TYPE_NOTIFY_OD_ENABLE_USER', | |
138: 'ES_EVENT_TYPE_NOTIFY_OD_ATTRIBUTE_VALUE_ADD', | |
139: 'ES_EVENT_TYPE_NOTIFY_OD_ATTRIBUTE_VALUE_REMOVE', | |
140: 'ES_EVENT_TYPE_NOTIFY_OD_ATTRIBUTE_SET', | |
141: 'ES_EVENT_TYPE_NOTIFY_OD_CREATE_USER', | |
142: 'ES_EVENT_TYPE_NOTIFY_OD_CREATE_GROUP', | |
143: 'ES_EVENT_TYPE_NOTIFY_OD_DELETE_USER', | |
144: 'ES_EVENT_TYPE_NOTIFY_OD_DELETE_GROUP', | |
145: 'ES_EVENT_TYPE_NOTIFY_XPC_CONNECT', | |
146: 'ES_EVENT_TYPE_LAST' | |
}; | |
if (ObjC.available) { | |
try { | |
const ESCoreAnalytics = ObjC.classes.ESCoreAnalytics; | |
const sendEvent_event_ = ESCoreAnalytics['- sendEvent:event:']; | |
Interceptor.attach(sendEvent_event_.implementation, { | |
onEnter: function (args) { | |
console.log('[+] sendEvent:event: entered'); | |
// Interpreting 'event' as an NSDictionary | |
const eventDict = new ObjC.Object(args[3]); | |
console.log(' Endpoint Security Event subscription details:'); | |
const keys = eventDict.allKeys(); | |
for (let i = 0; i < keys.count(); i++) { | |
const key = keys.objectAtIndex_(i); | |
const value = eventDict.objectForKey_(key); | |
if (value !== null && typeof value.toString === 'function') { | |
let valueString = value.toString(); | |
// Resolve EventType to a readable format | |
if (key.toString() === 'EventType' && eventTypeMapping[valueString]) { | |
// `eventTypeMapping` is discussed below | |
valueString = eventTypeMapping[valueString] + ` (${valueString})`; | |
} | |
console.log(` ${key.toString()}: ${valueString}`); | |
} else { | |
console.log(` ${key.toString()}: <null or undefined>`); | |
} | |
} | |
} | |
}); | |
} catch (e) { | |
console.error(e); | |
} | |
} else { | |
console.error('Objective-C runtime not found...'); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
What does the end result look like? Notice that simply by pivoting off of the method's arguments with
ObjC.Object(args[3])
we were able to read the dictionary being sent across to CoreAnalytics. In this case, we can see some incredible detail:sysext
(System Extension)ES_EVENT_TYPE_NOTIFY_AUTHORIZATION_PETITION
in this case which has ID: 129com.redcanary.agent.securityextension
UA6JCQGF3F
1c2dc75b5d568ddf7981179a8482d7b1c383d5e