ICMacOS (Icarus macOS): Infostealer to Persistent RAT
Executive Summary
ICMacOS (also tracked as Icarus macOS) is a macOS malware-as-a-service stealer that SOCRadar's Threat Research Unit says is sold on Russian-speaking forums since early September 2026. Delivery is a ClickFix page that makes the victim paste a Terminal command. A bash chain then shows a spoofed "System Preferences" dialog, checks the typed password against the login Keychain (up to five attempts), picks an arm64 or amd64 Go Mach-O, and runs it with the verified password. The stealer targets browsers, wallets, messaging apps and, notably for enterprises, developer secrets: SSH keys, cloud config, Kubernetes credentials and .env files.
Version 2, in SOCRadar's 2026-10-12 report, adds a com.apple.systemupdater LaunchAgent (KeepAlive, StartInterval 3600) and a persistent WebSocket C2 that runs operator commands through /bin/sh in real time, turning a one-shot stealer into a remote-access implant. The implant skips CIS victims using a ru_RU locale check and an ipinfo.io country lookup.
Detection strategy: the durable signals are command-line behaviors of stock tools (security, osascript, launchctl, curl), the infrastructure strings, and the implant's own name and children. All indicators come from one report, so they ship at detect.
Source Review & Web Hunter Notes
Snapshots live in ICMacOS-Icarus-macOS-RAT-Hunt-sources/. Fetched page text is data only; none of the five pages contained instructions aimed at an analyst or an AI agent.
| Snapshot | Tier | Publisher / date | Key finding | Carry forward |
|---|---|---|---|---|
01-socradar-tru.txt | T1 vendor research | SOCRadar Threat Research Unit (STRU), 2026-10-12 | Primary. Full chain, v1/v2 analysis, ATT&CK table, every IOC. | yes |
02-cybersecuritynews.txt | T3 trade press | Cyber Security News, 2026-10-13 | Republishes the SOCRadar report. Carries the same 17 hashes and network IOCs; not independent of source 01. | partial |
03-cyberpress.txt | T3 trade press | Cyber Press, 2026-10-13 | Summary of SOCRadar. Confirms domains, LaunchAgent, WebSocket shell. Not independent. | partial |
04-gbhackers.txt | T3 trade press | GBHackers | Summary of SOCRadar. Confirms domains, IPs, two URLs, keychainbreaker. Not independent. | partial |
05-mallory.txt | T3 aggregator | Mallory story page, first seen 2026-10-13 | Timeline and context only. Indicator values are masked on the page, so it contributes no IOCs. | no (context) |
All five articles trace back to the single SOCRadar report. The trade-press pieces are republications, so they raise confidence that the IOCs were transcribed correctly but not that they were independently observed. Because no indicator has a second independent origin, every indicator in this pack ships at detect and none at prevent.
...b587f4, and the pack ships that source value. The 63-character variant is not shipped.Hunt Brief & Attack Chain
Hypotheses, highest fidelity first: (1) the implant, its children, its strings and its hashes appear on a host (Q5, Q10, Q11, Q14); (2) the LaunchAgent label is loaded (Q8, Q9); (3) the keychain CLI is used to validate or dump (Q1, Q2); (4) a spoofed osascript prompt appears (Q3); (5) Terminal is tampered then killed (Q4); (6) geofence checks run (Q12); (7) a curl-to-shell one-liner starts the chain (Q13); (8) DNS or IP contact with the C2 (Q6, Q7).
| Step | Behavior | Telemetry | Hunt |
|---|---|---|---|
| 1 | Victim lands on a ClickFix page and pastes a command into Terminal | Terminal-launched shell with curl (macOS process creation with command line; CrowdStrike: ProcessRollup2. SentinelOne: Process Creation. Defender: DeviceProcessEvents) | Q13, Q5 |
| 2 | Dropper saved to /tmp from escapeai[.]live/icmacos_run_v2[.]command, run with build and owner parameters | DNS lookup with requesting process (CrowdStrike: DnsRequest. SentinelOne: DNS Resolved. Defender: DeviceEvents) and process creation | Q5, Q6 |
| 3 | Terminal preferences altered; fake System Preferences dialog via osascript; password validated with unlock-keychain, up to 5 tries | Process creation with command line | Q3, Q4, Q1 |
| 4 | uname -m chooses arm64 or amd64; Mach-O downloaded to /tmp/.update-tmp/ICMacOs.gz and run with nohup; killall Terminal; fake error shown | Process creation, outbound network connection (CrowdStrike: NetworkConnectIP4. SentinelOne: IP Connect. Defender: DeviceNetworkEvents) | Q10, Q4, Q7 |
| 5 | Geofence (ru_RU, ipinfo.io country), then theft: Keychain, browsers, wallets, developer secrets, messaging, notes, VPN, files | Process creation for the CLI parts; file reads are outside the verified event set | Q12, Q1, Q2; gap for file reads |
| 6 | Archive in /tmp (for example .systemd-private-helper.zip) POSTed to /upload | Outbound connection and DNS; archive creation is a file event not verified for macOS | Q6, Q7; gap for archive |
| 7 | v2 only: pgrep/kill of older instances, root or wheel check, LaunchAgent written and launchctl bootstrap | Process creation with command line | Q8, Q9, Q10 |
| 8 | v2 only: WebSocket C2 to wss[://]escapeai[.]live/ws, operator commands run through /bin/sh | Process creation with parent name, outbound connection, DNS | Q11, Q6, Q7 |
Consolidated IOC Table
Fanged values appear only in the import CSV and the queries. Everything below is from SOCRadar (snapshot 01), with the same values repeated by the trade press where noted.
| Type | Value | Confidence | Action | Context |
|---|---|---|---|---|
| Domain | escapeai[.]live | medium | detect | Primary C2, dropper and payload delivery, config, upload, WebSocket. In 01, 02, 03, 04. |
| Domain | mikoblico[.]xyz | medium | detect | Labelled "ICMacOS Login" in the SOCRadar table. In 01, 02, 03, 04. |
| IPv4 | 85.137.253[.]61 | medium | detect | Labelled "ICMacOS Login". In 01, 04. |
| IPv4 | 45.13.186[.]247 | medium | detect | Labelled "ICMacOS Login". In 01, 04. |
| URL | hxxps[://]escapeai[.]live/icmacos_run_v2[.]command?t={date} | medium | detect | Dropper download |
| URL | hxxp[://]escapeai[.]live/loader_v2[.]sh?build={build_name}&owner={owner} | medium | detect | Loader (listed by SOCRadar, 01, 02) |
| URL | hxxps[://]escapeai[.]live/ICMacOs?arch=arm64 and ?arch=amd64 | medium | detect | Mach-O delivery by CPU architecture |
| URL | hxxps[://]escapeai[.]live/payload[.]py | medium | detect | Python supplementary payload |
| URL | hxxps[://]escapeai[.]live/api/build_config | medium | detect | Per-build config and fake error text |
| URL | hxxps[://]escapeai[.]live/upload | medium | detect | HTTPS POST multipart/form-data exfiltration |
| URL | wss[://]escapeai[.]live/ws?mac_id={hostname}&username={username} | medium | detect | Version 2 WebSocket C2 |
| Path | /tmp/.update-helper.log | medium | hunt | Dropper log |
| Path | /tmp/.cache-update.log | medium | hunt | Stealer log |
| Path | /tmp/.update-tmp/ICMacOs.gz | medium | hunt | Staged compressed payload |
| Path | /tmp/.systemd-private-helper.zip | low | hunt | Example name of the hidden loot archive (SOCRadar says "e.g.") |
| Path | ~/Library/LaunchAgents/com.apple.systemupdater.plist | medium | detect | v2 persistence. Label com.apple.systemupdater, KeepAlive, StartInterval 3600 |
| SHA-256 | 11 dropper script hashes | medium | detect | In the CSV in section 10. Scripts, not stock binaries. |
| SHA-256 | 3 Mach-O v1 hashes | medium | detect | In the CSV in section 10 |
| SHA-256 | 2 Mach-O v2 hashes | medium | detect | In the CSV in section 10. See note on one corrected value below. |
| SHA-256 | 1 Python payload hash | medium | detect | In the CSV in section 10 |
Affected Surface & Telemetry Matrix
| Surface | Telemetry | Priority | Gap |
|---|---|---|---|
| macOS process execution (command line, image path, parent) | Process creation with command line, path and parent (CrowdStrike: ProcessRollup2, SyntheticProcessRollup2. SentinelOne: Process Creation. Defender: DeviceProcessEvents) | High | None for the CLI steps. Scripts passed over stdin or files hide their text. |
| Name resolution | DNS lookup with the requesting process (CrowdStrike: DnsRequest. SentinelOne: DNS Resolved. Defender: DeviceEvents) | High | Lookups resolved only inside the browser may not be attributed. Encrypted DNS bypasses the sensor view. |
| Outbound network | Outbound connection (CrowdStrike: NetworkConnectIP4. SentinelOne: IP Connect. Defender: DeviceNetworkEvents) | High | TLS content, WebSocket frames and the upload body are outside endpoint telemetry. |
| Persistence file writes | File creation by process (CrowdStrike: file-write events. SentinelOne: File Creation. Defender: DeviceFileEvents) | Medium | The plist is written by the Go implant, so no process-creation event exists. Only the launchctl step is covered here; file-write event names for macOS are not verified in the pack's references. |
| Keychain and credential files | File read telemetry | Low | Outside endpoint telemetry for this pack: offline keychainbreaker parsing of login.keychain-db, and reads of .ssh, .aws, .kube, .env* and browser stores generate no process event. |
| Identity and cloud | Cloud, VCS and SaaS audit logs | High priority, outside endpoint telemetry | Stolen SSH, cloud, Kubernetes, Git and session tokens are used from other hosts, so detection moves to those logs. |
ATT&CK Mapping
| Tactic | Technique | Name | Observed behavior | Hunt |
|---|---|---|---|---|
| Execution | T1204.004 | User Execution: Malicious Copy and Paste | ClickFix page makes the victim paste a Terminal command | Q13, Q5 |
| Execution | T1059.004 | Unix Shell | Bash dropper chain, then /bin/sh remote shell in v2 | Q5, Q10, Q11 |
| Execution | T1059.002 | AppleScript | osascript spawns the fake dialog and launches the payload with nohup | Q3 |
| Execution | T1059.006 | Python | Supplementary payload.py (VPN, Slack/Signal/Zoom, filegrabber) | Q5 (fetch), gap on execution |
| Persistence | T1543.001 | Launch Agent | com.apple.systemupdater.plist, KeepAlive, StartInterval 3600 | Q8, Q9 |
| Stealth | T1036.005 | Masquerading | Apple-like label to blend into launchctl list | Q8, Q9 |
| Stealth | T1480 | Execution Guardrails | locale ru_RU and ipinfo.io country check | Q12 |
| Stealth | T1564 | Hide Artifacts | com.apple.Terminal preference edits, killall Terminal, hidden /tmp files | Q4 |
| Privilege Escalation | T1548 | Abuse Elevation Control Mechanism | AppleScript with administrator privileges | Q3 |
| Credential Access | T1056.002 | GUI Input Capture | Fake System Preferences password dialog | Q3 |
| Credential Access | T1555.001 | Keychain | unlock-keychain -p validation, dump-keychain -d, offline keychainbreaker parse | Q1 (CLI only) |
| Credential Access | T1555.003 | Credentials from Web Browsers | Safe Storage key read, Login Data and Cookies copy | Q2 (key read only) |
| Credential Access | T1555.005 | Password Managers | Password manager app and extension data | Gap |
| Credential Access | T1552.001 | Credentials In Files | SSH keys, .aws, .kube, .docker, .env* recursive search | Gap |
| Credential Access | T1552.003 | Shell History | .zsh_history, .bash_history and others | Gap |
| Discovery | T1082 / T1083 / T1057 / T1033 | System, File, Process, User discovery | system_profiler, sysctl, sw_vers, pgrep ICMACOS, root/wheel check | Q11 (child processes) |
| Collection | T1115 | Clipboard Data | pbpaste at execution time | Q11 |
| Collection | T1005 / T1119 / T1213 / T1560 | Local data, automated collection, archive | Wallet and extension stores, filegrabber, hidden ZIP in /tmp | Gap (file telemetry) |
| Exfiltration | T1048.002 / T1567 | HTTPS POST to escapeai[.]live/upload | multipart/form-data over HTTPS | Q6, Q7, Q5 |
| Command and Control | T1071.001 | Web Protocols | Gorilla WebSocket client to wss://escapeai[.]live/ws | Q6, Q7 |
Native Audit-Log Hunts
Run these on a suspect Mac (or through MDM). All are read-only.
# 1. Persistence: Apple-labelled agents in the user folder, and the specific label ls -la ~/Library/LaunchAgents/ | grep -i "com.apple." launchctl print gui/$(id -u)/com.apple.systemupdater 2>&1 | head -20 plutil -p ~/Library/LaunchAgents/com.apple.systemupdater.plist 2>&1 # 2. Hidden staging and log artifacts ls -la /tmp/.update-helper.log /tmp/.cache-update.log /tmp/.systemd-private-helper.zip /tmp/.update-tmp 2>&1 # 3. Hash any binary found (compare to the Mach-O rows in section 10) shasum -a 256 /tmp/.update-tmp/* 2>/dev/null # 4. Live network: who is talking to the C2 host lsof -nP -i 2>/dev/null | grep -i -E "ICMacOs|escapeai" # 5. Unified log: privileged AppleScript and keychain CLI use in the last day log show --last 1d --predicate 'process == "osascript" OR eventMessage CONTAINS "unlock-keychain" OR eventMessage CONTAINS "systemupdater"' --style compact | head -100
- Proxy and DNS logs: search 30 days for
escapeai[.]liveandmikoblico[.]xyz, paying attention to/ws,/uploadand/ICMacOs?arch=paths in proxy logs. - Cloud and VCS audit logs (stolen developer secrets): for any confirmed host, review AWS CloudTrail, Kubernetes audit, Git hosting audit and SSH bastion logs for use of that user's keys from new source addresses after the infection time.
- Identity provider: new sessions, token grants and MFA changes for the user after infection.
Hunt Queries: CrowdStrike CQL, SentinelOne PowerQuery and Defender XDR KQL
Use your tenant's own address. SentinelOne does not document a link that pre-fills a query, so each "Copy & open SentinelOne" button copies the query and opens this console: paste it into PowerQuery.
Pick your portal. Microsoft documents a Share link in advanced hunting but not its URL format, so each "Copy & open Defender" button copies the query and opens Advanced hunting: paste it into the editor.
Event names used: ProcessRollup2, SyntheticProcessRollup2, DnsRequest, NetworkConnectIP4, all present in the crowdstrike-logscale-v3 event reference. event_platform=Mac scopes process queries to macOS. Set the time window in the console; LOOKBACK comments record intent.
Looks for: The dropper validates the phished password with security unlock-keychain -p (up to five tries) and the stealer falls back to security dump-keychain -d. T1555.001.
FP: Build agents that unlock a code-signing keychain with -p (fastlane, xcodebuild wrappers, CI runners). Exclude by service account or parent; keep interactive-user hits in scope.
Known limitations and deployment notes
- PowerQuery: A keychain command run by a process the agent did not observe starting is not captured.
- PowerQuery assumes: src.process.user holds the account that ran the creating process.
- PowerQuery assumes: tgt.process.cmdline holds the full argument string of the created process.
- KQL – Defender XDR: A keychain command run by a process the sensor did not observe starting is not captured.
- KQL – Defender XDR assumes: The query carries no operating-system filter; the security binary name is macOS specific.
- KQL – Defender XDR assumes: ProcessCommandLine holds the full argument string.
// HUNT: macOS keychain password validation or dump via the security CLI // MITRE: T1555.001 // CONF: high FP: medium COST: low | REQUIRES: macOS process creation with command line // LOOKBACK: 7d // TUNING: exclude CI service accounts that unlock a build keychain, e.g. add | UserName!=/^(jenkins|buildkite|runner)$/i after the CommandLine filter. A user-context dump-keychain -d has almost no benign use and should stay in scope. #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | event_platform=Mac | FileName=/^security$/i | CommandLine=/unlock-keychain\s+(\S+\s+)*-p\s|dump-keychain\s+(\S+\s+)*-d/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, ImageFileName, CommandLine])
4 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.type: Event typeevent.time: Event timetgt.process.name: Created process nametgt.process.cmdline: Created command line
Recommended fields
src.process.name: Creating process
Optional fields
src.process.user: Account
Readiness test
event.type = 'Process Creation' tgt.process.name = * | limit 5 | columns event.time, tgt.process.name, tgt.process.cmdline
// HUNT: macOS keychain password validation or dump via the security CLI
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1555.001
// CONF: high | FP: medium
// EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: the security binary by name with the unlock-keychain -p or dump-keychain -d argument pattern. matches is case-insensitive, which reproduces the CQL /i intent. The new process is tgt.process.*.
// REQUIRES: SentinelOne process-creation events with command line from macOS agents
// TUNING: Exclude CI service accounts that unlock a build keychain after a baseline review. A user-context dump-keychain -d has almost no benign use and should stay in scope.
// LOOKBACK: 7d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A keychain command run by a process the agent did not observe starting is not captured.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation' tgt.process.name in:anycase ('security') tgt.process.cmdline matches 'unlock-keychain\\s+(\\S+\\s+)*-p\\s|dump-keychain\\s+(\\S+\\s+)*-d'
| sort -event.time
| limit 200
| columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdlineAutomated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeFileName: Created process nameProcessCommandLine: Created command line
Recommended fields
InitiatingProcessFileName: Initiating process
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp, FileName, ProcessCommandLine | take 5
// HUNT: macOS keychain password validation or dump via the security CLI // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1555.001 // CONF: high | FP: medium // EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: the security binary by name with the unlock-keychain -p or dump-keychain -d pattern. The regex carries (?i) to keep the CQL /i intent. // REQUIRES: Defender for Endpoint process-creation telemetry from macOS devices (DeviceProcessEvents) // TUNING: Exclude CI service accounts that unlock a build keychain after a baseline review. // LOOKBACK: 7d; extend to 30d for the incident window // CONFIGURATION: No lookup objects required. // KNOWN GAPS: A keychain command run by a process the sensor did not observe starting is not captured. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceProcessEvents | where Timestamp >= ago(7d) | where FileName =~ "security" | where ProcessCommandLine matches regex @"(?i)unlock-keychain\\s+(\\S+\\s+)*-p\\s|dump-keychain\\s+(\\S+\\s+)*-d" | project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FolderPath, ProcessCommandLine | sort by Timestamp desc | take 200
Looks for: Chromium-family master key extraction with security find-generic-password -w ... "<Browser> Safe Storage". T1555.003.
FP: Rare password-recovery or migration tools, and developers testing browser automation. Baseline per fleet for a week.
Known limitations and deployment notes
- PowerQuery: A key read through the Security framework API rather than the command line tool is not captured.
- PowerQuery assumes: src.process.user holds the account that ran the creating process.
- KQL – Defender XDR: A key read through the Security framework API rather than the command line tool is not captured.
- KQL – Defender XDR assumes: The query carries no operating-system filter; the security binary name is macOS specific.
- KQL – Defender XDR assumes: ProcessCommandLine holds the full argument string.
// HUNT: browser Safe Storage key read through the security CLI // MITRE: T1555.003 // CONF: medium FP: medium COST: low | REQUIRES: macOS process creation with command line // LOOKBACK: 7d // TUNING: exclude known IT or forensics tooling by ParentBaseFileName once baselined. Browsers read their own key through the Security framework, not this CLI, so benign hits are uncommon. #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | event_platform=Mac | FileName=/^security$/i | CommandLine=/find-generic-password/i | CommandLine=/Safe\s+Storage/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, ImageFileName, CommandLine])
4 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.type: Event typeevent.time: Event timetgt.process.name: Created process nametgt.process.cmdline: Created command line
Recommended fields
src.process.name: Creating process
Optional fields
src.process.user: Account
Readiness test
event.type = 'Process Creation' tgt.process.name = * | limit 5 | columns event.time, tgt.process.name, tgt.process.cmdline
// HUNT: browser Safe Storage key read through the security CLI
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1555.003
// CONF: medium | FP: medium
// EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: the security binary reading a generic password whose arguments mention Safe Storage. matches is case-insensitive, which reproduces the CQL /i intent.
// REQUIRES: SentinelOne process-creation events with command line from macOS agents
// TUNING: Exclude known IT or forensics tooling by creating process name once baselined. Browsers read their own key through the Security framework, not this CLI, so benign hits are uncommon.
// LOOKBACK: 7d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A key read through the Security framework API rather than the command line tool is not captured.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation' tgt.process.name in:anycase ('security') tgt.process.cmdline contains 'find-generic-password' tgt.process.cmdline matches 'Safe\\s+Storage'
| sort -event.time
| limit 200
| columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdlineAutomated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeFileName: Created process nameProcessCommandLine: Created command line
Recommended fields
InitiatingProcessFileName: Initiating process
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp, FileName, ProcessCommandLine | take 5
// HUNT: browser Safe Storage key read through the security CLI // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1555.003 // CONF: medium | FP: medium // EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: the security binary with find-generic-password and a Safe Storage service name. Both string tests are case-insensitive. // REQUIRES: Defender for Endpoint process-creation telemetry from macOS devices (DeviceProcessEvents) // TUNING: Exclude known IT or forensics tooling by initiating process name once baselined. // LOOKBACK: 7d; extend to 30d for the incident window // CONFIGURATION: No lookup objects required. // KNOWN GAPS: A key read through the Security framework API rather than the command line tool is not captured. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceProcessEvents | where Timestamp >= ago(7d) | where FileName =~ "security" | where ProcessCommandLine contains "find-generic-password" | where ProcessCommandLine matches regex @"(?i)Safe\\s+Storage" | project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FolderPath, ProcessCommandLine | sort by Timestamp desc | take 200
Looks for: AppleScript launches the spoofed "System Preferences" password prompt and, as fallback, runs security dump-keychain -d through do shell script ... with administrator privileges. T1056.002, T1059.002, T1548. Only visible when the script text is on the command line (-e); a script passed through a file or stdin hides these strings.
FP: MDM agents and installers legitimately use with administrator privileges. Exclude by parent (jamf, mdm agent, installer) after baselining.
Known limitations and deployment notes
- PowerQuery: An AppleScript run from a script file rather than the command line is not captured when the prompt text is not in the arguments.
- PowerQuery assumes: src.process.user holds the account that ran the creating process.
- KQL – Defender XDR: An AppleScript run from a script file rather than the command line is not captured when the prompt text is not in the arguments.
- KQL – Defender XDR assumes: The query carries no operating-system filter; osascript is macOS specific.
- KQL – Defender XDR assumes: ProcessCommandLine holds the full argument string.
// HUNT: osascript spoofed System Preferences prompt or privileged keychain dump // MITRE: T1056.002, T1059.002, T1548 // CONF: medium FP: medium COST: low | REQUIRES: macOS process creation with command line // LOOKBACK: 7d // TUNING: exclude management agents with | ParentBaseFileName!=/^(jamf|Self Service|mdmclient|installer)$/i after baselining; keep any hit whose CommandLine also contains dump-keychain or hidden answer. #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | event_platform=Mac | FileName=/^osascript$/i | CommandLine=/System Preferences|hidden answer|with administrator privileges|dump-keychain/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, ImageFileName, CommandLine])
4 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.type: Event typeevent.time: Event timetgt.process.name: Created process nametgt.process.cmdline: Created command line
Recommended fields
src.process.name: Creating process
Optional fields
src.process.user: Account
Readiness test
event.type = 'Process Creation' tgt.process.name = * | limit 5 | columns event.time, tgt.process.name, tgt.process.cmdline
// HUNT: osascript spoofed System Preferences prompt or privileged keychain dump
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1056.002, T1059.002, T1548
// CONF: medium | FP: medium
// EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: osascript whose arguments carry a System Preferences prompt, a hidden answer field, an administrator-privileges request or dump-keychain. matches is case-insensitive, which reproduces the CQL /i intent.
// REQUIRES: SentinelOne process-creation events with command line from macOS agents
// TUNING: Exclude management agents by creating process name after baselining; keep any hit whose command line also contains dump-keychain or hidden answer.
// LOOKBACK: 7d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: An AppleScript run from a script file rather than the command line is not captured when the prompt text is not in the arguments.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation' tgt.process.name in:anycase ('osascript') tgt.process.cmdline matches 'System Preferences|hidden answer|with administrator privileges|dump-keychain'
| sort -event.time
| limit 200
| columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdlineAutomated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeFileName: Created process nameProcessCommandLine: Created command line
Recommended fields
InitiatingProcessFileName: Initiating process
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp, FileName, ProcessCommandLine | take 5
// HUNT: osascript spoofed System Preferences prompt or privileged keychain dump // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1056.002, T1059.002, T1548 // CONF: medium | FP: medium // EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: osascript with a System Preferences prompt, hidden answer, administrator-privileges request or dump-keychain in its arguments. contains is case-insensitive, which reproduces the CQL /i intent. // REQUIRES: Defender for Endpoint process-creation telemetry from macOS devices (DeviceProcessEvents) // TUNING: Exclude management agents by initiating process name after baselining. // LOOKBACK: 7d; extend to 30d for the incident window // CONFIGURATION: No lookup objects required. // KNOWN GAPS: An AppleScript run from a script file rather than the command line is not captured when the prompt text is not in the arguments. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceProcessEvents | where Timestamp >= ago(7d) | where FileName =~ "osascript" | where ProcessCommandLine contains "System Preferences" or ProcessCommandLine contains "hidden answer" or ProcessCommandLine contains "with administrator privileges" or ProcessCommandLine contains "dump-keychain" | project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FolderPath, ProcessCommandLine | sort by Timestamp desc | take 200
Looks for: The dropper alters com.apple.Terminal preferences to hide window titles and ends with killall Terminal to close the victim's window. SOCRadar does not state which tool writes the preference, so this covers defaults, plutil and PlistBuddy. T1564.
FP: Users styling Terminal with defaults write and IT scripts that restart Terminal. Alert on both behaviors from one host inside minutes, not on either alone.
Known limitations and deployment notes
- PowerQuery: The 10-minute pairing of a preference edit and killall Terminal is a tuning step and is not enforced by this query.
- PowerQuery assumes: src.process.user holds the account that ran the creating process.
- KQL – Defender XDR: The 10-minute pairing of a preference edit and killall Terminal is a tuning step and is not enforced by this query.
- KQL – Defender XDR assumes: The query carries no operating-system filter; these tools are macOS specific in this combination.
- KQL – Defender XDR assumes: ProcessCommandLine holds the full argument string.
// HUNT: com.apple.Terminal preference edits and killall Terminal // MITRE: T1564 // CONF: medium FP: medium COST: low | REQUIRES: macOS process creation with command line // LOOKBACK: 7d // TUNING: single hits are noisy. Raise to alert only when one aid shows both a Terminal preference edit and killall Terminal within 10 minutes, or exclude managed-config scripts by ParentBaseFileName. #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | event_platform=Mac | FileName=/^(defaults|plutil|PlistBuddy|killall)$/i | CommandLine=/com\.apple\.Terminal|killall\s+Terminal/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, ImageFileName, CommandLine])
4 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.type: Event typeevent.time: Event timetgt.process.name: Created process nametgt.process.cmdline: Created command line
Recommended fields
src.process.name: Creating process
Optional fields
src.process.user: Account
Readiness test
event.type = 'Process Creation' tgt.process.name = * | limit 5 | columns event.time, tgt.process.name, tgt.process.cmdline
// HUNT: com.apple.Terminal preference edits and killall Terminal
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1564
// CONF: medium | FP: medium
// EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: defaults, plutil, PlistBuddy or killall whose arguments name the com.apple.Terminal preferences or killall Terminal. The CQL names the file and domain-style literal verbatim; contains and matches are case-insensitive, reproducing the /i intent.
// REQUIRES: SentinelOne process-creation events with command line from macOS agents
// TUNING: Single hits are noisy. Raise to alert only when one host shows both a Terminal preference edit and killall Terminal within 10 minutes, or exclude managed-config scripts by creating process name.
// LOOKBACK: 7d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: The 10-minute pairing of a preference edit and killall Terminal is a tuning step and is not enforced by this query.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation' tgt.process.name in:anycase ('defaults', 'plutil', 'PlistBuddy', 'killall') (tgt.process.cmdline contains 'com.apple.Terminal' or tgt.process.cmdline matches 'killall\\s+Terminal')
| sort -event.time
| limit 200
| columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdlineAutomated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeFileName: Created process nameProcessCommandLine: Created command line
Recommended fields
InitiatingProcessFileName: Initiating process
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp, FileName, ProcessCommandLine | take 5
// HUNT: com.apple.Terminal preference edits and killall Terminal
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1564
// CONF: medium | FP: medium
// EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: defaults, plutil, PlistBuddy or killall with com.apple.Terminal or killall Terminal in the arguments.
// REQUIRES: Defender for Endpoint process-creation telemetry from macOS devices (DeviceProcessEvents)
// TUNING: Raise to alert only when one device shows both a Terminal preference edit and killall Terminal within 10 minutes.
// LOOKBACK: 7d; extend to 30d for the incident window
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: The 10-minute pairing of a preference edit and killall Terminal is a tuning step and is not enforced by this query.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceProcessEvents
| where Timestamp >= ago(7d)
| where FileName in~ ("defaults", "plutil", "PlistBuddy", "killall")
| where ProcessCommandLine contains "com.apple.Terminal" or ProcessCommandLine matches regex @"(?i)killall\\s+Terminal"
| project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FolderPath, ProcessCommandLine
| sort by Timestamp desc
| take 200Looks for: Any process whose command line carries the C2 host, the login domain, the dropper or loader names, the payload URL fragment or the hidden staging paths SOCRadar published.
FP: Near zero. A hit on a hunting or threat-intel host that merely queried the strings is the main benign case.
Known limitations and deployment notes
- PowerQuery: A string split across arguments or built at run time is not matched.
- PowerQuery assumes: The query carries no operating-system filter, so a matching command line on any agent platform is returned.
- PowerQuery assumes: The leading dot of .update-helper.log, .cache-update.log and .systemd-private-helper.zip is matched as an escaped group, as in the CQL.
- PowerQuery assumes: src.process.user holds the account that ran the creating process.
- KQL – Defender XDR: A string split across arguments or built at run time is not matched.
- KQL – Defender XDR assumes: The query carries no operating-system filter, so a matching command line on any device platform is returned.
- KQL – Defender XDR assumes: The leading dot of .update-helper.log, .cache-update.log and .systemd-private-helper.zip is matched as an escaped group, as in the CQL.
- KQL – Defender XDR assumes: ProcessCommandLine holds the full argument string.
// HUNT: published ICMacOS infrastructure and staging strings in command lines // MITRE: T1204.004, T1059.004, T1105 // CONF: high FP: low COST: low | REQUIRES: macOS process creation with command line // LOOKBACK: 7d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | event_platform=Mac | CommandLine=/escapeai\.live|mikoblico\.xyz|icmacos_run_v2|loader_v2\.sh|ICMacOs\?arch=|\.update-tmp|\.update-helper\.log|\.cache-update\.log|\.systemd-private-helper\.zip/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, ImageFileName, CommandLine])
3 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.type: Event typeevent.time: Event timetgt.process.cmdline: Created command line
Recommended fields
tgt.process.name: Created process namesrc.process.name: Creating process
Optional fields
src.process.user: Account
Readiness test
event.type = 'Process Creation' tgt.process.cmdline = * | limit 5 | columns event.time, tgt.process.name, tgt.process.cmdline
// HUNT: published ICMacOS infrastructure and staging strings in command lines // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1204.004, T1059.004, T1105 // CONF: high | FP: low // EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: any process whose command line carries one of the published ICMacOS domains or staging strings. Each alternative is a literal substring test, case-insensitive, which reproduces the CQL /i intent. // REQUIRES: SentinelOne process-creation events with command line from macOS agents // TUNING: None expected: the strings are specific to this campaign. // LOOKBACK: 7d // CONFIGURATION: No lookup objects required. // KNOWN GAPS: A string split across arguments or built at run time is not matched. // VALIDATION LEVEL: static-reviewed event.type = 'Process Creation' tgt.process.cmdline matches 'escapeai\\.live|mikoblico\\.xyz|icmacos_run_v2|loader_v2\\.sh|ICMacOs\\?arch=|\\.update-tmp|(\\.)update-helper\\.log|(\\.)cache-update\\.log|(\\.)systemd-private-helper\\.zip' | sort -event.time | limit 200 | columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdline
Automated validation: static-passed
2 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeProcessCommandLine: Created command line
Recommended fields
InitiatingProcessFileName: Initiating process
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp, ProcessCommandLine | take 5
// HUNT: published ICMacOS infrastructure and staging strings in command lines // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1204.004, T1059.004, T1105 // CONF: high | FP: low // EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: any command line carrying one of the published ICMacOS domains or staging strings, as case-insensitive substring tests. // REQUIRES: Defender for Endpoint process-creation telemetry (DeviceProcessEvents) // TUNING: None expected: the strings are specific to this campaign. // LOOKBACK: 7d; extend to 30d for the incident window // CONFIGURATION: No lookup objects required. // KNOWN GAPS: A string split across arguments or built at run time is not matched. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceProcessEvents | where Timestamp >= ago(7d) | where ProcessCommandLine matches regex @"(?i)escapeai\.live|mikoblico\.xyz|icmacos_run_v2|loader_v2\.sh|ICMacOs\?arch=|\.update-tmp|(\.)update-helper\.log|(\.)cache-update\.log|(\.)systemd-private-helper\.zip" | project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FileName, FolderPath, ProcessCommandLine | sort by Timestamp desc | take 200
Looks for: Resolution of escapeai.live (C2, delivery, upload) or mikoblico.xyz from any host, including subdomains. Pivot on ContextProcessId to the requesting process.
FP: Near zero outside research hosts. Lookups made inside the browser by the ClickFix page are visible here only if the sensor attributes them to the browser process.
Known limitations and deployment notes
- PowerQuery: The suffix anchoring of the CQL is replaced by a substring test.
- PowerQuery assumes: event.dns.request is the populated DNS name field on this tenant; the vendor docs name dns.request, so run the readiness test to see which is filled.
- PowerQuery assumes: The acting process on a DNS event is src.process.*.
- KQL – Defender XDR: The suffix anchoring of the CQL is replaced by a substring test.
- KQL – Defender XDR assumes: The DNS name is stored under DnsQueryString or QueryName inside AdditionalFields; the readiness test prints the raw field so you can see which key your tenant fills.
- KQL – Defender XDR assumes: DnsQueryResponse events are recorded for the monitored macOS devices.
// HUNT: DNS resolution of ICMacOS domains // MITRE: T1071.001, T1567 // CONF: high FP: low COST: low | REQUIRES: endpoint DNS request telemetry // LOOKBACK: 7d #event_simpleName=DnsRequest | DomainName=/(^|\.)(escapeai\.live|mikoblico\.xyz)$/i | table([@timestamp, aid, ComputerName, DomainName, ContextProcessId_decimal])
3 required fields · View requirements
Required telemetry
- DNS Resolved
Required fields
event.type: Event typeevent.time: Event timeevent.dns.request: Queried name
Recommended fields
src.process.name: Querying process
Fallbacks
event.dns.request→dns.request: Different tenants populate one or the other; the readiness test shows which.
Readiness test
event.type = 'DNS Resolved' event.dns.request = * | limit 5 | columns event.time, event.dns.request
// HUNT: DNS resolution of ICMacOS domains // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1071.001, T1567 // CONF: high | FP: low // EQUIVALENCE: equivalent-with-schema-assumptions - Same intent: a DNS resolution for either ICMacOS domain. The CQL anchors the name to the domain or a subdomain of it; this query uses a substring test, which can also match a longer name that merely contains the domain. // REQUIRES: SentinelOne DNS Resolved events from macOS agents // TUNING: None expected: both domains are specific to this campaign. // LOOKBACK: 7d // CONFIGURATION: No lookup objects required. // KNOWN GAPS: The suffix anchoring of the CQL is replaced by a substring test. // VALIDATION LEVEL: static-reviewed event.type = 'DNS Resolved' (event.dns.request contains 'escapeai.live' or event.dns.request contains 'mikoblico.xyz') | sort -event.time | limit 200 | columns event.time, endpoint.name, event.dns.request, src.process.name, src.process.pid
Automated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceEvents
Required fields
Timestamp: Event timeActionType: Event actionAdditionalFields: Event details
Recommended fields
InitiatingProcessFileName: Initiating process
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceEvents | where Timestamp > ago(1d) | where ActionType == "DnsQueryResponse" | project Timestamp, ActionType, AdditionalFields | take 5
// HUNT: DNS resolution of ICMacOS domains // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1071.001, T1567 // CONF: high | FP: low // EQUIVALENCE: equivalent-with-schema-assumptions - Same intent: a DNS resolution for either ICMacOS domain, read from DeviceEvents DnsQueryResponse. The name sits inside AdditionalFields, and the CQL suffix anchoring is replaced by a substring test. // REQUIRES: Defender for Endpoint DnsQueryResponse events in DeviceEvents // TUNING: None expected: both domains are specific to this campaign. // LOOKBACK: 7d; extend to 30d for the incident window // CONFIGURATION: No lookup objects required. // KNOWN GAPS: The suffix anchoring of the CQL is replaced by a substring test. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceEvents | where Timestamp >= ago(7d) | where ActionType == "DnsQueryResponse" | extend DnsName = tostring(coalesce(parse_json(AdditionalFields)["DnsQueryString"], parse_json(AdditionalFields)["QueryName"])) | where DnsName contains "escapeai.live" or DnsName contains "mikoblico.xyz" | project Timestamp, ReportId, DeviceId, DeviceName, DnsName, InitiatingProcessFileName, InitiatingProcessId | sort by Timestamp desc | take 200
Looks for: IPv4 connections to the two addresses SOCRadar lists under the login infrastructure. Shared hosting means an IP match alone needs the DNS or process corroboration before containment.
FP: Near zero today. Addresses can be reassigned, so the expiry on the Falcon IOC rows is six months.
Known limitations and deployment notes
- PowerQuery: Connections that go through a proxy show the proxy address, not the destination.
- PowerQuery assumes: dst.ip.address holds the remote address on IP Connect events.
- KQL – Defender XDR: Connections that go through a proxy show the proxy address, not the destination.
- KQL – Defender XDR assumes: RemoteIP holds the destination address for outbound connections.
// HUNT: outbound connection to published ICMacOS IP addresses // MITRE: T1071.001 // CONF: high FP: low COST: low | REQUIRES: endpoint network connection telemetry // LOOKBACK: 7d #event_simpleName=NetworkConnectIP4 | in(RemoteAddressIP4, values=["85.137.253.61", "45.13.186.247"]) | table([@timestamp, aid, ComputerName, ContextBaseFileName, RemoteAddressIP4, RemotePort, LocalAddressIP4])
3 required fields · View requirements
Required telemetry
- IP Connect
Required fields
event.type: Event typeevent.time: Event timedst.ip.address: Remote address
Recommended fields
src.process.name: Connecting processdst.port.number: Remote port
Optional fields
src.ip.address: Local address
Readiness test
event.type = 'IP Connect' dst.ip.address = * | limit 5 | columns event.time, dst.ip.address
// HUNT: outbound connection to published ICMacOS IP addresses
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1071.001
// CONF: high | FP: low
// EQUIVALENCE: equivalent-with-schema-assumptions - Same intent: an outbound connection to either published ICMacOS address. The acting process on a network event is src.process.*.
// REQUIRES: SentinelOne IP Connect events from macOS agents
// TUNING: None expected: both addresses are specific to this campaign.
// LOOKBACK: 7d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: Connections that go through a proxy show the proxy address, not the destination.
// VALIDATION LEVEL: static-reviewed
event.type = 'IP Connect' dst.ip.address in ('85.137.253.61', '45.13.186.247')
| sort -event.time
| limit 200
| columns event.time, endpoint.name, src.process.name, src.ip.address, dst.ip.address, dst.port.numberAutomated validation: static-passed
2 required fields · View requirements
Required telemetry
- DeviceNetworkEvents
Required fields
Timestamp: Event timeRemoteIP: Remote address
Recommended fields
InitiatingProcessFileName: Initiating processRemotePort: Remote port
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceNetworkEvents | where Timestamp > ago(1d) | project Timestamp, RemoteIP, RemotePort | take 5
// HUNT: outbound connection to published ICMacOS IP addresses
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1071.001
// CONF: high | FP: low
// EQUIVALENCE: equivalent-with-schema-assumptions - Same intent: an outbound connection to either published ICMacOS address, read from DeviceNetworkEvents.
// REQUIRES: Defender for Endpoint network telemetry (DeviceNetworkEvents)
// TUNING: None expected: both addresses are specific to this campaign.
// LOOKBACK: 7d; extend to 30d for the incident window
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: Connections that go through a proxy show the proxy address, not the destination.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceNetworkEvents
| where Timestamp >= ago(7d)
| where RemoteIP in ("85.137.253.61", "45.13.186.247")
| project Timestamp, ReportId, DeviceId, DeviceName, InitiatingProcessFileName, RemoteIP, RemotePort, LocalIP
| sort by Timestamp desc
| take 200Looks for: Version 2 registers its persistence with launchctl bootstrap gui/<uid> ~/Library/LaunchAgents/com.apple.systemupdater.plist. T1543.001, T1036.005.
FP: None expected: this label is not a shipped Apple job.
Known limitations and deployment notes
- PowerQuery: A LaunchAgent loaded by launchd at login without a launchctl command is not captured.
- PowerQuery assumes: src.process.user holds the account that ran the creating process.
- KQL – Defender XDR: A LaunchAgent loaded by launchd at login without a launchctl command is not captured.
- KQL – Defender XDR assumes: The query carries no operating-system filter; launchctl is macOS specific.
- KQL – Defender XDR assumes: ProcessCommandLine holds the full argument string.
// HUNT: launchctl referencing the com.apple.systemupdater persistence label // MITRE: T1543.001, T1036.005 // CONF: high FP: low COST: low | REQUIRES: macOS process creation with command line // LOOKBACK: 7d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | event_platform=Mac | FileName=/^launchctl$/i | CommandLine=/systemupdater/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, ImageFileName, CommandLine])
4 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.type: Event typeevent.time: Event timetgt.process.name: Created process nametgt.process.cmdline: Created command line
Recommended fields
src.process.name: Creating process
Optional fields
src.process.user: Account
Readiness test
event.type = 'Process Creation' tgt.process.name = * | limit 5 | columns event.time, tgt.process.name, tgt.process.cmdline
// HUNT: launchctl referencing the com.apple.systemupdater persistence label
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1543.001, T1036.005
// CONF: high | FP: low
// EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: launchctl whose arguments mention systemupdater. contains is case-insensitive, which reproduces the CQL /i intent.
// REQUIRES: SentinelOne process-creation events with command line from macOS agents
// TUNING: None expected: the label is specific to this campaign.
// LOOKBACK: 7d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A LaunchAgent loaded by launchd at login without a launchctl command is not captured.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation' tgt.process.name in:anycase ('launchctl') tgt.process.cmdline contains 'systemupdater'
| sort -event.time
| limit 200
| columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdlineAutomated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeFileName: Created process nameProcessCommandLine: Created command line
Recommended fields
InitiatingProcessFileName: Initiating process
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp, FileName, ProcessCommandLine | take 5
// HUNT: launchctl referencing the com.apple.systemupdater persistence label // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1543.001, T1036.005 // CONF: high | FP: low // EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: launchctl with systemupdater in its arguments. contains is case-insensitive. // REQUIRES: Defender for Endpoint process-creation telemetry from macOS devices (DeviceProcessEvents) // TUNING: None expected: the label is specific to this campaign. // LOOKBACK: 7d; extend to 30d for the incident window // CONFIGURATION: No lookup objects required. // KNOWN GAPS: A LaunchAgent loaded by launchd at login without a launchctl command is not captured. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceProcessEvents | where Timestamp >= ago(7d) | where FileName =~ "launchctl" | where ProcessCommandLine contains "systemupdater" | project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FolderPath, ProcessCommandLine | sort by Timestamp desc | take 200
Looks for: Generic form of the persistence trick: launchctl loading a com.apple.* plist out of /Users/<name>/Library/LaunchAgents. Catches renamed variants of the label. T1543.001, T1036.005.
FP: A few vendor tools and profile migrations drop Apple-prefixed plists in user LaunchAgents. Baseline the labels seen in a week and exclude them by name.
Known limitations and deployment notes
- PowerQuery: A plist loaded from a path that does not start with /Users/ is not matched; the other CQL cards cover the campaign label.
- PowerQuery assumes: src.process.user holds the account that ran the creating process.
- PowerQuery assumes: The home folder path starts with /Users/, as on a stock macOS install.
- KQL – Defender XDR: A plist loaded from a path that does not start with /Users/ is not matched.
- KQL – Defender XDR assumes: The query carries no operating-system filter; the path and launchctl are macOS specific.
- KQL – Defender XDR assumes: The home folder path starts with /Users/, as on a stock macOS install.
// HUNT: com.apple.* LaunchAgent loaded from a per-user LaunchAgents folder // MITRE: T1543.001, T1036.005 // CONF: medium FP: medium COST: low | REQUIRES: macOS process creation with command line // LOOKBACK: 7d // TUNING: after a one-week baseline, exclude known-good labels with | CommandLine!=/com\.apple\.(labelA|labelB)\.plist/i. Keep unknown labels and anything whose plist sits under /tmp or a hidden folder. #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | event_platform=Mac | FileName=/^launchctl$/i | CommandLine=/bootstrap|load|submit|kickstart/i | CommandLine=/\/Users\/[^\/]+\/Library\/LaunchAgents\/com\.apple\./i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, ImageFileName, CommandLine])
4 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.type: Event typeevent.time: Event timetgt.process.name: Created process nametgt.process.cmdline: Created command line
Recommended fields
src.process.name: Creating process
Optional fields
src.process.user: Account
Readiness test
event.type = 'Process Creation' tgt.process.name = * | limit 5 | columns event.time, tgt.process.name, tgt.process.cmdline
// HUNT: com.apple.* LaunchAgent loaded from a per-user LaunchAgents folder
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1543.001, T1036.005
// CONF: medium | FP: medium
// EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: launchctl with a load, bootstrap, submit or kickstart verb whose arguments point at a com.apple. plist in a per-user LaunchAgents folder. matches and contains are case-insensitive, which reproduces the CQL /i intent.
// REQUIRES: SentinelOne process-creation events with command line from macOS agents
// TUNING: After a one-week baseline, exclude known-good labels. Keep unknown labels and anything whose plist sits under /tmp or a hidden folder.
// LOOKBACK: 7d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A plist loaded from a path that does not start with /Users/ is not matched; the other CQL cards cover the campaign label.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation' tgt.process.name in:anycase ('launchctl') tgt.process.cmdline matches 'bootstrap|load|submit|kickstart' tgt.process.cmdline matches '/Users/[^/]+/Library/LaunchAgents/com[.]apple[.]'
| sort -event.time
| limit 200
| columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdlineAutomated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeFileName: Created process nameProcessCommandLine: Created command line
Recommended fields
InitiatingProcessFileName: Initiating process
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp, FileName, ProcessCommandLine | take 5
// HUNT: com.apple.* LaunchAgent loaded from a per-user LaunchAgents folder // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1543.001, T1036.005 // CONF: medium | FP: medium // EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: launchctl with a load, bootstrap, submit or kickstart verb and a com.apple. plist in a per-user LaunchAgents folder. The regex carries (?i) to keep the CQL /i intent. // REQUIRES: Defender for Endpoint process-creation telemetry from macOS devices (DeviceProcessEvents) // TUNING: After a one-week baseline, exclude known-good labels. Keep unknown labels and anything whose plist sits under /tmp or a hidden folder. // LOOKBACK: 7d; extend to 30d for the incident window // CONFIGURATION: No lookup objects required. // KNOWN GAPS: A plist loaded from a path that does not start with /Users/ is not matched. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceProcessEvents | where Timestamp >= ago(7d) | where FileName =~ "launchctl" | where ProcessCommandLine contains "bootstrap" or ProcessCommandLine contains "load" or ProcessCommandLine contains "submit" or ProcessCommandLine contains "kickstart" | where ProcessCommandLine matches regex @"(?i)/Users/[^/]+/Library/LaunchAgents/com\.apple\." | project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FolderPath, ProcessCommandLine | sort by Timestamp desc | take 200
Looks for: Execution of a binary named ICMacOs or from the hidden .update-tmp staging folder. The name is the one SOCRadar documents; a renamed build is covered by the hash query and by the LaunchAgent queries.
FP: Near zero. If the operator renames the binary this query goes quiet, which is why it is not the only persistence detection.
Known limitations and deployment notes
- PowerQuery: An implant renamed and run from outside a .update-tmp folder is not matched by name or path.
- PowerQuery assumes: tgt.process.image.sha256 is populated on process-creation events; it is shown for triage only and is not part of the predicate.
- PowerQuery assumes: src.process.user holds the account that ran the creating process.
- KQL – Defender XDR: An implant renamed and run from outside a .update-tmp folder is not matched by name or path.
- KQL – Defender XDR assumes: FolderPath holds the full image path of the created process.
- KQL – Defender XDR assumes: SHA256 is shown for triage only and is often unpopulated.
// HUNT: ICMacOs implant binary or .update-tmp staging execution // MITRE: T1059.004, T1036.005 // CONF: high FP: low COST: low | REQUIRES: macOS process creation with image path // LOOKBACK: 7d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | event_platform=Mac | FileName=/^ICMacOs$/i or ImageFileName=/\.update-tmp/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, FileName, ImageFileName, CommandLine, SHA256HashData])
4 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.type: Event typeevent.time: Event timetgt.process.name: Created process nametgt.process.image.path: Created process path
Recommended fields
src.process.name: Creating process
Optional fields
tgt.process.image.sha256: Hashtgt.process.cmdline: Created command line
Readiness test
event.type = 'Process Creation' tgt.process.name = * | limit 5 | columns event.time, tgt.process.name, tgt.process.image.path
// HUNT: ICMacOs implant binary or .update-tmp staging execution
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1059.004, T1036.005
// CONF: high | FP: low
// EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: a process named ICMacOs, or one whose image path contains .update-tmp. The new process is tgt.process.*. contains is case-insensitive and in:anycase makes the name test case-insensitive, which reproduces the CQL /i intent.
// REQUIRES: SentinelOne process-creation events with image path from macOS agents
// TUNING: None expected: the name and staging folder are specific to this campaign.
// LOOKBACK: 7d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: An implant renamed and run from outside a .update-tmp folder is not matched by name or path.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation' (tgt.process.name in:anycase ('ICMacOs') or tgt.process.image.path contains '.update-tmp')
| sort -event.time
| limit 200
| columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.image.path, tgt.process.image.sha256, tgt.process.cmdlineAutomated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeFileName: Created process nameFolderPath: Created process path
Recommended fields
InitiatingProcessFileName: Initiating process
Optional fields
SHA256: Hash. SHA256 is often unpopulated in DeviceProcessEvents; SHA1 is the safer pivot.
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp, FileName, FolderPath | take 5
// HUNT: ICMacOs implant binary or .update-tmp staging execution // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1059.004, T1036.005 // CONF: high | FP: low // EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: a created process named ICMacOs, or one whose path contains .update-tmp. // REQUIRES: Defender for Endpoint process-creation telemetry from macOS devices (DeviceProcessEvents) // TUNING: None expected: the name and staging folder are specific to this campaign. // LOOKBACK: 7d; extend to 30d for the incident window // CONFIGURATION: No lookup objects required. // KNOWN GAPS: An implant renamed and run from outside a .update-tmp folder is not matched by name or path. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceProcessEvents | where Timestamp >= ago(7d) | where FileName =~ "ICMacOs" or FolderPath contains ".update-tmp" | project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FileName, FolderPath, ProcessCommandLine, SHA1, SHA256 | sort by Timestamp desc | take 200
Looks for: Version 2 executes operator text over /bin/sh and returns output over the WebSocket, so interactive C2 shows up as shells, discovery tools, pbpaste and security spawned by the implant. T1059.004, T1115, T1082.
FP: Near zero while the binary keeps the documented name.
Known limitations and deployment notes
- PowerQuery: Children of an implant renamed away from ICMacOs are not matched.
- PowerQuery assumes: src.process.name holds the creator's name on Process Creation events.
- PowerQuery assumes: src.process.user holds the account that ran the creating process.
- KQL – Defender XDR: Children of an implant renamed away from ICMacOs are not matched.
- KQL – Defender XDR assumes: InitiatingProcessFileName holds the creator's file name.
// HUNT: processes spawned by the ICMacOs implant // MITRE: T1059.004, T1115, T1082, T1033 // CONF: high FP: low COST: low | REQUIRES: macOS process creation with parent name // LOOKBACK: 7d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | event_platform=Mac | ParentBaseFileName=/^ICMacOs$/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, FileName, CommandLine])
3 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.type: Event typeevent.time: Event timesrc.process.name: Creating process name
Recommended fields
tgt.process.name: Created process nametgt.process.cmdline: Created command line
Optional fields
src.process.user: Account
Readiness test
event.type = 'Process Creation' src.process.name = * | limit 5 | columns event.time, src.process.name, tgt.process.name
// HUNT: processes spawned by the ICMacOs implant
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1059.004, T1115, T1082, T1033
// CONF: high | FP: low
// EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: a process whose creator is named ICMacOs. On a Process Creation event the creator is src.process.*, so the implant is matched there and the child is tgt.process.*. in:anycase reproduces the CQL /i intent.
// REQUIRES: SentinelOne process-creation events from macOS agents
// TUNING: None expected: a child of the implant is suspicious by definition.
// LOOKBACK: 7d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: Children of an implant renamed away from ICMacOs are not matched.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation' src.process.name in:anycase ('ICMacOs')
| sort -event.time
| limit 200
| columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdlineAutomated validation: static-passed
2 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeInitiatingProcessFileName: Initiating process
Recommended fields
FileName: Created process nameProcessCommandLine: Created command line
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp, InitiatingProcessFileName, FileName | take 5
// HUNT: processes spawned by the ICMacOs implant // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1059.004, T1115, T1082, T1033 // CONF: high | FP: low // EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: a created process whose initiating process is named ICMacOs. The CQL parent field maps to InitiatingProcessFileName. // REQUIRES: Defender for Endpoint process-creation telemetry from macOS devices (DeviceProcessEvents) // TUNING: None expected: a child of the implant is suspicious by definition. // LOOKBACK: 7d; extend to 30d for the incident window // CONFIGURATION: No lookup objects required. // KNOWN GAPS: Children of an implant renamed away from ICMacOs are not matched. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceProcessEvents | where Timestamp >= ago(7d) | where InitiatingProcessFileName =~ "ICMacOs" | project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine | sort by Timestamp desc | take 200
Looks for: Before stealing, the Mach-O runs locale | grep -c ru_RU and curl -s --max-time 5 https://ipinfo.io/country to skip CIS victims. T1480.
FP: Admin scripts that look up their public country. The pair of checks within seconds, from a non-interactive parent, is the discriminator.
Known limitations and deployment notes
- PowerQuery: The 60-second pairing of a locale check and an ipinfo.io lookup is a tuning step and is not enforced by this query.
- PowerQuery assumes: The query carries no operating-system filter, so the same shell commands on Linux agents are also returned.
- PowerQuery assumes: src.process.user holds the account that ran the creating process.
- KQL – Defender XDR: The 60-second pairing of a locale check and an ipinfo.io lookup is a tuning step and is not enforced by this query.
- KQL – Defender XDR assumes: The query carries no operating-system filter, so the same shell commands on Linux devices are also returned.
- KQL – Defender XDR assumes: ProcessCommandLine holds the full argument string.
// HUNT: CIS geofence checks (locale ru_RU, ipinfo country lookup) // MITRE: T1480 // CONF: medium FP: medium COST: low | REQUIRES: macOS process creation with command line // LOOKBACK: 7d // TUNING: exclude well-known IT inventory scripts by ParentBaseFileName; prioritise hosts where both ru_RU and ipinfo.io/country appear for one aid inside 60 seconds. #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | event_platform=Mac | FileName=/^(sh|bash|zsh|curl|grep)$/i | CommandLine=/ru_RU|ipinfo\.io\/country/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, ImageFileName, CommandLine])
4 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.type: Event typeevent.time: Event timetgt.process.name: Created process nametgt.process.cmdline: Created command line
Recommended fields
src.process.name: Creating process
Optional fields
src.process.user: Account
Readiness test
event.type = 'Process Creation' tgt.process.name = * | limit 5 | columns event.time, tgt.process.name, tgt.process.cmdline
// HUNT: CIS geofence checks (locale ru_RU, ipinfo country lookup)
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1480
// CONF: medium | FP: medium
// EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: sh, bash, zsh, curl or grep whose arguments carry ru_RU or ipinfo.io/country. contains is case-insensitive, which reproduces the CQL /i intent.
// REQUIRES: SentinelOne process-creation events with command line from macOS agents
// TUNING: Exclude well-known IT inventory scripts by creating process name; prioritise hosts where both ru_RU and ipinfo.io/country appear within 60 seconds.
// LOOKBACK: 7d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: The 60-second pairing of a locale check and an ipinfo.io lookup is a tuning step and is not enforced by this query.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation' tgt.process.name in:anycase ('sh', 'bash', 'zsh', 'curl', 'grep') (tgt.process.cmdline contains 'ru_RU' or tgt.process.cmdline contains 'ipinfo.io/country')
| sort -event.time
| limit 200
| columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdlineAutomated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeFileName: Created process nameProcessCommandLine: Created command line
Recommended fields
InitiatingProcessFileName: Initiating process
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp, FileName, ProcessCommandLine | take 5
// HUNT: CIS geofence checks (locale ru_RU, ipinfo country lookup)
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1480
// CONF: medium | FP: medium
// EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: sh, bash, zsh, curl or grep with ru_RU or ipinfo.io/country in the arguments.
// REQUIRES: Defender for Endpoint process-creation telemetry from macOS devices (DeviceProcessEvents)
// TUNING: Exclude well-known IT inventory scripts by initiating process name.
// LOOKBACK: 7d; extend to 30d for the incident window
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: The 60-second pairing of a locale check and an ipinfo.io lookup is a tuning step and is not enforced by this query.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceProcessEvents
| where Timestamp >= ago(7d)
| where FileName in~ ("sh", "bash", "zsh", "curl", "grep")
| where ProcessCommandLine contains "ru_RU" or ProcessCommandLine contains "ipinfo.io/country"
| project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FolderPath, ProcessCommandLine
| sort by Timestamp desc
| take 200Looks for: ClickFix lures make the victim paste a one-line downloader. This is the generic shape (bash -c "$(curl ...)" or curl ... | sh), not an ICMacOS-specific string. T1204.004.
FP: Very common for developers: Homebrew and many vendor installers use the same shape. Treat as a hunt, not an alert.
Known limitations and deployment notes
- PowerQuery: Expect a high false-positive rate from legitimate installers; the Homebrew exclusion is only a starting point.
- PowerQuery: A download written with wget or a language runtime instead of curl is not matched.
- PowerQuery assumes: The query carries no operating-system filter, so the same shell one-liners on Linux agents are also returned.
- PowerQuery assumes: src.process.user holds the account that ran the creating process.
- KQL – Defender XDR: Expect a high false-positive rate from legitimate installers; the Homebrew exclusion is only a starting point.
- KQL – Defender XDR: A download written with wget or a language runtime instead of curl is not matched.
- KQL – Defender XDR assumes: The query carries no operating-system filter, so the same shell one-liners on Linux devices are also returned.
- KQL – Defender XDR assumes: ProcessCommandLine holds the full argument string.
// HUNT: ClickFix-style curl-to-shell one-liners // MITRE: T1204.004, T1059.004 // CONF: medium FP: high COST: medium | REQUIRES: macOS process creation with command line // LOOKBACK: 7d // TUNING: exclude the Homebrew installer and other vendor installers you allow: the CommandLine!=/Homebrew\/install/i line below is a starting point. Prioritise hits to new or low-reputation hosts, or where the next stage lands under /tmp and is a .command file. #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | event_platform=Mac | FileName=/^(sh|bash|zsh)$/i | CommandLine=/-c\s+.*\$\(\s*curl|curl\s.*\|\s*(ba|z)?sh/i | CommandLine!=/Homebrew\/install/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, ImageFileName, CommandLine])
4 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.type: Event typeevent.time: Event timetgt.process.name: Created process nametgt.process.cmdline: Created command line
Recommended fields
src.process.name: Creating process
Optional fields
src.process.user: Account
Readiness test
event.type = 'Process Creation' tgt.process.name = * | limit 5 | columns event.time, tgt.process.name, tgt.process.cmdline
// HUNT: ClickFix-style curl-to-shell one-liners
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1204.004, T1059.004
// CONF: medium | FP: high
// EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: a shell running a curl command substitution or piping curl into a shell, excluding the Homebrew installer. matches and contains are case-insensitive, which reproduces the CQL /i intent.
// REQUIRES: SentinelOne process-creation events with command line from macOS agents
// TUNING: Exclude the Homebrew installer and other vendor installers you allow. Prioritise hits to new or low-reputation hosts, or where the next stage lands under /tmp and is a .command file.
// LOOKBACK: 7d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: Expect a high false-positive rate from legitimate installers; the Homebrew exclusion is only a starting point. A download written with wget or a language runtime instead of curl is not matched.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation' tgt.process.name in:anycase ('sh', 'bash', 'zsh') tgt.process.cmdline matches '-c\\s+.*[$][(]\\s*curl|curl\\s.*[|]\\s*(ba|z)?sh' !(tgt.process.cmdline contains 'Homebrew/install')
| sort -event.time
| limit 200
| columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdlineAutomated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeFileName: Created process nameProcessCommandLine: Created command line
Recommended fields
InitiatingProcessFileName: Initiating process
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp, FileName, ProcessCommandLine | take 5
// HUNT: ClickFix-style curl-to-shell one-liners
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1204.004, T1059.004
// CONF: medium | FP: high
// EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: a shell running a curl command substitution or piping curl into a shell, excluding the Homebrew installer. The regex carries (?i) to keep the CQL /i intent.
// REQUIRES: Defender for Endpoint process-creation telemetry from macOS devices (DeviceProcessEvents)
// TUNING: Exclude the Homebrew installer and other vendor installers you allow. Prioritise hits to new or low-reputation hosts.
// LOOKBACK: 7d; extend to 30d for the incident window
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: Expect a high false-positive rate from legitimate installers; the Homebrew exclusion is only a starting point. A download written with wget or a language runtime instead of curl is not matched.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceProcessEvents
| where Timestamp >= ago(7d)
| where FileName in~ ("sh", "bash", "zsh")
| where ProcessCommandLine matches regex @"(?i)-c\\s+.*[$][(]\\s*curl|curl\\s.*[|]\\s*(ba|z)?sh"
| where ProcessCommandLine !contains "Homebrew/install"
| project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FolderPath, ProcessCommandLine
| sort by Timestamp desc
| take 200Looks for: SHA-256 values from SOCRadar's host indicator table matched against process image hashes. Mach-O builds will match as the executed image; dropper hashes are shell scripts, so they only match if the sensor reports the script as the image.
FP: Near zero. Use the Falcon IOC import for file-hash matching of scripts at rest.
Known limitations and deployment notes
- PowerQuery: A rebuilt or re-signed sample has a new hash and is not matched; the behavioural cards cover it.
- PowerQuery assumes: tgt.process.image.sha256 is populated on process-creation events on this tenant; the readiness test shows how many rows carry it.
- PowerQuery assumes: src.process.user holds the account that ran the creating process.
- KQL – Defender XDR: SHA256 is often unpopulated in DeviceProcessEvents, and the CQL carries no SHA1 values to pivot on instead.
- KQL – Defender XDR: A rebuilt or re-signed sample has a new hash and is not matched.
- KQL – Defender XDR assumes: SHA256 is populated for the created process on this tenant; the readiness test counts how many rows carry it.
// HUNT: published ICMacOS SHA-256 values as process images // MITRE: T1059.004 // CONF: high FP: low COST: low | REQUIRES: macOS process creation with SHA-256 // LOOKBACK: 7d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | in(SHA256HashData, values=["5dfb0c01ac5c075e23ec37873b30ba16cf28e290e9439d04101f0a8191f929d8", "8cc449e7e240894e77187f6faff415bc8b9f2f9da73f60eef1f7605debd9144a", "62e435102e1e1de74537f174ede7c8ff198dc4df3fd2e1167f537096e0b4dd17", "857236d1902f4604acdf27519c0310064d21f8a82af3b95b1e4f02fef581b1d0", "6917505bbdc8efa01ea1a0298eae62a93a57a8c98d3712a69d822dca4a667f05", "dca852b53c259641e1782bd9122c5007130614a7a8fd17102400acb4f50f6e94", "e7e8ac14aaee970c6d00c6cbb398decc56dfc128974c01bfc8e7acd13a18576e", "ec37acd3bd15f50eee2941d5644ca0ee738b36ce4a39e9e08058e35ebc7961fc", "fcf9de13ecc70b4fda3998ed7a93849edf86c48767a1a13f32f4a6a631a65ae2", "3d4f70172c8f31813e7b37fc1a49bce193663e33c4eb65952bb5aec9d7176826", "8b7606bdccdd6ff691db875283fdf5b6b658dd8d4d141b44e07f8f2583ff5604", "bc8d70f000e73c0c7a69a2676805190e7109cab59df3e34c5a74d2cb7f13a7e4", "a9b21ac0112855b835b5e5850ef167471eff7305d42b3a8104c1961b257a444d", "c8136413ad38a1028050f5d508e25267b518c5fdeac80b6442103d1009d8924c", "e52855d447d152bb698e565f361161cdc8946183ab09bf3cbea89765a2b5ff31", "d9df05a3fb68d302ecf134a1214b609c6ec0a3fb9122907214afac3908b587f4", "8b4303a065e18e80050ef22031ec60b1a4e84f958d9e56cc5cc34cd29d988d69"]) | table([@timestamp, ComputerName, UserName, FileName, ImageFileName, SHA256HashData, CommandLine])
3 required fields · View requirements
Required telemetry
- Process Creation
Required fields
event.type: Event typeevent.time: Event timetgt.process.image.sha256: Created process hash
Recommended fields
tgt.process.name: Created process name
Optional fields
tgt.process.cmdline: Created command line
Readiness test
event.type = 'Process Creation' tgt.process.image.sha256 = * | limit 5 | columns event.time, tgt.process.name, tgt.process.image.sha256
// HUNT: published ICMacOS SHA-256 values as process images
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1059.004
// CONF: high | FP: low
// EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: a created process whose SHA-256 is one of the 17 published ICMacOS values. The new process is tgt.process.*; in:anycase makes the hash comparison case-insensitive.
// REQUIRES: SentinelOne process-creation events with a populated SHA-256 on macOS agents
// TUNING: None expected: the hashes are specific to this campaign.
// LOOKBACK: 7d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A rebuilt or re-signed sample has a new hash and is not matched; the behavioural cards cover it.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation' tgt.process.image.sha256 in:anycase ('5dfb0c01ac5c075e23ec37873b30ba16cf28e290e9439d04101f0a8191f929d8', '8cc449e7e240894e77187f6faff415bc8b9f2f9da73f60eef1f7605debd9144a', '62e435102e1e1de74537f174ede7c8ff198dc4df3fd2e1167f537096e0b4dd17', '857236d1902f4604acdf27519c0310064d21f8a82af3b95b1e4f02fef581b1d0', '6917505bbdc8efa01ea1a0298eae62a93a57a8c98d3712a69d822dca4a667f05', 'dca852b53c259641e1782bd9122c5007130614a7a8fd17102400acb4f50f6e94', 'e7e8ac14aaee970c6d00c6cbb398decc56dfc128974c01bfc8e7acd13a18576e', 'ec37acd3bd15f50eee2941d5644ca0ee738b36ce4a39e9e08058e35ebc7961fc', 'fcf9de13ecc70b4fda3998ed7a93849edf86c48767a1a13f32f4a6a631a65ae2', '3d4f70172c8f31813e7b37fc1a49bce193663e33c4eb65952bb5aec9d7176826', '8b7606bdccdd6ff691db875283fdf5b6b658dd8d4d141b44e07f8f2583ff5604', 'bc8d70f000e73c0c7a69a2676805190e7109cab59df3e34c5a74d2cb7f13a7e4', 'a9b21ac0112855b835b5e5850ef167471eff7305d42b3a8104c1961b257a444d', 'c8136413ad38a1028050f5d508e25267b518c5fdeac80b6442103d1009d8924c', 'e52855d447d152bb698e565f361161cdc8946183ab09bf3cbea89765a2b5ff31', 'd9df05a3fb68d302ecf134a1214b609c6ec0a3fb9122907214afac3908b587f4', '8b4303a065e18e80050ef22031ec60b1a4e84f958d9e56cc5cc34cd29d988d69')
| sort -event.time
| limit 200
| columns event.time, endpoint.name, src.process.user, tgt.process.name, tgt.process.image.path, tgt.process.image.sha256, tgt.process.cmdlineAutomated validation: static-passed
2 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeSHA256: Created process hash
Recommended fields
FileName: Created process name
Optional fields
SHA1: Hash. SHA256 is often unpopulated in DeviceProcessEvents; SHA1 is shown for triage only.
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | where isnotempty(SHA256) | project Timestamp, SHA256 | take 5
// HUNT: published ICMacOS SHA-256 values as process images
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1059.004
// CONF: high | FP: low
// EQUIVALENCE: equivalent-with-schema-assumptions - Same predicate: a created process whose SHA-256 is one of the 17 published ICMacOS values. SHA256 is often unpopulated in DeviceProcessEvents, so an empty result is weaker evidence than on the CQL tab.
// REQUIRES: Defender for Endpoint process-creation telemetry with a populated SHA256 (DeviceProcessEvents)
// TUNING: None expected: the hashes are specific to this campaign.
// LOOKBACK: 7d; extend to 30d for the incident window
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: SHA256 is often unpopulated in DeviceProcessEvents, and the CQL carries no SHA1 values to pivot on instead. A rebuilt or re-signed sample has a new hash and is not matched.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceProcessEvents
| where Timestamp >= ago(7d)
| where SHA256 in~ ("5dfb0c01ac5c075e23ec37873b30ba16cf28e290e9439d04101f0a8191f929d8", "8cc449e7e240894e77187f6faff415bc8b9f2f9da73f60eef1f7605debd9144a", "62e435102e1e1de74537f174ede7c8ff198dc4df3fd2e1167f537096e0b4dd17", "857236d1902f4604acdf27519c0310064d21f8a82af3b95b1e4f02fef581b1d0", "6917505bbdc8efa01ea1a0298eae62a93a57a8c98d3712a69d822dca4a667f05", "dca852b53c259641e1782bd9122c5007130614a7a8fd17102400acb4f50f6e94", "e7e8ac14aaee970c6d00c6cbb398decc56dfc128974c01bfc8e7acd13a18576e", "ec37acd3bd15f50eee2941d5644ca0ee738b36ce4a39e9e08058e35ebc7961fc", "fcf9de13ecc70b4fda3998ed7a93849edf86c48767a1a13f32f4a6a631a65ae2", "3d4f70172c8f31813e7b37fc1a49bce193663e33c4eb65952bb5aec9d7176826", "8b7606bdccdd6ff691db875283fdf5b6b658dd8d4d141b44e07f8f2583ff5604", "bc8d70f000e73c0c7a69a2676805190e7109cab59df3e34c5a74d2cb7f13a7e4", "a9b21ac0112855b835b5e5850ef167471eff7305d42b3a8104c1961b257a444d", "c8136413ad38a1028050f5d508e25267b518c5fdeac80b6442103d1009d8924c", "e52855d447d152bb698e565f361161cdc8946183ab09bf3cbea89765a2b5ff31", "d9df05a3fb68d302ecf134a1214b609c6ec0a3fb9122907214afac3908b587f4", "8b4303a065e18e80050ef22031ec60b1a4e84f958d9e56cc5cc34cd29d988d69")
| project Timestamp, ReportId, DeviceId, DeviceName, AccountName, FileName, FolderPath, SHA1, SHA256, ProcessCommandLine
| sort by Timestamp desc
| take 200Detection Rules by Platform
CrowdStrike: Custom IOA
| IOA name | Pattern (Process Creation, macOS) | Promotes | Action | Exclusions |
|---|---|---|---|---|
| ICMacOS published strings in command line | Command line matches (?i)(escapeai\.live|mikoblico\.xyz|icmacos_run_v2|loader_v2\.sh|ICMacOs\?arch=|\.update-tmp) | Promote Q5 | Detect, high | None needed |
| Keychain password validation or dump | Image .*/security, command line (?i)(unlock-keychain\s+\S*\s*-p\s|dump-keychain\s+.*-d) | Promote Q1 | Detect, medium | CI service accounts, build keychain parents |
| osascript spoofed password prompt | Image .*/osascript, command line (?i)(System Preferences|hidden answer|dump-keychain) | Promote Q3 | Detect, medium | MDM and installer parents |
| Apple-named LaunchAgent loaded from user folder | Image .*/launchctl, command line (?i)/Users/[^/]+/Library/LaunchAgents/com\.apple\. | Promote Q8, Q9 | Detect, high | Baselined labels |
| ICMacOs implant child process | Parent image .*/ICMacOs | Promote Q11 | Detect, high | None |
Alert package for Q5 / Q11 (campaign-specific, highest fidelity)
- Scheduled search name: DETECT - ICMacOS Strings or Implant Children (macOS)
- Description: Fires when a macOS process carries the published ICMacOS C2 or staging strings, or when a child process is spawned by a binary named ICMacOs. Indicates a ClickFix-delivered stealer or v2 remote shell.
- Email subject: [HIGH] Detection: ICMacOS - macOS infostealer/RAT activity on <ComputerName>
- Body: What fired (query, host, user, command line). Meaning: the user likely pasted a Terminal command and typed their login password into a spoofed dialog, so assume the password, Keychain, browser sessions, SSH, cloud and Kubernetes credentials are exposed. Immediate action: network-contain the host, do not power off, start the triage list. Escalate to IR lead on any v2 sign (LaunchAgent, ICMacOs children).
Triage checklist (L1)
- Confirm the hit: host, user, parent chain, full command line.
- Run Q6 and Q7 for the same
aidto see whether DNS or connections to the C2 exist. - Check for the LaunchAgent: Q8 and Q9, then the native hunt in section 7 if the host is reachable.
- Look for /tmp artifacts: hidden logs,
.update-tmp, hidden ZIP. - Ask the user what they pasted or typed and when; record the lure URL from browser history.
- Isolate with network containment; keep the host powered for volatile triage.
- Open credential-rotation tasks (section 14) for the user: macOS password first.
- Escalate to IR and cloud/identity owners if the user held developer credentials.
Pivot queries
// host-scoped: everything the implant did (replace the aid) #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | aid=REPLACE_WITH_AID | ParentBaseFileName=/^(ICMacOs|launchd|sh|bash|zsh)$/i | table([@timestamp, ParentBaseFileName, FileName, CommandLine]) | sort(@timestamp, order=asc) // environment-wide: which other hosts resolved the C2 domain #event_simpleName=DnsRequest | DomainName=/(^|\.)escapeai\.live$/i | groupBy([ComputerName], function=count(as=Lookups)) | sort(Lookups, order=desc)
SentinelOne: custom detection rules
| Rule | Source query | Run as | Notes |
|---|---|---|---|
| ICMacOS published strings in command line | Q5, PowerQuery tab | Scheduled custom detection rule | Bind entities so the alert names the host instead of "Unknown Device" |
| Keychain password validation or dump | Q1, PowerQuery tab | Scheduled custom detection rule | Bind entities so the alert names the host instead of "Unknown Device" |
| osascript spoofed password prompt | Q3, PowerQuery tab | Scheduled custom detection rule | Bind entities so the alert names the host instead of "Unknown Device" |
| Apple-named LaunchAgent loaded from user folder | Q8, Q9, PowerQuery tab | Scheduled custom detection rule | Bind entities so the alert names the host instead of "Unknown Device" |
| ICMacOs implant child process | Q11, PowerQuery tab | Scheduled custom detection rule | Bind entities so the alert names the host instead of "Unknown Device" |
Create the rule with POST /web/api/v2.1/cloud-detection/rules, queryType: "scheduled" and queryLang: "2.0", with the query in data.scheduledParams.query. Use 2.0 operator spellings: a rule written with the 1.0 token ContainsCIS was accepted and never fired on a tenant. The API does not warn, so lint the body before deploying.
Microsoft Defender: custom detection rules
| Rule | Source query | Run as | Notes |
|---|---|---|---|
| ICMacOS published strings in command line | Q5, KQL – Defender XDR tab | Custom detection rule, alert only, every hour | The query returns Timestamp, ReportId and DeviceId, which Microsoft recommends for Defender for Endpoint tables so alerts carry the device group scope and the process tree. Remove the Timestamp filter and the final sort and take before saving the rule: the service applies the rule's lookback itself |
| Keychain password validation or dump | Q1, KQL – Defender XDR tab | Custom detection rule, alert only, every hour | The query returns Timestamp, ReportId and DeviceId, which Microsoft recommends for Defender for Endpoint tables so alerts carry the device group scope and the process tree. Remove the Timestamp filter and the final sort and take before saving the rule: the service applies the rule's lookback itself |
| osascript spoofed password prompt | Q3, KQL – Defender XDR tab | Custom detection rule, alert only, every hour | The query returns Timestamp, ReportId and DeviceId, which Microsoft recommends for Defender for Endpoint tables so alerts carry the device group scope and the process tree. Remove the Timestamp filter and the final sort and take before saving the rule: the service applies the rule's lookback itself |
| Apple-named LaunchAgent loaded from user folder | Q8, Q9, KQL – Defender XDR tab | Custom detection rule, alert only, every hour | The query returns Timestamp, ReportId and DeviceId, which Microsoft recommends for Defender for Endpoint tables so alerts carry the device group scope and the process tree. Remove the Timestamp filter and the final sort and take before saving the rule: the service applies the rule's lookback itself |
| ICMacOs implant child process | Q11, KQL – Defender XDR tab | Custom detection rule, alert only, every hour | The query returns Timestamp, ReportId and DeviceId, which Microsoft recommends for Defender for Endpoint tables so alerts carry the device group scope and the process tree. Remove the Timestamp filter and the final sort and take before saving the rule: the service applies the rule's lookback itself |
Q2, Q4, Q6, Q7, Q10, Q12, Q13 and Q14 stay a hunt in this pack, not a rule. A rule can generate only 150 alerts per run. Continuous (NRT) frequency needs a single table and no comment lines, so delete the generated comment header from the query first.
Machine-Readable IOC Appendix
All rows are detect and high or medium severity, never critical: the intelligence has one origin (see section 2). Paths and URL paths are behavioral signatures, not importable IOCs.
type,value,action,severity,expiration,description,tags domain,escapeai.live,detect,high,2027-04-14,ICMacOS primary C2 and payload delivery host,campaign:ICMacOS domain,mikoblico.xyz,detect,high,2027-04-14,ICMacOS login infrastructure (SOCRadar IOC table),campaign:ICMacOS ipv4,85.137.253.61,detect,high,2027-04-14,ICMacOS login infrastructure (SOCRadar IOC table),campaign:ICMacOS ipv4,45.13.186.247,detect,high,2027-04-14,ICMacOS login infrastructure (SOCRadar IOC table),campaign:ICMacOS sha256,5dfb0c01ac5c075e23ec37873b30ba16cf28e290e9439d04101f0a8191f929d8,detect,medium,2027-04-14,ICMacOS dropper script,campaign:ICMacOS sha256,8cc449e7e240894e77187f6faff415bc8b9f2f9da73f60eef1f7605debd9144a,detect,medium,2027-04-14,ICMacOS dropper script,campaign:ICMacOS sha256,62e435102e1e1de74537f174ede7c8ff198dc4df3fd2e1167f537096e0b4dd17,detect,medium,2027-04-14,ICMacOS dropper script,campaign:ICMacOS sha256,857236d1902f4604acdf27519c0310064d21f8a82af3b95b1e4f02fef581b1d0,detect,medium,2027-04-14,ICMacOS dropper script,campaign:ICMacOS sha256,6917505bbdc8efa01ea1a0298eae62a93a57a8c98d3712a69d822dca4a667f05,detect,medium,2027-04-14,ICMacOS dropper script,campaign:ICMacOS sha256,dca852b53c259641e1782bd9122c5007130614a7a8fd17102400acb4f50f6e94,detect,medium,2027-04-14,ICMacOS dropper script,campaign:ICMacOS sha256,e7e8ac14aaee970c6d00c6cbb398decc56dfc128974c01bfc8e7acd13a18576e,detect,medium,2027-04-14,ICMacOS dropper script,campaign:ICMacOS sha256,ec37acd3bd15f50eee2941d5644ca0ee738b36ce4a39e9e08058e35ebc7961fc,detect,medium,2027-04-14,ICMacOS dropper script,campaign:ICMacOS sha256,fcf9de13ecc70b4fda3998ed7a93849edf86c48767a1a13f32f4a6a631a65ae2,detect,medium,2027-04-14,ICMacOS dropper script,campaign:ICMacOS sha256,3d4f70172c8f31813e7b37fc1a49bce193663e33c4eb65952bb5aec9d7176826,detect,medium,2027-04-14,ICMacOS dropper script,campaign:ICMacOS sha256,8b7606bdccdd6ff691db875283fdf5b6b658dd8d4d141b44e07f8f2583ff5604,detect,medium,2027-04-14,ICMacOS dropper script,campaign:ICMacOS sha256,bc8d70f000e73c0c7a69a2676805190e7109cab59df3e34c5a74d2cb7f13a7e4,detect,high,2027-04-14,ICMacOS Mach-O v1,campaign:ICMacOS sha256,a9b21ac0112855b835b5e5850ef167471eff7305d42b3a8104c1961b257a444d,detect,high,2027-04-14,ICMacOS Mach-O v1,campaign:ICMacOS sha256,c8136413ad38a1028050f5d508e25267b518c5fdeac80b6442103d1009d8924c,detect,high,2027-04-14,ICMacOS Mach-O v1,campaign:ICMacOS sha256,e52855d447d152bb698e565f361161cdc8946183ab09bf3cbea89765a2b5ff31,detect,high,2027-04-14,ICMacOS Mach-O v2,campaign:ICMacOS sha256,d9df05a3fb68d302ecf134a1214b609c6ec0a3fb9122907214afac3908b587f4,detect,high,2027-04-14,ICMacOS Mach-O v2,campaign:ICMacOS sha256,8b4303a065e18e80050ef22031ec60b1a4e84f958d9e56cc5cc34cd29d988d69,detect,medium,2027-04-14,ICMacOS Python payload,campaign:ICMacOS
indicatorType,indicatorValue,action,title,description,expirationTime,severity,recommendedActions,rbacGroups,category,mitretechniques,GenerateAlert DomainName,escapeai.live,Audit,ICMacOS primary C2 and payload delivery host,ICMacOS primary C2 and payload delivery host,2027-04-14T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True DomainName,mikoblico.xyz,Audit,ICMacOS login infrastructure,ICMacOS login infrastructure (SOCRadar IOC table),2027-04-14T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True IpAddress,85.137.253.61,Audit,ICMacOS login infrastructure,ICMacOS login infrastructure (SOCRadar IOC table),2027-04-14T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True IpAddress,45.13.186.247,Audit,ICMacOS login infrastructure,ICMacOS login infrastructure (SOCRadar IOC table),2027-04-14T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True FileSha256,5dfb0c01ac5c075e23ec37873b30ba16cf28e290e9439d04101f0a8191f929d8,Audit,ICMacOS dropper script,ICMacOS dropper script,2027-04-14T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True FileSha256,8cc449e7e240894e77187f6faff415bc8b9f2f9da73f60eef1f7605debd9144a,Audit,ICMacOS dropper script,ICMacOS dropper script,2027-04-14T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True FileSha256,62e435102e1e1de74537f174ede7c8ff198dc4df3fd2e1167f537096e0b4dd17,Audit,ICMacOS dropper script,ICMacOS dropper script,2027-04-14T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True FileSha256,857236d1902f4604acdf27519c0310064d21f8a82af3b95b1e4f02fef581b1d0,Audit,ICMacOS dropper script,ICMacOS dropper script,2027-04-14T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True FileSha256,6917505bbdc8efa01ea1a0298eae62a93a57a8c98d3712a69d822dca4a667f05,Audit,ICMacOS dropper script,ICMacOS dropper script,2027-04-14T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True FileSha256,dca852b53c259641e1782bd9122c5007130614a7a8fd17102400acb4f50f6e94,Audit,ICMacOS dropper script,ICMacOS dropper script,2027-04-14T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True FileSha256,e7e8ac14aaee970c6d00c6cbb398decc56dfc128974c01bfc8e7acd13a18576e,Audit,ICMacOS dropper script,ICMacOS dropper script,2027-04-14T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True FileSha256,ec37acd3bd15f50eee2941d5644ca0ee738b36ce4a39e9e08058e35ebc7961fc,Audit,ICMacOS dropper script,ICMacOS dropper script,2027-04-14T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True FileSha256,fcf9de13ecc70b4fda3998ed7a93849edf86c48767a1a13f32f4a6a631a65ae2,Audit,ICMacOS dropper script,ICMacOS dropper script,2027-04-14T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True FileSha256,3d4f70172c8f31813e7b37fc1a49bce193663e33c4eb65952bb5aec9d7176826,Audit,ICMacOS dropper script,ICMacOS dropper script,2027-04-14T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True FileSha256,8b7606bdccdd6ff691db875283fdf5b6b658dd8d4d141b44e07f8f2583ff5604,Audit,ICMacOS dropper script,ICMacOS dropper script,2027-04-14T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True FileSha256,bc8d70f000e73c0c7a69a2676805190e7109cab59df3e34c5a74d2cb7f13a7e4,Audit,ICMacOS Mach-O v1,ICMacOS Mach-O v1,2027-04-14T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True FileSha256,a9b21ac0112855b835b5e5850ef167471eff7305d42b3a8104c1961b257a444d,Audit,ICMacOS Mach-O v1,ICMacOS Mach-O v1,2027-04-14T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True FileSha256,c8136413ad38a1028050f5d508e25267b518c5fdeac80b6442103d1009d8924c,Audit,ICMacOS Mach-O v1,ICMacOS Mach-O v1,2027-04-14T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True FileSha256,e52855d447d152bb698e565f361161cdc8946183ab09bf3cbea89765a2b5ff31,Audit,ICMacOS Mach-O v2,ICMacOS Mach-O v2,2027-04-14T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True FileSha256,d9df05a3fb68d302ecf134a1214b609c6ec0a3fb9122907214afac3908b587f4,Audit,ICMacOS Mach-O v2,ICMacOS Mach-O v2,2027-04-14T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True FileSha256,8b4303a065e18e80050ef22031ec60b1a4e84f958d9e56cc5cc34cd29d988d69,Audit,ICMacOS Python payload,ICMacOS Python payload,2027-04-14T00:00:00.0Z,Medium,Investigate the device and pivot into the pack's queries,,,,True
Column names and allowed values are from Microsoft's documented parameter table. Check each expirationTime before importing: an indicator whose date has passed is already expired. Download the sample CSV from the Import page to confirm the column order before a bulk import. Each file takes at most 500 indicators. Learn describes the import per entity type, so if a mixed file is rejected, split it by indicatorType. An imported indicator does nothing unless the matching Advanced features are on (for example Custom network indicators and Allow or block file).
This pack does not ship a SentinelOne import block: the import format could not be verified against SentinelOne's own documentation. Export a sample from your console and the block can be added with confidence.
# Behavioral signatures (no atomic value; hunt, do not import)
launchctl bootstrap gui/<uid> ~/Library/LaunchAgents/com.apple.systemupdater.plist
plist keys: Label=com.apple.systemupdater, KeepAlive=true, StartInterval=3600
security unlock-keychain -p <password> ~/Library/Keychains/login.keychain-db (up to 5 attempts)
security dump-keychain -d ~/Library/Keychains/login.keychain-db
security find-generic-password -w -a "<user>" -s "<Browser> Safe Storage"
osascript -> fake "System Preferences" dialog; do shell script ... with administrator privileges
killall Terminal (after com.apple.Terminal preference edits)
locale | grep -c ru_RU
curl -s --max-time 5 https://ipinfo.io/country
pgrep ICMACOS then kill -SIGKILL <pid>
Paths: /tmp/.update-helper.log /tmp/.cache-update.log /tmp/.update-tmp/ICMacOs.gz /tmp/.systemd-private-helper.zip
URL paths on the C2 host: /icmacos_run_v2.command /loader_v2.sh /ICMacOs?arch=arm64 /ICMacOs?arch=amd64 /payload.py /api/build_config /upload /ws?mac_id={hostname}&username={username}# Names used by the sources ICMacOS, Icarus macOS (SOCRadar Threat Research Unit; also "ICMacOs" for the Mach-O) Icarus ClickFix (companion delivery panel named by SOCRadar) Mach-O written in Go; Gorilla WebSocket client; embedded keychainbreaker library Actor handle per SOCRadar: GlowComa (MaaS seller). Not an attribution claim by this pack.
# macOS audit (read-only) ls -la ~/Library/LaunchAgents/ | grep "com.apple." launchctl list | grep -i systemupdater ls -la /tmp/.update* /tmp/.cache-update.log /tmp/.systemd-private-helper.zip 2>/dev/null profiles list 2>/dev/null | head # Credential exposure inventory (names and permissions only, never contents) ls -l ~/.ssh ~/.aws/credentials ~/.kube/config ~/.docker/config.json 2>/dev/null find ~ -maxdepth 4 -name ".env*" -not -path "*/node_modules/*" 2>/dev/null | head -50
Detection Validation Gates
| Gate | Criteria |
|---|---|
| Telemetry ready | Mac sensors report process creation with command line and parent name, DNS requests with the requesting process, and outbound connections (CrowdStrike: ProcessRollup2, DnsRequest, NetworkConnectIP4. SentinelOne: Process Creation, DNS Resolved, IP Connect. Defender: DeviceProcessEvents, DeviceEvents, DeviceNetworkEvents). Confirm event_platform=Mac returns rows in your tenant. |
| Benign baseline | Run Q1, Q2, Q3, Q4, Q9, Q12 and Q13 for 7 days without alerting; record parents of benign hits (CI agents, MDM, Homebrew) and add exclusions. |
| Positive test | On an isolated lab Mac, run harmless equivalents: security unlock-keychain -p x /tmp/test.keychain-db against a throwaway keychain, launchctl list with a dummy com.apple-prefixed test plist in a test account, and an osascript call carrying the string System Preferences. Expect Q1, Q9 and Q3 to fire. |
| Promotion | Promote only Q5, Q8 and Q11 to scheduled searches first; others stay hunt-only until baselined. All remain Detect. |
Hardening: Tiered
- Alert on the network indicators, do not block on them yet. Add
escapeai[.]live,mikoblico[.]xyzand the two IPs to DNS and proxy alerting. Single-origin indicators justify visibility first; blocking is the owner's decision. MITRE M1037 Filter Network Traffic. Verify: Q6 and Q7 return results in a test. - Run the LaunchAgent audit across the Mac fleet. Flag any
com.apple.*plist in a user LaunchAgents folder. MITRE M1047 Audit. Verify: playbook step 1 output. CIS Apple macOS Benchmark covers login item and LaunchAgent review by name; exact item numbers vary by OS release. - Confirm FileVault and a lock-on-sleep policy. A stolen login password unlocks the keychain, so full-disk encryption plus screen lock limit what a lost or idle Mac exposes. CIS Apple macOS Benchmark (FileVault, screen saver lock). Verify:
fdesetup status. - Brief developers and admins on the exact lure. No legitimate site or support person needs a command pasted into Terminal, and no dialog that appears after running a script should receive the login password. MITRE M1017 User Training.
- Restrict who can run Terminal-based installers on non-developer Macs. Use MDM application restrictions or an allowlisting tool (for example a binary-authorization agent) so unsigned or unknown downloads cannot execute from /tmp. MITRE M1038 Execution Prevention. Mac Gatekeeper and notarization enforcement is in the CIS Apple macOS Benchmark. Verify:
spctl --status. - Managed login items. Use MDM to inventory and, where supported, control Background Task Management items so unknown LaunchAgents surface to the admin. MITRE M1018 User Account Management, M1022 Restrict File and Directory Permissions. best-practice, no formal benchmark item named
- Keychain hygiene for admins and developers. Use a separate keychain password from the login password where policy allows, and store high-value secrets in an agent-protected store, not in plaintext files. MITRE M1027 Password Policies. best-practice, no formal benchmark
- Tune the Falcon Mac prevention policy to the strongest machine-learning and script-control settings your tenant supports and confirm the sensor is current on every Mac. best-practice, vendor setting names vary by console version
- Remove long-lived developer secrets from disk. Move to short-lived cloud credentials (federated SSO sessions), hardware-backed or agent-held SSH keys, and Kubernetes exec-based credential plugins. This directly removes the high-value files ICMacOS targets (.ssh, .aws, .kube, .env*). MITRE M1027, M1041 Encrypt Sensitive Information. NIST SP 800-53 IA-5.
- Detect stolen-credential use at the source. Enable and centralize cloud, Kubernetes, VCS and bastion audit logs with alerts on new-source use of an existing key (ATT&CK T1078 follow-on). Outside endpoint telemetry by design.
- Browser and wallet policy. Keep crypto wallets and password managers out of corporate browser profiles; require MFA that is phishing resistant for admin SaaS so a stolen cookie is not enough. MITRE M1032 Multi-factor Authentication.
Deployable Playbooks
Step 1: Inventory suspicious LaunchAgents (read-only)
Prerequisites: shell as the target user, or an MDM script run per user. Reboot required: No. Rollback: none required, nothing is changed.
for d in /Users/*/Library/LaunchAgents; do [ -d "$d" ] || continue ls -la "$d" | grep -i "com.apple." | sed "s|^|$d: |" done launchctl list | grep -i systemupdater
Step 2: Quarantine and remove the ICMacOS persistence (confirmed infection only)
Prerequisites: host is network-contained and triage evidence is collected; run as the affected user (not root) so the correct gui/<uid> domain is used. Reboot required: No. Rollback: the plist is moved, not deleted. To restore: mv ~/ICMacOS-quarantine/com.apple.systemupdater.plist ~/Library/LaunchAgents/ and launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.apple.systemupdater.plist. Restoring re-enables the malware, so only do this to preserve evidence on an isolated lab host.
UIDN=$(id -u) mkdir -p ~/ICMacOS-quarantine launchctl bootout gui/$UIDN/com.apple.systemupdater 2>/dev/null mv ~/Library/LaunchAgents/com.apple.systemupdater.plist ~/ICMacOS-quarantine/ 2>/dev/null pkill -x ICMacOs 2>/dev/null mv /tmp/.update-tmp /tmp/.cache-update.log /tmp/.update-helper.log /tmp/.systemd-private-helper.zip ~/ICMacOS-quarantine/ 2>/dev/null launchctl list | grep -i systemupdater || echo "label gone"
Step 3: Credential exposure inventory (read-only, names only)
Prerequisites: shell as the affected user. Reboot required: No. Rollback: none required, nothing is changed. The output tells the identity team which secrets to rotate.
ls -l ~/.ssh ~/.aws/credentials ~/.aws/config ~/.kube/config ~/.docker/config.json \
~/.config/gcloud/application_default_credentials.json ~/.npmrc ~/.netrc ~/.git-credentials 2>/dev/null
find ~ -maxdepth 5 -name ".env*" -not -path "*/node_modules/*" 2>/dev/null
ls -d ~/Library/Application\ Support/{Exodus,Electrum,"Ledger Live"} 2>/dev/null
Step 4: Post-incident credential rotation (order matters)
Prerequisites: a clean device, and the incident owner's approval. Reboot required: No. Rollback: none required for rotation itself; keep the old values only until dependent services are re-keyed, then destroy them.
- macOS account password (from a clean Mac or after reimage). The attacker holds the verified plaintext.
- Browser-stored passwords and active sessions: sign out everywhere, reset high-value accounts, MFA re-enrollment.
- SSH keys (generate new, remove old public keys from servers and Git hosting), cloud access keys and sessions, Kubernetes tokens and kubeconfig contexts, Docker, npm, PyPI, Git tokens, database passwords, every secret found in
.env*files. - Password manager master credentials and recovery material if its data folder was present.
- Crypto wallets: move funds to new wallets created on a clean device.
- Messaging sessions (Telegram, Discord, Slack, Signal) revoked from the account side.
Containment Runbook
| Phase | Actions | Owner | Evidence |
|---|---|---|---|
| Isolate | Network-contain the Mac in Falcon, keep it powered, disable the user's SSO sessions and VPN, suspend cloud keys found in the exposure inventory. | SOC / IR | Containment timestamp, host and user record |
| Isolate: by platform | CrowdStrike: network-contain the host. SentinelOne: network quarantine (Disconnect from Network; confirm the label in your console version). Microsoft Defender: Isolate device (full network isolation). | SOC / IR | Containment timestamp, host and user record |
| Scope | Run Q5, Q6, Q7, Q8, Q9, Q11 across the fleet; determine v1 (stealer only) or v2 (LaunchAgent plus WebSocket); list secrets present using playbook step 3. | IR / detection engineering | Query exports, secret inventory |
| Eradicate | Prefer reimage. If not, run playbook step 2 and re-verify with Q8, Q9, Q10. Do not trust in-place cleanup alone because the operator had a live shell on v2. | IR / endpoint engineering | Quarantine folder, hashes, launchctl output |
| Rotate | Playbook step 4 in the stated order; review cloud, Kubernetes, VCS and IdP audit logs from infection time for misuse. | Identity / cloud owners | Rotation log, audit-log review |
| Recover | Return the Mac to service after reimage, with updated sensor and managed login item controls; user retraining on the lure. | Endpoint engineering | Health check, training record |
| Re-hunt | Re-run the queries after 7 and 30 days and on any update to the SOCRadar indicators. | Detection engineering | Query results, closure decision |
Detection Coverage Map
| Technique | Behavior | CQL | IOA | CrowdStrike coverage | Gap | SentinelOne | Defender XDR |
|---|---|---|---|---|---|---|---|
| T1204.004 | ClickFix paste to Terminal | Q13, Q5 | IOA 1 | Partial | Browser page and clipboard are outside endpoint telemetry; Q13 is noisy | Good, with assumptions | Good, with assumptions |
| T1059.004 / .002 | Bash chain and osascript | Q3, Q5, Q10, Q11 | IOA 1, 3, 5 | Good | Script text passed through stdin or file hides strings | Good, with assumptions | Good, with assumptions |
| T1056.002 | Fake password dialog | Q3 | IOA 3 | Partial | The password typed and the dialog itself are not visible | Good, with assumptions | Good, with assumptions |
| T1555.001 | Keychain unlock/dump | Q1 | IOA 2 | Partial | Offline keychainbreaker parse of login.keychain-db makes no process; keychain contents are not visible | Good, with assumptions | Good, with assumptions |
| T1555.003 | Browser keys and stores | Q2 | none | Partial | Copying Login Data and Cookies is file access; no verified macOS file-read event used | Good, with assumptions | Good, with assumptions |
| T1552.001 / .003, T1555.005, T1005, T1119 | Dev secrets, histories, password managers, wallets | none | none | GAP | File reads of .ssh, .aws, .kube, .env*, wallets: outside verified endpoint telemetry. Cover with cloud and VCS audit logs | No query | No query |
| T1560 | Hidden ZIP in /tmp | Q5 (path strings only) | IOA 1 | GAP | Go code creates the archive; archive-write event for macOS is not verified | Good, with assumptions | Good, with assumptions |
| T1543.001 / T1036.005 | com.apple.systemupdater LaunchAgent | Q8, Q9 | IOA 4 | Partial | The plist file write is not seen; only the launchctl step | Good, with assumptions | Good, with assumptions |
| T1564, T1480 | Terminal prefs, geofence | Q4, Q12 | none | Partial | Medium-FP hunts | Good, with assumptions | Good, with assumptions |
| T1071.001, T1567, T1048.002 | C2 and upload to escapeai[.]live | Q6, Q7 | none | Partial | TLS body, WebSocket frames and upload content invisible; in-browser lookups may be unattributed | Good, with assumptions | Good, with assumptions |
| T1059.006 | payload.py execution | Q5 (fetch string) | IOA 1 | Partial | Python execution of an unseen script path is generic | Good, with assumptions | Good, with assumptions |
Honest limits: Falcon macOS telemetry cannot see keychain contents, what the victim types into a dialog, anything resolved or rendered only inside the browser (including the ClickFix page), TLS or WebSocket payloads, or the content of files the Go implant reads. Validation gates are in section 11; none of the queries has been run against a live tenant.
Hunt Summary Ticket
TITLE: ICMacOS (Icarus macOS) infostealer evolving into a persistent RAT SEVERITY: High (single-origin intelligence) DATE: 2026-10-14 VERSION: v0.1 Draft 2026-10-14 SCOPE: macOS endpoints, especially developer and admin Macs holding SSH, cloud, Kubernetes and .env secrets HYPOTHESIS: A ClickFix paste leads to a spoofed password dialog, Keychain validation, theft and, on v2, LaunchAgent persistence plus WebSocket shell. QUERIES: Q1 keychain CLI; Q2 Safe Storage; Q3 osascript prompt; Q4 Terminal prefs; Q5 published strings; Q6 DNS; Q7 IP; Q8 and Q9 LaunchAgent; Q10 implant exec; Q11 implant children; Q12 geofence; Q13 curl-to-shell; Q14 hashes DO FIRST: Run Q5, Q6, Q7, Q8 and Q11 over 30 days; run the LaunchAgent audit on developer Macs. FINDINGS: any published string, domain, IP, label, ICMacOs process or hash. GAPS: file reads of secrets, keychain contents, archive creation, browser-only activity and TLS payloads are outside endpoint telemetry. ACTIONS: contain, reimage or run playbook step 2, rotate credentials in order (playbook step 4), review cloud and VCS audit logs. OWNER: SOC / Incident Response / Identity FOLLOW-UP: Re-hunt after 7 and 30 days and on any SOCRadar IOC update.
Changelog
References
| Tier | Source | Used for | Access date |
|---|---|---|---|
| T1 | SOCRadar TRU: Inside ICMacOS (2026-10-12) | Primary analysis and all IOCs (snapshot 01) | 2026-10-14 |
| T3 | Cyber Security News (2026-10-13) | Republication of IOC lists (snapshot 02) | 2026-10-14 |
| T3 | Cyber Press (2026-10-13) | Summary and domain confirmation (snapshot 03) | 2026-10-14 |
| T3 | GBHackers | Summary and partial IOC confirmation (snapshot 04) | 2026-10-14 |
| T3 | Mallory story page | Timeline context only (snapshot 05) | 2026-10-14 |
| Ref | MITRE ATT&CK | Technique IDs as listed in the SOCRadar table | 2026-10-14 |