CyberXero: AI-Augmented Initial Access Broker
Executive Summary
Attacker objective: sell access. CyberXero is the forum alias of an initial access broker that SOCRadar's Threat Research Unit documented on 2026-10-06. It runs two pipelines from one workstation: a global automated campaign that mass-compromises WordPress and e-commerce sites for access and payment data, and a curated manual campaign against Ukrainian energy and utilities. Confirmed exfiltration covers four Ukrainian organisations and more than 628,000 records on individuals, including 564,073 subscriber records and 213,340 access-log entries from a Kharkiv district heating provider.
What is different: an AI orchestration layer on the actor's own infrastructure. SOCRadar reports up to 51 specialised Claude Code agent definitions on the primary workstation and a PentAGI deployment wired into a Cobalt Strike team server through an AI provider API for payload generation. One recorded run scanned 4,708 targets, reached 429 WordPress admin panels and deployed 32 shells in 61 seconds. The whole operation became visible because the actor exposed an open directory with its live working directory, AI session logs and plaintext tokens.
Scope of this pack: the actor, not the vulnerability. The WordPress REST API batch flaws (CVE-2026-63030, CVE-2026-60137) are only the delivery vector for the mass pipeline and are covered by a separate pack in this library; nothing here hunts the vulnerability itself, and no indicator is borrowed from another pack. This pack hunts what CyberXero does after and around that entry: Cobalt Strike PowerShell stagers, the UpdSvc service, remote WMI, Redis abuse with SSH key injection, webshell execution on sensored web servers, and the machine-speed tempo.
Honest coverage: the mass scanning and panel compromise happen against internet-facing web applications. Most of that is web-server-log and database territory, not endpoint telemetry. The strong endpoint surfaces are the PowerShell stager and beacon on sensored Windows hosts, UpdSvc service creation, remote WMI, shell-driven authorized_keys edits and Redis abuse on sensored Linux hosts, and webshell command execution on sensored web servers. Section 15 states the blind spots as gaps.
Defender priority: run Q1, Q3, Q6, Q12 and Q17 across 30 days first (near-zero false positives). Then Q15 and Q16 on every sensored web server, and Q14 to find Redis reachable from the internet. Run the section 7 native checks for the parts no sensor sees: rogue wp2_ administrators, wp2shell_ plugin directories, and authorized_keys on Redis hosts. Nothing in this pack ships at prevent: the whole indicator set originates from one report.
Source Review & Web Hunter Notes
| Tier | Source | Key finding | Carry forward |
|---|---|---|---|
| 1 | SOCRadar: CyberXero, An AI-Augmented Initial Access Broker Targeting Ukrainian Critical Infrastructure (2026-10-06) | Primary source. All infrastructure, hashes, behavioural indicators, TTP table, hunting guidance. Snapshot 01. | Yes |
| 2 | GBHackers: Russian-Speaking CyberXero Uses AI Agent Swarm (2026-10-07) | Secondary. Restates five of the SOCRadar infrastructure IPs and the campaign narrative. Derivative of source 1. Snapshot 02. | Yes (narrative, five IPs) |
| 2 | Security Affairs: CyberXero Used 51 AI Agents to Steal 628,000 Ukrainian Records (2026-10-12) | Secondary. Quotes SOCRadar; confirms scale, victim counts, operator and refusal findings. No indicators. Snapshot 03. | Yes (narrative) |
| 2 | The Hacker News: CyberXero Uses Claude Code in Campaign That Stole Over 628,000 Ukrainian Records (2026-10-12) | Secondary. Confirms the two-pipeline structure, Redis breach of two Chinese entities, CVE delivery vector and hunting advice. Snapshot 04. | Yes (narrative) |
| 2 | eSecurityPlanet: CyberXero Uses Claude Code in Ukraine Data Theft (2026-10-12) | Secondary. Repeats wp2_, wp2shell_ and authorized_keys hunting guidance. Snapshot 05. | Yes (narrative) |
| 1 | MITRE ATT&CK T1098.004, T1505.003, T1543.003, T1047, T1059.001 | Technique names and mitigation IDs used in sections 6 and 12. Snapshots 06 to 10. | Yes |
| 1 | Redis documentation: Redis security | bind, protected mode, requirepass, ACLs, rename-command CONFIG. Snapshot 11. | Yes (hardening) |
| 1 | WordPress Developer Resources: Hardening WordPress | File permissions, DISALLOW_FILE_EDIT, plugin hygiene. Snapshot 12. | Yes (hardening) |
| 1 | Microsoft Learn: about_Logging_Windows | Script block and module logging. Snapshot 13. | Yes (hardening) |
Web Hunter decisions and discrepancies
- One originating report. Every indicator comes from SOCRadar. The four secondary outlets restate it. GBHackers repeats five IPs verbatim, but it credits SOCRadar throughout, so it is not independent corroboration. Result: every indicator ships as detect, nothing at prevent, and confidence is MEDIUM for indicators and HIGH for the behavioural description.
- Record count correction. The task brief gave 628,073 heating-provider records. SOCRadar and the secondary coverage say 564,073 subscriber records plus 213,340 access-log entries at that provider, and more than 628,000 records across four organisations. This pack uses the SOCRadar figures.
- Hash descriptions. SOCRadar lists 71e21094... as
1.binand 59c535f4... asconfig.bin, both Chinese-cluster staging payloads. The stager hash is a cracked Cobalt Strike 4.9.1 build attributed by SOCRadar to Pwn3rs Team. - Scope held to the actor. The CVE list in the source (CVE-2026-63030, CVE-2026-60137, CVE-2026-4815, CVE-2015-1397) is mentioned only as delivery. No detection here targets the REST API flaw.
- Behavioural patterns are not atomic IOCs.
wp2_plus eight hex,wp2shell_plus eight hex and the 13-character stager path are shipped as patterns and queries, not as CSV rows. - Not in the endpoint's view. The Telegram bot notification, the AI session logs, the VLESS/Xray proxy layer and the CryptoPay gateway are actor-side. The pack lists them for context and builds nothing on them.
- Untrusted source content. SOCRadar describes material recovered from the actor's own directory. The pack treats all of it as data: nothing quoted from that directory was executed or fetched, and no value from it reaches an action column.
Hunt Brief & Attack Chain
Hunt hypotheses (ordered by fidelity)
| # | Hypothesis | MITRE | Telemetry | Queries | Confidence |
|---|---|---|---|---|---|
| H1 | A Windows host ran a PowerShell or cmd IEX stager against a CyberXero address or a bare-IP high-port URL. | T1059.001, T1105 | Process creation with command line (CrowdStrike: ProcessRollup2. SentinelOne: Process Creation. Defender: DeviceProcessEvents) | Q1, Q2 | HIGH |
| H2 | A service named UpdSvc, or any service whose binPath downloads and executes, was created and then run by services.exe. | T1543.003 | Service creation (CrowdStrike: CreateService. SentinelOne and Defender: no listed event, use Windows event 7045 or the Services registry key) plus process creation with parent | Q3, Q4, Q5 | HIGH |
| H3 | A sensored host talked to, or accepted a connection from, a published CyberXero address or the team server port set. | T1071.001, T1595.002 | Outbound network connection with process (CrowdStrike: NetworkConnectIP4. SentinelOne: IP Connect. Defender: DeviceNetworkEvents); inbound accepted connection (CrowdStrike: NetworkReceiveAcceptIP4) | Q6, Q7, Q8 | HIGH for IPs, MEDIUM for ports |
| H4 | WMI was used to execute commands remotely on or from a host. | T1047 | Process creation with parent and command line | Q9, Q10 | MEDIUM |
| H5 | A Redis host was reached from the internet, abused through replication or config commands, and had an SSH key injected. | T1190, T1098.004 | Inbound accepted connection; Linux process creation with command line and parent | Q11, Q12, Q13, Q14 | MEDIUM (the Redis-side file write is invisible, see gaps) |
| H6 | A webshell on a sensored web server executed operator commands, at machine pace. | T1505.003 | Process creation with parent (web worker as parent) | Q15, Q16, Q17 | MEDIUM |
| H7 | One of the four published files was present on a sensored host. | T1105, T1027 | File hash on process and file-write events | Q18 | MEDIUM (low yield, see Q18 limit) |
Attack chain
| Step | Behaviour | Telemetry | Hunt angle |
|---|---|---|---|
| 1. Recon | masscan, nuclei and wpscan (SOCRadar) against global ranges and a 95-subdomain Ukrainian energy list; 45.88.106.78 is the mass scanning server | Web and firewall logs; inbound accepted connection on sensored hosts | Q7, native N1 |
| 2. Entry (opportunistic) | wp2shell Python package against WordPress; also Magento, PrestaShop, Support Board. CVE delivery only. | Web server and database logs (outside endpoint telemetry) | Native N2 to N4 |
| 3. Webshell and rogue admin | wp2_ plus eight hex administrator; wp2shell_ plus eight hex plugin; WSO-Shell.php registered as an active plugin | Database, file system; web worker child processes on sensored hosts | Q15, Q16, Q17, N2, N3 |
| 4. Entry (directed / Redis) | Exposed Redis abused by rogue replication (SLAVEOF technique) to inject SSH keys; 42.193.100.94 is the Redis exploitation node | Inbound accepted connection; Linux process creation | Q11, Q12, Q13, Q14, N5 |
| 5. Stager and C2 | PowerShell IEX from 42.193.227.214:8033, Cobalt Strike beacon over 1002 (HTTPS) and 8044 (HTTP) | Process creation; outbound connection | Q1, Q2, Q6, Q8 |
| 6. Persistence | UpdSvc service via svc.cna, binPath is the IEX download | Service creation; process creation with parent services.exe | Q3, Q4, Q5 |
| 7. Lateral movement | WMI remote execution; pass-the-hash via scan_pth.cna | Process creation; authentication telemetry | Q9, Q10; PTH is a gap |
| 8. Collection and exfiltration | Database dumps (MySQL, MongoDB, Redis), hardcoded-credential extractors, Telegram bot notifications | Database and network logs (outside endpoint telemetry) | Gap |
Consolidated IOC Table
Twelve atomic indicators, all from the SOCRadar indicator tables and present in snapshot 01-socradar-cyberxero.txt. All are single-originated, so all ship as detect. Confidence is MEDIUM because the infrastructure is cloud-hosted and perishable. Behavioural patterns follow the atomic rows.
| Type | Value | Confidence | Action | Context | Expiry |
|---|---|---|---|---|---|
| SHA-256 | 92a789444708fa1cb4cc5a89e0aa6cc7a279b62a7b8a4d2857255a18197d0090 | MEDIUM | detect | stager32.bin Cobalt Strike x86 stager (Pwn3rs Team 4.9.1 build). SOCRadar only. | 2027-04-13 |
| SHA-256 | a5ae0aab352871bc0b038b3aa43b03eb223425628c884af7b9fc592cd34eb86c | MEDIUM | detect | WSO-Shell.php WSO webshell obfuscated with R00t-Shell.com 2.0.15. SOCRadar only. | 2027-04-13 |
| SHA-256 | 71e21094c1ac1cf0275c91ed377965e248bca1c12711f6dd20e2682681fc1192 | MEDIUM | detect | 1.bin Chinese-cluster staging payload. SOCRadar only. | 2027-04-13 |
| SHA-256 | 59c535f47ab4d35f6d9fc8b8aec4a72438ea0b89e5a4dcea74b05d2d32cfa483 | MEDIUM | detect | config.bin Chinese-cluster staging payload. SOCRadar only. | 2027-04-13 |
| IPv4 | 46.21.250.135 | MEDIUM | detect | Primary workstation and open directory seed node. SOCRadar, restated by GBHackers (derivative, not independent). | 2027-04-13 |
| IPv4 | 45.88.106.2 | MEDIUM | detect | Provisioning server port 1500. SOCRadar, restated by GBHackers (derivative, not independent). | 2027-04-13 |
| IPv4 | 45.88.106.78 | MEDIUM | detect | Mass scanning server. SOCRadar only. | 2027-04-13 |
| IPv4 | 42.193.227.214 | MEDIUM | detect | Cobalt Strike team server (1002 HTTPS beacon / 8044 HTTP staging / 8033 PS stager / 9995). SOCRadar, restated by GBHackers (derivative, not independent). | 2027-04-13 |
| IPv4 | 42.193.100.94 | MEDIUM | detect | Redis exploitation node and PentAGI agents. SOCRadar only. | 2027-04-13 |
| IPv4 | 49.234.12.182 | MEDIUM | detect | Staging and payload delivery (Chinese cluster). SOCRadar only. | 2027-04-13 |
| IPv4 | 212.193.31.189 | MEDIUM | detect | Multi-chain CryptoPay gateway. SOCRadar, restated by GBHackers (derivative, not independent). | 2027-04-13 |
| IPv4 | 91.208.184.148 | MEDIUM | detect | Secondary workstation. SOCRadar, restated by GBHackers (derivative, not independent). | 2027-04-13 |
Behavioural indicators (patterns, not atomic IOCs)
| Kind | Value | Meaning | Where used |
|---|---|---|---|
| Pattern | wp2_[0-9a-f]{8} | Rogue WordPress administrator username created by wp2shell | Hunt (database, not endpoint) |
| Pattern | /wp-content/plugins/wp2shell_[0-9a-f]{8}/ | wp2shell webshell plugin directory | Hunt (web root file sweep, Q17) |
| Name | WSO-Shell.php | WSO-family webshell registered as an active plugin | Hunt (file sweep, Q17) |
| Name | UpdSvc | Windows service created by the Cobalt Strike svc.cna aggressor script; binPath is a C2 IEX download | Detect (Q3, Q4, Q5) |
| Pattern | http://42.193.227.214:8033/[a-z0-9]{13} | PowerShell IEX stager download URL | Detect (Q1, Q2) |
| Ports | 1002, 8044, 8033, 9995 on 42.193.227.214 | Beacon HTTPS, HTTP staging, stager delivery, team server | Hunt by port set (Q8) |
Affected Surface & Telemetry Matrix
| Surface | Required telemetry | Priority | Gap risk |
|---|---|---|---|
| Sensored Windows servers and workstations reachable by the Cobalt Strike chain | Process creation with command line and parent (CrowdStrike: ProcessRollup2. SentinelOne: Process Creation. Defender: DeviceProcessEvents); service creation (CrowdStrike: CreateService); outbound connection (CrowdStrike: NetworkConnectIP4) | CRITICAL | LOW for stager and service. Service creation is a cross-platform gap: outside endpoint telemetry on SentinelOne and Defender, use Windows event 7045. |
| Sensored Linux web servers running WordPress, Magento or PrestaShop | Process creation with parent (web worker as parent); inbound accepted connection (CrowdStrike: NetworkReceiveAcceptIP4) | CRITICAL | MEDIUM: command execution is visible, the file write of the webshell and the SQL injection are outside endpoint telemetry. |
| Sensored Linux Redis hosts | Process creation with command line and parent; inbound accepted connection | HIGH | HIGH: the Redis save that writes authorized_keys creates no process, and the replication handshake is on the wire. |
| WordPress application and database (wp_users, plugin directory) | Database audit, file integrity, web server access logs | CRITICAL | HIGH: outside endpoint telemetry. Native hunts N2 to N4 are the only coverage. |
| Perimeter and egress (firewall, proxy, DNS) | Connection logs with destination IP and port | HIGH | MEDIUM: the strongest place to see the IP and port set for hosts with no sensor. |
| Identity (NTLM pass-the-hash across segments) | Authentication events with logon type | MEDIUM | HIGH: no query in this pack; scan_pth.cna is documented only as a script name. |
| Actor-side: Telegram notifications, AI session logs, VLESS/Xray, CryptoPay | None on a defender endpoint | INFO | Not observable by a defender sensor. Listed for context only. |
ATT&CK Mapping
| Tactic | Technique | Name | Observed behaviour | Query | Mitigations |
|---|---|---|---|---|---|
| Reconnaissance | T1595.002 | Active Scanning: Vulnerability Scanning | masscan, nuclei, wpscan from 45.88.106.78 | Q7 | Not mapped |
| Initial Access | T1190 | Exploit Public-Facing Application | wp2shell against WordPress; Redis exposure; Magento and others. CVE is delivery only. | Q14 | Native N2 to N5 |
| Execution | T1059.001 | PowerShell | IEX stager from 42.193.227.214:8033 | Q1, Q2 | M1038, M1045, M1049, M1042, M1026 |
| Execution | T1047 | Windows Management Instrumentation | WMI remote execution on compromised hosts | Q9, Q10 | M1040, M1038, M1026, M1018 |
| Persistence | T1543.003 | Create or Modify System Process: Windows Service | UpdSvc via svc.cna | Q3, Q4, Q5 | M1047, M1040, M1045, M1028, M1018 |
| Persistence | T1505.003 | Server Software Component: Web Shell | WSO and wp2shell webshells as active WordPress plugins | Q15, Q16, Q17 | M1042, M1018 |
| Persistence | T1098.004 | Account Manipulation: SSH Authorized Keys | Key injected through rogue Redis replication | Q11, Q12, Q13 | M1042, M1022, M1018 |
| Persistence | T1136.001 | Create Account: Local Account | Rogue wp2_ plus eight hex WordPress administrators | Q17 (weak), N2 | Native only |
| Command and Control | T1071.001 | Application Layer Protocol: Web Protocols | Beacon on 1002 (HTTPS) and 8044 (HTTP) to 42.193.227.214 | Q6, Q8 | Egress control (best practice) |
| Command and Control | T1102.002 | Web Service: Bidirectional Communication | Telegram bot notification (actor side) | None | Not observable |
| Lateral Movement | T1550.002 | Pass the Hash | scan_pth.cna across internal segments | None | Gap |
| Defense Evasion | T1027 | Obfuscated Files or Information | WSO obfuscated with R00t-Shell.com 2.0.15 | Q18 (low yield) | Not mapped |
Technique IDs and the M-code lists for T1098.004, T1505.003, T1543.003, T1047 and T1059.001 were read from the saved MITRE snapshots (06 to 10). Other technique IDs follow the SOCRadar TTP table in snapshot 01. Rows marked best practice or native have no MITRE-listed preventive mitigation in the saved pages.
Native Audit-Log Hunts
The parts of the chain with no endpoint query. All checks are read-only. Run them on the web, database and Redis hosts, or through your RMM.
| # | Check | Where | What a hit means |
|---|---|---|---|
| N1 | Firewall, proxy and DNS logs for the eight published IPs and the port set 1002, 8033, 8044, 9995 to 42.193.227.214 | Perimeter / egress | Contact with CyberXero infrastructure from a host that may have no sensor |
| N2 | WordPress administrators matching ^wp2_[0-9a-f]{8}$ (wp-cli or SQL on wp_users, plus capability check) | WordPress database | Rogue administrator created by wp2shell. Strongest single indicator in the SOCRadar report. |
| N3 | Plugin directories matching wp2shell_[0-9a-f]{8} and any file named WSO-Shell.php; active plugin list diff against your approved list | Web root file system, wp option active_plugins | Deployed webshell. Preserve the file before removal. |
| N4 | Web access logs: requests into /wp-content/plugins/wp2shell_*/, and bursts of POSTs to the REST batch route followed by a new plugin request within seconds | Web server logs | Webshell use. Only the 61-second burst tempo is specific to this actor; the CVE route is covered by the separate pack. |
| N5 | Redis hosts: authorized_keys entries nobody can attribute, file modification time on ~/.ssh/authorized_keys, and INFO replication showing an unexpected master | Linux Redis servers | Rogue replication outcome. This is the only coverage of the Redis-side file write. |
| N6 | Windows: service named UpdSvc, event 7045 or 4697 with a PowerShell or cmd binPath, PowerShell script block events (4104) containing IEX against a bare IP | Windows event logs | Stager and persistence on hosts with no sensor |
| N7 | Review exposed AI agent session logs and tokens if you run agents with terminal access (SOCRadar guidance) | Your own agent hosts | Hygiene, not detection |
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.
18 queries. Windows service, process and network queries run on any sensored OS where noted; Q11 to Q13 are Linux specific, Q15 and Q16 cover both. Windows paths use FileName regexes so no path separators appear in a pattern. Event names were taken from the crowdstrike-logscale-v3 references and the linter's known-event list.
Looks for: Any process whose command line names a CyberXero IP (team server, Redis node, staging node, provisioning, scanner or workstation). The stager URL and the UpdSvc binPath both carry the team server address, so this single filter catches the stager, the service persistence and a hand-typed beacon launch. FP: None expected. The only benign hit is an analyst pasting a published IOC into a test command.
Known limitations and deployment notes
- PowerQuery: An address written in hex, as a decimal integer or defanged is not matched.
- PowerQuery assumes: tgt.process.cmdline holds the full command line of the created process.
- KQL – Defender XDR: An address written in hex, as a decimal integer or defanged is not matched.
- KQL – Defender XDR assumes: ProcessCommandLine holds the full command line of the created process.
// HUNT: Process command line references CyberXero infrastructure (CyberXero) // MITRE: T1059.001, T1105, T1071.001 // CONF: high FP: low COST: low // REQUIRES: Process creation with command line (ProcessRollup2) // FALSE POSITIVES: None expected: published attacker-owned addresses. // LOOKBACK: 30d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | CommandLine=/(42\.193\.227\.214|42\.193\.100\.94|49\.234\.12\.182|46\.21\.250\.135|45\.88\.106\.2\b|45\.88\.106\.78|212\.193\.31\.189|91\.208\.184\.148)/ | table([@timestamp, aid, ComputerName, UserName, FileName, CommandLine, ParentBaseFileName]) | sort(@timestamp, order=desc)
2 required fields · View requirements
Required telemetry
- Process Creation events
Required fields
event.type: Event typetgt.process.cmdline: Created command line
Recommended fields
tgt.process.name: Created process namesrc.process.name: Creator process name
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'Process Creation' tgt.process.cmdline = * | limit 5 | columns event.type, tgt.process.cmdline
// HUNT: Process command line references CyberXero infrastructure (CyberXero) // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1059.001, T1105, T1071.001 // CONF: high | FP: low // FALSE POSITIVES: None expected: published attacker-owned addresses. // EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: any of the eight published addresses in the created process's command line. matches is case-insensitive, and 45.88.106.2 keeps its word boundary as in the CQL. // REQUIRES: SentinelOne process-creation telemetry with the command line // TUNING: None expected: the addresses are published attacker infrastructure. Review any hit before closing it. // LOOKBACK: 30d // CONFIGURATION: No lookup objects required. // KNOWN GAPS: An address written in hex, as a decimal integer or defanged is not matched. // VALIDATION LEVEL: static-reviewed event.type = 'Process Creation' tgt.process.cmdline matches '(42\\.193\\.227\\.214|42\\.193\\.100\\.94|49\\.234\\.12\\.182|46\\.21\\.250\\.135|45\\.88\\.106\\.2\\b|45\\.88\\.106\\.78|212\\.193\\.31\\.189|91\\.208\\.184\\.148)' | columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdline | sort -event.time | limit 200
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: Process command line references CyberXero infrastructure (CyberXero) // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1059.001, T1105, T1071.001 // CONF: high | FP: low // FALSE POSITIVES: None expected: published attacker-owned addresses. // EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: any of the eight published addresses in the created process's command line, with the word boundary kept on 45.88.106.2. // REQUIRES: Defender for Endpoint process-creation telemetry (DeviceProcessEvents) // TUNING: None expected: the addresses are published attacker infrastructure. Review any hit before closing it. // LOOKBACK: 30d // CONFIGURATION: No lookup objects required. // KNOWN GAPS: An address written in hex, as a decimal integer or defanged is not matched. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceProcessEvents | where Timestamp >= ago(30d) | where ProcessCommandLine matches regex @"(42\.193\.227\.214|42\.193\.100\.94|49\.234\.12\.182|46\.21\.250\.135|45\.88\.106\.2\b|45\.88\.106\.78|212\.193\.31\.189|91\.208\.184\.148)" | project Timestamp, ReportId, DeviceId, DeviceName, AccountName, FileName, ProcessCommandLine, InitiatingProcessFileName | sort by Timestamp desc | take 200
Looks for: The stager shape, independent of the exact IP: a scripting host running IEX or DownloadString against a URL whose host is a raw IPv4 address on a non-default port. SOCRadar documents http://42.193.227.214:8033/ plus 13 lowercase alphanumerics; infrastructure rotates, the shape does not. The second regex pins the documented path shape. FP: Internal admin scripts that pull from an artifact server by IP and port. Exclude your own internal ranges and known build hosts (see the TUNING line in the query).
Known limitations and deployment notes
- PowerQuery: A download whose URL is assembled at run time is not matched.
- PowerQuery assumes: endpoint.os carries the value windows for Windows agents.
- PowerQuery assumes: The URL is matched as plain text in the command line, so a URL built at run time from variables is not seen.
- KQL – Defender XDR: A download whose URL is assembled at run time is not matched.
- KQL – Defender XDR assumes: Windows sensors report the image name with the .exe suffix, so no separate platform predicate is needed.
- KQL – Defender XDR assumes: The URL is matched as plain text in the command line.
// HUNT: PowerShell or cmd IEX download from a bare-IP URL with a high port (CyberXero) // MITRE: T1059.001, T1105 // CONF: medium FP: medium COST: low // REQUIRES: Process creation with command line (ProcessRollup2) // FALSE POSITIVES: Internal artifact servers addressed by IP and port. TUNING below. // TUNING: drop internal destinations with the commented CommandLine!=/.../ line once your artifact-server list is known; do not exclude by FileName alone // LOOKBACK: 14d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | event_platform=Win | FileName=/^(powershell|pwsh|cmd)(\.exe)?$/i | CommandLine=/(\biex\b|invoke-expression|downloadstring|net\.webclient|invoke-webrequest|\biwr\b)/i | CommandLine=/https?:\/\/[0-9]{1,3}(\.[0-9]{1,3}){3}:[0-9]{2,5}\b/i // | CommandLine!=/https?:\/\/(10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.)/i | table([@timestamp, aid, ComputerName, UserName, FileName, CommandLine, ParentBaseFileName])
4 required fields · View requirements
Required telemetry
- Process Creation events
Required fields
event.type: Event typeendpoint.os: Operating systemtgt.process.name: Created process nametgt.process.cmdline: Created command line
Recommended fields
src.process.name: Creator process name
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'Process Creation' endpoint.os = * tgt.process.name = * tgt.process.cmdline = * | limit 5 | columns event.type, endpoint.os, tgt.process.name, tgt.process.cmdline
// HUNT: PowerShell or cmd IEX download from a bare-IP URL with a high port (CyberXero)
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1059.001, T1105
// CONF: medium | FP: medium
// FALSE POSITIVES: Internal artifact servers addressed by IP and port. TUNING below.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate on Windows: PowerShell or cmd carrying a download-and-execute token and an http(s) URL whose host is a bare IPv4 address with an explicit port. matches is case-insensitive, which reproduces the CQL /i intent.
// REQUIRES: SentinelOne process-creation telemetry with the command line
// TUNING: Drop internal artifact servers by destination address once your artifact-server list is known. Do not exclude by process name alone.
// LOOKBACK: 14d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A download whose URL is assembled at run time is not matched.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation'
endpoint.os in:anycase ('windows')
tgt.process.name in:anycase ('powershell.exe', 'pwsh.exe', 'cmd.exe', 'powershell', 'pwsh', 'cmd')
tgt.process.cmdline matches '(\\biex\\b|invoke-expression|downloadstring|net\\.webclient|invoke-webrequest|\\biwr\\b)'
tgt.process.cmdline matches 'https?:[/][/][0-9]{1,3}(\\.[0-9]{1,3}){3}:[0-9]{2,5}\\b'
| columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdline
| sort -event.time
| limit 200Automated 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: PowerShell or cmd IEX download from a bare-IP URL with a high port (CyberXero)
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1059.001, T1105
// CONF: medium | FP: medium
// FALSE POSITIVES: Internal artifact servers addressed by IP and port. TUNING below.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: PowerShell or cmd carrying a download-and-execute token and an http(s) URL whose host is a bare IPv4 address with an explicit port. The (?i) prefix reproduces the CQL /i intent. The Windows platform predicate is carried by the .exe image names.
// REQUIRES: Defender for Endpoint process-creation telemetry (DeviceProcessEvents)
// TUNING: Drop internal artifact servers by destination address once your artifact-server list is known. Do not exclude by process name alone.
// LOOKBACK: 14d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A download whose URL is assembled at run time is not matched.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceProcessEvents
| where Timestamp >= ago(14d)
| where FileName in~ ("powershell.exe", "pwsh.exe", "cmd.exe")
| where ProcessCommandLine matches regex @"(?i)(\biex\b|invoke-expression|downloadstring|net\.webclient|invoke-webrequest|\biwr\b)"
| where ProcessCommandLine matches regex @"(?i)https?://[0-9]{1,3}(\.[0-9]{1,3}){3}:[0-9]{2,5}\b"
| project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine
| sort by Timestamp desc
| take 200Looks for: The named persistence from the SOCRadar indicator table: a Windows service called UpdSvc whose binPath is a C2 IEX download. Also matches any new service whose image path contains the team server address. FP: UpdSvc is a plausible name for a vendor updater. Confirm by the ServiceImagePath: a PowerShell or cmd binPath with a URL is hostile, a vendor binary under Program Files is not.
Known limitations and deployment notes
- PowerQuery: A service created through an API path that writes no observed registry value is not seen.
- PowerQuery: The CQL service-created event is not available in this schema.
- PowerQuery assumes: registry.keyPath ends in the service name or in the service name plus the value name, and registry.value holds the data written.
- PowerQuery assumes: Registry Value Modified events under the Services key are collected on the tenant.
- KQL – Defender XDR: A service created through an API path that writes no observed registry value is not seen.
- KQL – Defender XDR: The CQL service-created event has no direct Defender equivalent.
- KQL – Defender XDR assumes: RegistryKey holds the full key path, so a service key ends in the service name.
- KQL – Defender XDR assumes: RegistryValueSet is the ActionType recorded when a service value is written.
// HUNT: UpdSvc service created (Cobalt Strike svc.cna persistence) (CyberXero) // MITRE: T1543.003, T1059.001 // CONF: high FP: low COST: low // REQUIRES: Service creation (CreateService) // FALSE POSITIVES: A vendor updater legitimately named UpdSvc (check ServiceImagePath). // LOOKBACK: 30d #event_simpleName=CreateService | ServiceName=/^UpdSvc$/i or ServiceDisplayName=/^UpdSvc$/i or ServiceImagePath=/42\.193\.227\.214/ | table([@timestamp, aid, ComputerName, UserName, ServiceName, ServiceDisplayName, ServiceImagePath]) | sort(@timestamp, order=desc)
3 required fields · View requirements
Required telemetry
- Registry Value Modified events
Required fields
event.type: Event typeregistry.keyPath: Registry key pathregistry.value: Registry value
Recommended fields
src.process.name: Writer process name
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'Registry Value Modified' registry.keyPath = * registry.value = * | limit 5 | columns event.type, registry.keyPath, registry.value
// HUNT: UpdSvc service created (Cobalt Strike svc.cna persistence) (CyberXero) // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1543.003, T1059.001 // CONF: high | FP: low // FALSE POSITIVES: A vendor updater legitimately named UpdSvc (check ServiceImagePath). // EQUIVALENCE: approximate-analytic - SentinelOne has no service-creation event in the attested field model. The service exists as a value written under the Services registry key, so the hunt reads Registry Value Modified: a key named UpdSvc, a value equal to UpdSvc (display name), or a value naming 42.193.227.214 (image path). The CQL reads the CreateService event directly. // REQUIRES: SentinelOne registry telemetry for HKLM Services keys (Registry Value Modified) // TUNING: A vendor updater legitimately named UpdSvc is the known false positive: check the image path value before escalating. // LOOKBACK: 30d // CONFIGURATION: No lookup objects required. // KNOWN GAPS: A service created through an API path that writes no observed registry value is not seen. The CQL service-created event is not available in this schema. // VALIDATION LEVEL: static-reviewed event.type = 'Registry Value Modified' registry.keyPath matches '\\\\Services\\\\' (registry.keyPath matches '\\\\Services\\\\UpdSvc(\\\\|$)' or registry.value matches '^UpdSvc$' or registry.value matches '42\\.193\\.227\\.214') | columns event.time, endpoint.name, src.process.name, registry.keyPath, registry.value | sort -event.time | limit 200
Automated validation: static-passed
4 required fields · View requirements
Required telemetry
- DeviceRegistryEvents
Required fields
Timestamp: Event timeActionType: Action typeRegistryKey: Registry keyRegistryValueData: Registry value data
Recommended fields
InitiatingProcessFileName: Writer process
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceRegistryEvents | where Timestamp > ago(1d) | project Timestamp, ActionType, RegistryKey, RegistryValueData | take 5
// HUNT: UpdSvc service created (Cobalt Strike svc.cna persistence) (CyberXero) // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1543.003, T1059.001 // CONF: high | FP: low // FALSE POSITIVES: A vendor updater legitimately named UpdSvc (check ServiceImagePath). // EQUIVALENCE: approximate-analytic - ServiceInstalled is recorded only when the Audit Security System Extension policy is deployed, so the hunt reads the registry write that creates the service instead: a key named UpdSvc, a value equal to UpdSvc (display name), or a value naming 42.193.227.214 (image path). // REQUIRES: Defender for Endpoint registry telemetry (DeviceRegistryEvents) // TUNING: A vendor updater legitimately named UpdSvc is the known false positive: check the image path value before escalating. // LOOKBACK: 30d // CONFIGURATION: No lookup objects required. // KNOWN GAPS: A service created through an API path that writes no observed registry value is not seen. The CQL service-created event has no direct Defender equivalent. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceRegistryEvents | where Timestamp >= ago(30d) | where ActionType == "RegistryValueSet" | where RegistryKey matches regex @"(?i)\\Services\\" | where RegistryKey matches regex @"(?i)\\Services\\UpdSvc$" or RegistryValueData matches regex @"(?i)^UpdSvc$" or RegistryValueData contains "42.193.227.214" | project Timestamp, ReportId, DeviceId, DeviceName, InitiatingProcessAccountName, InitiatingProcessFileName, RegistryKey, RegistryValueName, RegistryValueData | sort by Timestamp desc | take 200
Looks for: The behavioral form of UpdSvc: any new service whose image path launches PowerShell, cmd, mshta or rundll32 AND carries an IEX, download, encoded-command or URL token. Survives a rename of the service. FP: Some backup, RMM and deployment tools wrap a PowerShell one-liner in a service. Exclude by the known vendor ServiceName.
Known limitations and deployment notes
- PowerQuery: A service created through an API path that writes no observed registry value is not seen.
- PowerQuery: The CQL service-created event is not available in this schema.
- PowerQuery assumes: registry.keyPath holds the key path and registry.value holds the data written.
- PowerQuery assumes: The value is not restricted to ImagePath because the keyPath and valueName split is not verified on a tenant; the scripting-host and download predicates narrow it to the same rows in practice.
- KQL – Defender XDR: A service created through an API path that writes no observed registry value is not seen.
- KQL – Defender XDR: The CQL service-created event has no direct Defender equivalent.
- KQL – Defender XDR assumes: RegistryValueSet is the ActionType recorded when a service value is written.
- KQL – Defender XDR assumes: The value is not restricted to ImagePath; the scripting-host and download predicates narrow it to the same rows in practice.
// HUNT: Service created with a scripting-host binPath that downloads or decodes (CyberXero) // MITRE: T1543.003, T1059.001 // CONF: medium FP: medium COST: low // REQUIRES: Service creation (CreateService) // FALSE POSITIVES: Vendor tools that wrap a PowerShell command in a service. // TUNING: allowlist the vendor ServiceName values you find in your first run with the commented ServiceName!=/.../ line // LOOKBACK: 30d #event_simpleName=CreateService | ServiceImagePath=/(powershell|pwsh|mshta|rundll32|cmd(\.exe)?\s+.c\s)/i | ServiceImagePath=/(\biex\b|invoke-expression|downloadstring|frombase64string|-e(nc|ncodedcommand)?\s|https?:)/i // | ServiceName!=/^(ExampleVendorAgent|ExampleBackupSvc)$/i | table([@timestamp, aid, ComputerName, UserName, ServiceName, ServiceDisplayName, ServiceImagePath])
3 required fields · View requirements
Required telemetry
- Registry Value Modified events
Required fields
event.type: Event typeregistry.keyPath: Registry key pathregistry.value: Registry value
Recommended fields
src.process.name: Writer process name
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'Registry Value Modified' registry.keyPath = * registry.value = * | limit 5 | columns event.type, registry.keyPath, registry.value
// HUNT: Service created with a scripting-host binPath that downloads or decodes (CyberXero) // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1543.003, T1059.001 // CONF: medium | FP: medium // FALSE POSITIVES: Vendor tools that wrap a PowerShell command in a service. // EQUIVALENCE: approximate-analytic - SentinelOne has no service-creation event in the attested field model, so the hunt reads the Registry Value Modified write under the Services key and applies both CQL predicates to the value: a scripting-host binary path, and a download or decode token. The CQL reads the ImagePath of the CreateService event directly. // REQUIRES: SentinelOne registry telemetry for HKLM Services keys (Registry Value Modified) // TUNING: Allowlist the vendor service key names found in the first run. Keep the download-token requirement so only downloaders remain. // LOOKBACK: 30d // CONFIGURATION: No lookup objects required. // KNOWN GAPS: A service created through an API path that writes no observed registry value is not seen. The CQL service-created event is not available in this schema. // VALIDATION LEVEL: static-reviewed event.type = 'Registry Value Modified' registry.keyPath matches '\\\\Services\\\\' registry.value matches '(powershell|pwsh|mshta|rundll32|cmd(\\.exe)?\\s+.c\\s)' registry.value matches '(\\biex\\b|invoke-expression|downloadstring|frombase64string|-e(nc|ncodedcommand)?\\s|https?:)' | columns event.time, endpoint.name, src.process.name, registry.keyPath, registry.value | sort -event.time | limit 200
Automated validation: static-passed
4 required fields · View requirements
Required telemetry
- DeviceRegistryEvents
Required fields
Timestamp: Event timeActionType: Action typeRegistryKey: Registry keyRegistryValueData: Registry value data
Recommended fields
InitiatingProcessFileName: Writer process
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceRegistryEvents | where Timestamp > ago(1d) | project Timestamp, ActionType, RegistryKey, RegistryValueData | take 5
// HUNT: Service created with a scripting-host binPath that downloads or decodes (CyberXero) // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1543.003, T1059.001 // CONF: medium | FP: medium // FALSE POSITIVES: Vendor tools that wrap a PowerShell command in a service. // EQUIVALENCE: approximate-analytic - ServiceInstalled is recorded only when the Audit Security System Extension policy is deployed, so the hunt reads the registry write that creates the service and applies both CQL predicates to the value: a scripting-host binary path and a download or decode token. // REQUIRES: Defender for Endpoint registry telemetry (DeviceRegistryEvents) // TUNING: Allowlist the vendor service key names found in the first run. Keep the download-token requirement so only downloaders remain. // LOOKBACK: 30d // CONFIGURATION: No lookup objects required. // KNOWN GAPS: A service created through an API path that writes no observed registry value is not seen. The CQL service-created event has no direct Defender equivalent. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceRegistryEvents | where Timestamp >= ago(30d) | where ActionType == "RegistryValueSet" | where RegistryKey matches regex @"(?i)\\Services\\" | where RegistryValueData matches regex @"(?i)(powershell|pwsh|mshta|rundll32|cmd(\.exe)?\s+.c\s)" | where RegistryValueData matches regex @"(?i)(\biex\b|invoke-expression|downloadstring|frombase64string|-e(nc|ncodedcommand)?\s|https?:)" | project Timestamp, ReportId, DeviceId, DeviceName, InitiatingProcessAccountName, InitiatingProcessFileName, RegistryKey, RegistryValueName, RegistryValueData | sort by Timestamp desc | take 200
Looks for: Execution side of the service persistence: services.exe is the parent, the child is a scripting host, and the command line carries an IEX, download or URL token. Pairs with Q3 and Q4, which see the creation. FP: Service wrappers from RMM and management agents. Exclude by the exact command line your vendor uses.
Known limitations and deployment notes
- PowerQuery: A service wrapper that launches the script host through an intermediate process is not matched.
- PowerQuery assumes: endpoint.os carries the value windows for Windows agents.
- KQL – Defender XDR: A service wrapper that launches the script host through an intermediate process is not matched.
- KQL – Defender XDR assumes: Windows sensors report the image name with the .exe suffix, so no separate platform predicate is needed.
// HUNT: Script host spawned by services.exe with a download or decode token (CyberXero) // MITRE: T1543.003, T1059.001 // CONF: medium FP: medium COST: low // REQUIRES: Process creation with parent (ProcessRollup2) // FALSE POSITIVES: Management-agent service wrappers. // TUNING: exclude the exact CommandLine of approved agents; keep the URL token requirement so only downloaders remain // LOOKBACK: 14d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | event_platform=Win | ParentBaseFileName=/^services\.exe$/i | FileName=/^(powershell|pwsh|cmd|mshta|rundll32)(\.exe)?$/i | CommandLine=/(\biex\b|invoke-expression|downloadstring|frombase64string|https?:)/i | table([@timestamp, aid, ComputerName, UserName, FileName, CommandLine, ParentBaseFileName])
5 required fields · View requirements
Required telemetry
- Process Creation events
Required fields
event.type: Event typeendpoint.os: Operating systemsrc.process.name: Creator process nametgt.process.name: Created process nametgt.process.cmdline: Created command line
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'Process Creation' endpoint.os = * src.process.name = * tgt.process.name = * tgt.process.cmdline = * | limit 5 | columns event.type, endpoint.os, src.process.name, tgt.process.name, tgt.process.cmdline
// HUNT: Script host spawned by services.exe with a download or decode token (CyberXero)
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1543.003, T1059.001
// CONF: medium | FP: medium
// FALSE POSITIVES: Management-agent service wrappers.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate on Windows: a script host or LOLBin created by services.exe whose command line has a download or decode token. On a Process Creation event the created process is tgt.process.* and its creator, services.exe, is src.process.*.
// REQUIRES: SentinelOne process-creation telemetry with the creator process and command line
// TUNING: Exclude the exact command line of approved management agents. Keep the URL token requirement so only downloaders remain.
// LOOKBACK: 14d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A service wrapper that launches the script host through an intermediate process is not matched.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation'
endpoint.os in:anycase ('windows')
src.process.name in:anycase ('services.exe')
tgt.process.name in:anycase ('powershell.exe', 'pwsh.exe', 'cmd.exe', 'mshta.exe', 'rundll32.exe', 'powershell', 'pwsh', 'cmd', 'mshta', 'rundll32')
tgt.process.cmdline matches '(\\biex\\b|invoke-expression|downloadstring|frombase64string|https?:)'
| columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdline
| sort -event.time
| limit 200Automated validation: static-passed
4 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeInitiatingProcessFileName: Creator process nameFileName: 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, ProcessCommandLine | take 5
// HUNT: Script host spawned by services.exe with a download or decode token (CyberXero)
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1543.003, T1059.001
// CONF: medium | FP: medium
// FALSE POSITIVES: Management-agent service wrappers.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: a script host or LOLBin created by services.exe whose command line has a download or decode token. The creator is InitiatingProcessFileName.
// REQUIRES: Defender for Endpoint process-creation telemetry (DeviceProcessEvents)
// TUNING: Exclude the exact command line of approved management agents. Keep the URL token requirement so only downloaders remain.
// LOOKBACK: 14d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A service wrapper that launches the script host through an intermediate process is not matched.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceProcessEvents
| where Timestamp >= ago(14d)
| where InitiatingProcessFileName =~ "services.exe"
| where FileName in~ ("powershell.exe", "pwsh.exe", "cmd.exe", "mshta.exe", "rundll32.exe")
| where ProcessCommandLine matches regex @"(?i)(\biex\b|invoke-expression|downloadstring|frombase64string|https?:)"
| project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine
| sort by Timestamp desc
| take 200Looks for: Retrospective sweep of all eight CyberXero addresses on every sensored OS. Role map: 42.193.227.214 team server (1002 HTTPS beacon, 8044 HTTP staging, 8033 PowerShell stager, 9995 team server); 42.193.100.94 Redis exploitation; 49.234.12.182 staging; 46.21.250.135 workstation and open directory; 45.88.106.2 provisioning; 45.88.106.78 scanner; 212.193.31.189 payment gateway; 91.208.184.148 secondary workstation. Perishable: rotate the list as infrastructure is retired. FP: None expected.
Known limitations and deployment notes
- PowerQuery: Traffic that never reaches the endpoint sensor, such as a connection from a device with no agent, is not seen.
- PowerQuery assumes: dst.ip.address is the remote address of an outbound IP Connect event.
- KQL – Defender XDR: Traffic that never reaches the endpoint sensor, such as a connection from a device with no agent, is not seen.
- KQL – Defender XDR assumes: ConnectionSuccess, ConnectionFailed and ConnectionRequest are the outbound action types recorded on the tenant.
// HUNT: Outbound connection to a published CyberXero address (CyberXero) // MITRE: T1071.001, T1105, T1090 // CONF: high FP: low COST: low // REQUIRES: Outbound network connection with process (NetworkConnectIP4) // FALSE POSITIVES: None expected: published attacker-owned addresses. // LOOKBACK: 30d #event_simpleName=NetworkConnectIP4 | in(field=RemoteAddressIP4, values=["46.21.250.135","45.88.106.2","45.88.106.78","42.193.227.214","42.193.100.94","49.234.12.182","212.193.31.189","91.208.184.148"]) | table([@timestamp, aid, ComputerName, event_platform, ContextBaseFileName, RemoteAddressIP4, RemotePort, LocalAddressIP4]) | sort(@timestamp, order=desc)
2 required fields · View requirements
Required telemetry
- IP Connect events
Required fields
event.type: Event typedst.ip.address: Destination address
Recommended fields
src.process.name: Owning process namedst.port.number: Destination port
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'IP Connect' dst.ip.address = * | limit 5 | columns event.type, dst.ip.address, dst.port.number
// HUNT: Outbound connection to a published CyberXero address (CyberXero)
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1071.001, T1105, T1090
// CONF: high | FP: low
// FALSE POSITIVES: None expected: published attacker-owned addresses.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same network predicate: an endpoint connection whose destination is one of the eight published addresses. The process that opened the connection is src.process.* on a non-process event.
// REQUIRES: SentinelOne network telemetry (IP Connect) with the owning process
// TUNING: None expected: the addresses are published attacker infrastructure. Review any hit before closing it.
// LOOKBACK: 30d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: Traffic that never reaches the endpoint sensor, such as a connection from a device with no agent, is not seen.
// VALIDATION LEVEL: static-reviewed
event.type = 'IP Connect'
dst.ip.address in ('46.21.250.135', '45.88.106.2', '45.88.106.78', '42.193.227.214', '42.193.100.94', '49.234.12.182', '212.193.31.189', '91.208.184.148')
| columns event.time, endpoint.name, src.process.name, src.ip.address, dst.ip.address, dst.port.number
| sort -event.time
| limit 200Automated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceNetworkEvents
Required fields
Timestamp: Event timeActionType: Action typeRemoteIP: Remote address
Recommended fields
InitiatingProcessFileName: Owning processRemotePort: Remote port
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceNetworkEvents | where Timestamp > ago(1d) | project Timestamp, ActionType, RemoteIP, RemotePort | take 5
// HUNT: Outbound connection to a published CyberXero address (CyberXero)
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1071.001, T1105, T1090
// CONF: high | FP: low
// FALSE POSITIVES: None expected: published attacker-owned addresses.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same network predicate: an endpoint connection whose remote address is one of the eight published addresses, limited to outbound connection action types so inbound accepts stay with the next card.
// REQUIRES: Defender for Endpoint network telemetry (DeviceNetworkEvents)
// TUNING: None expected: the addresses are published attacker infrastructure. Review any hit before closing it.
// LOOKBACK: 30d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: Traffic that never reaches the endpoint sensor, such as a connection from a device with no agent, is not seen.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceNetworkEvents
| where Timestamp >= ago(30d)
| where ActionType in ("ConnectionSuccess", "ConnectionFailed", "ConnectionRequest")
| where RemoteIP in ("46.21.250.135", "45.88.106.2", "45.88.106.78", "42.193.227.214", "42.193.100.94", "49.234.12.182", "212.193.31.189", "91.208.184.148")
| project Timestamp, ReportId, DeviceId, DeviceName, InitiatingProcessFileName, RemoteIP, RemotePort, LocalIP
| sort by Timestamp desc
| take 200Looks for: A sensored internet-facing host accepted a connection from the scanner (45.88.106.78), the workstation, or the Redis and staging nodes. This is where a sensored web server or Redis host shows evidence of CyberXero touching it. Scan hits alone are not compromise: follow with Q15, Q16 and Q13 on the same aid. FP: Low. A scan hit on an exposed host is expected for an internet-facing system and is context, not proof of compromise.
Known limitations and deployment notes
- PowerQuery: If the tenant does not populate the direction field the query returns nothing, which reads as a clean estate.
- PowerQuery assumes: event.network.direction is populated and holds INCOMING for accepted inbound connections.
- PowerQuery assumes: src.ip.address is the remote peer and dst.ip.address and dst.port.number are the local listener on an incoming event.
- KQL – Defender XDR: If the tenant does not record InboundConnectionAccepted the query returns nothing, which reads as a clean estate.
- KQL – Defender XDR assumes: InboundConnectionAccepted is recorded on the tenant; it is attested in Microsoft-owned hunting repositories but not listed on the table's Learn page.
// HUNT: Inbound connection accepted from a published CyberXero address (CyberXero) // MITRE: T1595.002, T1190, T1021.004 // CONF: medium FP: low COST: low // REQUIRES: Inbound accepted connection (NetworkReceiveAcceptIP4) // FALSE POSITIVES: Scan hits against internet-facing hosts are context only. // LOOKBACK: 30d #event_simpleName=NetworkReceiveAcceptIP4 | in(field=RemoteAddressIP4, values=["46.21.250.135","45.88.106.2","45.88.106.78","42.193.227.214","42.193.100.94","49.234.12.182","212.193.31.189","91.208.184.148"]) | table([@timestamp, aid, ComputerName, event_platform, ContextBaseFileName, RemoteAddressIP4, LocalPort, LocalAddressIP4]) | sort(@timestamp, order=desc)
3 required fields · View requirements
Required telemetry
- IP Connect events
Required fields
event.type: Event typeevent.network.direction: Connection directionsrc.ip.address: Remote peer address
Recommended fields
dst.port.number: Local port
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'IP Connect' event.network.direction = * src.ip.address = * | limit 5 | columns event.type, event.network.direction, src.ip.address, dst.port.number
// HUNT: Inbound connection accepted from a published CyberXero address (CyberXero)
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1595.002, T1190, T1021.004
// CONF: medium | FP: low
// FALSE POSITIVES: Scan hits against internet-facing hosts are context only.
// EQUIVALENCE: approximate-analytic - The CQL reads an accepted-inbound-connection event. SentinelOne reports it as an IP Connect event whose direction is incoming, with the remote peer in the source address. The direction field and its value are documented but not seen in shipped queries, so the match is an approximation until confirmed on a tenant.
// REQUIRES: SentinelOne network telemetry (IP Connect) with the connection direction
// TUNING: Scan hits against internet-facing hosts are context only. Pair a hit with a successful logon or a process event on the same host before escalating.
// LOOKBACK: 30d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: If the tenant does not populate the direction field the query returns nothing, which reads as a clean estate.
// VALIDATION LEVEL: static-reviewed
event.type = 'IP Connect'
event.network.direction in:anycase ('incoming')
src.ip.address in ('46.21.250.135', '45.88.106.2', '45.88.106.78', '42.193.227.214', '42.193.100.94', '49.234.12.182', '212.193.31.189', '91.208.184.148')
| columns event.time, endpoint.name, src.process.name, src.ip.address, dst.ip.address, dst.port.number
| sort -event.time
| limit 200Automated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceNetworkEvents
Required fields
Timestamp: Event timeActionType: Action typeRemoteIP: Remote address
Recommended fields
LocalPort: Local port
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceNetworkEvents | where Timestamp > ago(1d) | where ActionType == "InboundConnectionAccepted" | project Timestamp, ActionType, RemoteIP, LocalPort | take 5
// HUNT: Inbound connection accepted from a published CyberXero address (CyberXero)
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1595.002, T1190, T1021.004
// CONF: medium | FP: low
// FALSE POSITIVES: Scan hits against internet-facing hosts are context only.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same network predicate: an accepted inbound connection whose remote address is one of the eight published addresses. InboundConnectionAccepted is the action type for an accepted inbound connection.
// REQUIRES: Defender for Endpoint network telemetry (DeviceNetworkEvents)
// TUNING: Scan hits against internet-facing hosts are context only. Pair a hit with a successful logon or a process event on the same host before escalating.
// LOOKBACK: 30d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: If the tenant does not record InboundConnectionAccepted the query returns nothing, which reads as a clean estate.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceNetworkEvents
| where Timestamp >= ago(30d)
| where ActionType == "InboundConnectionAccepted"
| where RemoteIP in ("46.21.250.135", "45.88.106.2", "45.88.106.78", "42.193.227.214", "42.193.100.94", "49.234.12.182", "212.193.31.189", "91.208.184.148")
| project Timestamp, ReportId, DeviceId, DeviceName, InitiatingProcessFileName, RemoteIP, LocalPort, LocalIP
| sort by Timestamp desc
| take 200Looks for: Survives IP rotation if the operator keeps the same port plan: 1002 (HTTPS beacon), 8033 (stager delivery), 8044 (HTTP staging) and 9995 (team server) to a non-private address. Grouped per host, process and destination so one beacon is one row. FP: Ports 8044 and 9995 are used by legitimate products. Exclude known vendor destinations and review by process name: a browser is noise, powershell, rundll32 or an unknown binary is not.
Known limitations and deployment notes
- PowerQuery: The link-local and carrier-grade NAT ranges are treated as external here, as they are in the CQL.
- PowerQuery assumes: dst.port.number is numeric and holds the remote port of an outbound IP Connect event.
- KQL – Defender XDR: RemoteIPType Public excludes link-local and carrier-grade NAT addresses, which the CQL treats as external.
- KQL – Defender XDR assumes: RemoteIPType is Public for routable addresses and is populated on the tenant.
- KQL – Defender XDR assumes: ConnectionSuccess, ConnectionFailed and ConnectionRequest are the outbound action types recorded on the tenant.
// HUNT: External connection on the team server port set (CyberXero) // MITRE: T1071.001, T1571 // CONF: medium FP: medium COST: medium // REQUIRES: Outbound network connection with process (NetworkConnectIP4) // FALSE POSITIVES: Legitimate software on 8044 or 9995. // TUNING: exclude vendor destination IPs after your first run, and rank rows whose ContextBaseFileName is a scripting host or an unsigned binary first // LOOKBACK: 7d #event_simpleName=NetworkConnectIP4 | in(field=RemotePort, values=["1002","8033","8044","9995"]) | !cidr(RemoteAddressIP4, subnet="10.0.0.0/8") | !cidr(RemoteAddressIP4, subnet="172.16.0.0/12") | !cidr(RemoteAddressIP4, subnet="192.168.0.0/16") | !cidr(RemoteAddressIP4, subnet="127.0.0.0/8") | groupBy([aid, ComputerName, ContextBaseFileName, RemoteAddressIP4, RemotePort], function=[count(as=conns), min(@timestamp, as=first_seen), max(@timestamp, as=last_seen)]) | sort(conns, order=desc)
3 required fields · View requirements
Required telemetry
- IP Connect events
Required fields
event.type: Event typedst.port.number: Destination portdst.ip.address: Destination address
Recommended fields
src.process.name: Owning process name
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'IP Connect' dst.port.number = * dst.ip.address = * | limit 5 | columns event.type, dst.port.number, dst.ip.address
// HUNT: External connection on the team server port set (CyberXero) // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1071.001, T1571 // CONF: medium | FP: medium // FALSE POSITIVES: Legitimate software on 8044 or 9995. // EQUIVALENCE: equivalent-with-schema-assumptions - Same network predicate: connections to destination ports 1002, 8033, 8044 or 9995 where the destination is not RFC 1918 or loopback, counted per host, process, destination and port with first and last seen. // REQUIRES: SentinelOne network telemetry (IP Connect) with the owning process // TUNING: Exclude vendor destination addresses after the first run, and rank rows whose process is a script host or an unsigned binary first. // LOOKBACK: 7d // CONFIGURATION: No lookup objects required. // KNOWN GAPS: The link-local and carrier-grade NAT ranges are treated as external here, as they are in the CQL. // VALIDATION LEVEL: static-reviewed event.type = 'IP Connect' dst.port.number in (1002, 8033, 8044, 9995) !(net_rfc1918(dst.ip.address)) !(net_ipsubnet(dst.ip.address, '127.0.0.0/8')) | group connections = count(), first_seen = min(event.time), last_seen = max(event.time) by endpoint.name, src.process.name, dst.ip.address, dst.port.number | sort -connections | limit 200
Automated validation: static-passed
4 required fields · View requirements
Required telemetry
- DeviceNetworkEvents
Required fields
Timestamp: Event timeActionType: Action typeRemotePort: Remote portRemoteIPType: Remote address class
Recommended fields
InitiatingProcessFileName: Owning processRemoteIP: Remote address
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceNetworkEvents | where Timestamp > ago(1d) | project Timestamp, ActionType, RemotePort, RemoteIPType | take 5
// HUNT: External connection on the team server port set (CyberXero)
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1071.001, T1571
// CONF: medium | FP: medium
// FALSE POSITIVES: Legitimate software on 8044 or 9995.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same network predicate: outbound connections to remote ports 1002, 8033, 8044 or 9995 where the remote address is public, counted per host, process, address and port. RemoteIPType replaces the CQL subnet exclusions.
// REQUIRES: Defender for Endpoint network telemetry (DeviceNetworkEvents)
// TUNING: Exclude vendor destination addresses after the first run, and rank rows whose process is a script host or an unsigned binary first.
// LOOKBACK: 7d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: RemoteIPType Public excludes link-local and carrier-grade NAT addresses, which the CQL treats as external.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed-with-warnings; fixtures=0/0
DeviceNetworkEvents
| where Timestamp >= ago(7d)
| where ActionType in ("ConnectionSuccess", "ConnectionFailed", "ConnectionRequest")
| where RemotePort in (1002, 8033, 8044, 9995)
| where RemoteIPType == "Public"
| summarize connections = count(), first_seen = min(Timestamp), last_seen = max(Timestamp) by DeviceId, DeviceName, InitiatingProcessFileName, RemoteIP, RemotePort
| sort by connections desc
| take 200Looks for: Remote WMI execution lands as a child of WmiPrvSE.exe on the target. SOCRadar documents WMI remote execution against hosts in the Chinese Redis cluster using a blank-password account. FP: Endpoint management, inventory and monitoring agents execute through WMI. Exclude the service accounts and command lines of those tools.
Known limitations and deployment notes
- PowerQuery: A payload that runs inside the WMI provider host without creating a child process is not seen.
- PowerQuery assumes: endpoint.os carries the value windows for Windows agents.
- PowerQuery assumes: Windows agents report the image name with the .exe suffix.
- KQL – Defender XDR: A payload that runs inside the WMI provider host without creating a child process is not seen.
- KQL – Defender XDR assumes: Windows sensors report the image name with the .exe suffix, so no separate platform predicate is needed.
// HUNT: Command shell or script host spawned by WmiPrvSE.exe (CyberXero) // MITRE: T1047 // CONF: medium FP: medium COST: low // REQUIRES: Process creation with parent (ProcessRollup2) // FALSE POSITIVES: Management and monitoring agents that run through WMI. // TUNING: exclude your management-tool UserName values and exact CommandLine strings; treat any hit with an IEX, download or encoded token as high priority // LOOKBACK: 14d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | event_platform=Win | ParentBaseFileName=/^wmiprvse\.exe$/i | FileName=/^(cmd|powershell|pwsh|rundll32|mshta|regsvr32|wscript|cscript|certutil|bitsadmin)(\.exe)?$/i | table([@timestamp, aid, ComputerName, UserName, FileName, CommandLine, ParentBaseFileName])
4 required fields · View requirements
Required telemetry
- Process Creation events
Required fields
event.type: Event typeendpoint.os: Operating systemsrc.process.name: Creator process nametgt.process.name: Created process name
Recommended fields
tgt.process.cmdline: Created command line
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'Process Creation' endpoint.os = * src.process.name = * tgt.process.name = * | limit 5 | columns event.type, endpoint.os, src.process.name, tgt.process.name
// HUNT: Command shell or script host spawned by WmiPrvSE.exe (CyberXero)
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1047
// CONF: medium | FP: medium
// FALSE POSITIVES: Management and monitoring agents that run through WMI.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate on Windows: a command shell, script host or LOLBin created by WmiPrvSE.exe. On a Process Creation event the created process is tgt.process.* and its creator, WmiPrvSE.exe, is src.process.*.
// REQUIRES: SentinelOne process-creation telemetry with the creator process
// TUNING: Exclude your management-tool accounts and exact command lines. Treat any hit with an IEX, download or encoded token as high priority.
// LOOKBACK: 14d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A payload that runs inside the WMI provider host without creating a child process is not seen.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation'
endpoint.os in:anycase ('windows')
src.process.name in:anycase ('wmiprvse.exe')
tgt.process.name in:anycase ('cmd.exe', 'powershell.exe', 'pwsh.exe', 'rundll32.exe', 'mshta.exe', 'regsvr32.exe', 'wscript.exe', 'cscript.exe', 'certutil.exe', 'bitsadmin.exe')
| columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdline
| sort -event.time
| limit 200Automated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeInitiatingProcessFileName: Creator process nameFileName: Created process name
Recommended fields
ProcessCommandLine: 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: Command shell or script host spawned by WmiPrvSE.exe (CyberXero)
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1047
// CONF: medium | FP: medium
// FALSE POSITIVES: Management and monitoring agents that run through WMI.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: a command shell, script host or LOLBin created by WmiPrvSE.exe. The creator is InitiatingProcessFileName.
// REQUIRES: Defender for Endpoint process-creation telemetry (DeviceProcessEvents)
// TUNING: Exclude your management-tool accounts and exact command lines. Treat any hit with an IEX, download or encoded token as high priority.
// LOOKBACK: 14d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A payload that runs inside the WMI provider host without creating a child process is not seen.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceProcessEvents
| where Timestamp >= ago(14d)
| where InitiatingProcessFileName =~ "wmiprvse.exe"
| where FileName in~ ("cmd.exe", "powershell.exe", "pwsh.exe", "rundll32.exe", "mshta.exe", "regsvr32.exe", "wscript.exe", "cscript.exe", "certutil.exe", "bitsadmin.exe")
| project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine
| sort by Timestamp desc
| take 200Looks for: Source side of the same activity: wmic with a node argument or process call create, and PowerShell WMI or CIM method calls with a remote computer name. FP: Administrators and inventory scripts use these. Exclude admin jump hosts and the service accounts that run scheduled inventory.
Known limitations and deployment notes
- PowerQuery: Remote WMI started from a tool other than wmic or PowerShell is not matched.
- PowerQuery assumes: endpoint.os carries the value windows for Windows agents.
- KQL – Defender XDR: Remote WMI started from a tool other than wmic or PowerShell is not matched.
- KQL – Defender XDR assumes: Windows sensors report the image name with the .exe suffix, so no separate platform predicate is needed.
// HUNT: WMI remote-execution initiators on the source host (CyberXero) // MITRE: T1047 // CONF: medium FP: medium COST: medium // REQUIRES: Process creation with command line (ProcessRollup2) // FALSE POSITIVES: Admin and inventory scripts. // TUNING: exclude the jump hosts and service accounts in your estate that legitimately run remote WMI; keep wmic process call create unexcluded // LOOKBACK: 14d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | event_platform=Win | FileName=/^(wmic|powershell|pwsh)(\.exe)?$/i | CommandLine=/(\s.node:|process\s+call\s+create|invoke-wmimethod|invoke-cimmethod|win32_process.*(computername|cimsession))/i | table([@timestamp, aid, ComputerName, UserName, FileName, CommandLine, ParentBaseFileName])
4 required fields · View requirements
Required telemetry
- Process Creation events
Required fields
event.type: Event typeendpoint.os: Operating systemtgt.process.name: Created process nametgt.process.cmdline: Created command line
Recommended fields
src.process.name: Creator process name
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'Process Creation' endpoint.os = * tgt.process.name = * tgt.process.cmdline = * | limit 5 | columns event.type, endpoint.os, tgt.process.name, tgt.process.cmdline
// HUNT: WMI remote-execution initiators on the source host (CyberXero)
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1047
// CONF: medium | FP: medium
// FALSE POSITIVES: Admin and inventory scripts.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate on Windows: wmic or PowerShell with a remote-node switch, a process call create, or a WMI or CIM method call. matches is case-insensitive, which reproduces the CQL /i intent.
// REQUIRES: SentinelOne process-creation telemetry with the command line
// TUNING: Exclude the jump hosts and service accounts that legitimately run remote WMI. Keep wmic process call create unexcluded.
// LOOKBACK: 14d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: Remote WMI started from a tool other than wmic or PowerShell is not matched.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation'
endpoint.os in:anycase ('windows')
tgt.process.name in:anycase ('wmic.exe', 'powershell.exe', 'pwsh.exe', 'wmic', 'powershell', 'pwsh')
tgt.process.cmdline matches '(\\s.node:|process\\s+call\\s+create|invoke-wmimethod|invoke-cimmethod|win32_process.*(computername|cimsession))'
| columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdline
| sort -event.time
| limit 200Automated 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: WMI remote-execution initiators on the source host (CyberXero)
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1047
// CONF: medium | FP: medium
// FALSE POSITIVES: Admin and inventory scripts.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: wmic or PowerShell with a remote-node switch, a process call create, or a WMI or CIM method call. The (?i) prefix reproduces the CQL /i intent.
// REQUIRES: Defender for Endpoint process-creation telemetry (DeviceProcessEvents)
// TUNING: Exclude the jump hosts and service accounts that legitimately run remote WMI. Keep wmic process call create unexcluded.
// LOOKBACK: 14d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: Remote WMI started from a tool other than wmic or PowerShell is not matched.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceProcessEvents
| where Timestamp >= ago(14d)
| where FileName in~ ("wmic.exe", "powershell.exe", "pwsh.exe")
| where ProcessCommandLine matches regex @"(?i)(\s.node:|process\s+call\s+create|invoke-wmimethod|invoke-cimmethod|win32_process.*(computername|cimsession))"
| project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine
| sort by Timestamp desc
| take 200Looks for: Local redis-cli use that matches the rogue-replication family: SLAVEOF or REPLICAOF toward another node, CONFIG SET dir or dbfilename (the lever that points a Redis save at an SSH directory), and MODULE LOAD. Honest limit: the attacker's replication handshake arrives over the network and is not a process on the victim, so this sees only the local shell side. FP: Redis administrators legitimately configure replication. Exclude replica build jobs and named admin accounts.
Known limitations and deployment notes
- PowerQuery: Commands piped to redis-cli on standard input, or sent by a client other than redis-cli, are not matched.
- PowerQuery assumes: endpoint.os carries the value linux for Linux agents.
- PowerQuery assumes: A command passed to redis-cli over standard input rather than the command line is not visible.
- KQL – Defender XDR: Commands piped to redis-cli on standard input, or sent by a client other than redis-cli, are not matched.
- KQL – Defender XDR assumes: The Linux sensor reports the image name without a suffix and fills ProcessCommandLine.
// HUNT: redis-cli replication or config abuse on a Linux host (CyberXero) // MITRE: T1190, T1098.004, T1059.004 // CONF: medium FP: medium COST: low // REQUIRES: Linux process creation with command line (ProcessRollup2) // FALSE POSITIVES: Redis administrators building replicas. // TUNING: exclude the admin UserName and the replication targets that are your own replicas; CONFIG SET dir pointing at a .ssh path is never legitimate // LOOKBACK: 30d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | event_platform=Lin | FileName=/^redis-cli$/ | CommandLine=/(slaveof|replicaof|config\s+set\s+(dir|dbfilename)|module\s+load)/i | table([@timestamp, aid, ComputerName, UserName, FileName, CommandLine, ParentBaseFileName])
4 required fields · View requirements
Required telemetry
- Process Creation events
Required fields
event.type: Event typeendpoint.os: Operating systemtgt.process.name: Created process nametgt.process.cmdline: Created command line
Recommended fields
src.process.name: Creator process name
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'Process Creation' endpoint.os = * tgt.process.name = * tgt.process.cmdline = * | limit 5 | columns event.type, endpoint.os, tgt.process.name, tgt.process.cmdline
// HUNT: redis-cli replication or config abuse on a Linux host (CyberXero)
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1190, T1098.004, T1059.004
// CONF: medium | FP: medium
// FALSE POSITIVES: Redis administrators building replicas.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate on Linux: redis-cli started with a replication, configuration-write or module-load command. The name match is case-sensitive as in the CQL, and the command match is case-insensitive.
// REQUIRES: SentinelOne Linux process-creation telemetry with the command line
// TUNING: Exclude the administrator account and the replication targets that are your own replicas. CONFIG SET dir pointing at a .ssh path is never legitimate.
// LOOKBACK: 30d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: Commands piped to redis-cli on standard input, or sent by a client other than redis-cli, are not matched.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation'
endpoint.os in:anycase ('linux')
tgt.process.name = 'redis-cli'
tgt.process.cmdline matches '(slaveof|replicaof|config\\s+set\\s+(dir|dbfilename)|module\\s+load)'
| columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdline
| sort -event.time
| limit 200Automated 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: redis-cli replication or config abuse on a Linux host (CyberXero) // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1190, T1098.004, T1059.004 // CONF: medium | FP: medium // FALSE POSITIVES: Redis administrators building replicas. // EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: redis-cli started with a replication, configuration-write or module-load command. The name match is case-sensitive as in the CQL, and the (?i) prefix keeps the command match case-insensitive. // REQUIRES: Defender for Endpoint for Linux process-creation telemetry (DeviceProcessEvents) // TUNING: Exclude the administrator account and the replication targets that are your own replicas. CONFIG SET dir pointing at a .ssh path is never legitimate. // LOOKBACK: 30d // CONFIGURATION: No lookup objects required. // KNOWN GAPS: Commands piped to redis-cli on standard input, or sent by a client other than redis-cli, are not matched. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceProcessEvents | where Timestamp >= ago(30d) | where FileName == "redis-cli" | where ProcessCommandLine matches regex @"(?i)(slaveof|replicaof|config\s+set\s+(dir|dbfilename)|module\s+load)" | project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine | sort by Timestamp desc | take 200
Looks for: A Redis server process should never start a shell, downloader or interpreter. Hits indicate module-load or similar code execution in the Redis process. Redis's own persistence children are not in the filename list. FP: Low. Custom Redis scripts that shell out are rare and should be known to the owning team.
Known limitations and deployment notes
- PowerQuery: A child started through a double fork, so that redis-server is no longer its creator, is not matched.
- PowerQuery assumes: endpoint.os carries the value linux for Linux agents.
- KQL – Defender XDR: A child started through a double fork, so that redis-server is no longer its creator, is not matched.
- KQL – Defender XDR assumes: The Linux sensor reports image names without a suffix.
// HUNT: redis-server spawning a shell or downloader (CyberXero) // MITRE: T1190, T1059.004, T1105 // CONF: high FP: low COST: low // REQUIRES: Linux process creation with parent (ProcessRollup2) // FALSE POSITIVES: Rare custom Redis integrations. // LOOKBACK: 30d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | event_platform=Lin | ParentBaseFileName=/^redis-server$/ | FileName=/^(sh|bash|dash|zsh|curl|wget|nc|ncat|python3?|perl|busybox|chmod|crontab)$/ | table([@timestamp, aid, ComputerName, UserName, FileName, CommandLine, ParentBaseFileName])
4 required fields · View requirements
Required telemetry
- Process Creation events
Required fields
event.type: Event typeendpoint.os: Operating systemsrc.process.name: Creator process nametgt.process.name: Created process name
Recommended fields
tgt.process.cmdline: Created command line
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'Process Creation' endpoint.os = * src.process.name = * tgt.process.name = * | limit 5 | columns event.type, endpoint.os, src.process.name, tgt.process.name
// HUNT: redis-server spawning a shell or downloader (CyberXero)
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1190, T1059.004, T1105
// CONF: high | FP: low
// FALSE POSITIVES: Rare custom Redis integrations.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate on Linux: a shell, downloader or interpreter created by redis-server. On a Process Creation event the created process is tgt.process.* and its creator, redis-server, is src.process.*. Both name matches are case-sensitive as in the CQL.
// REQUIRES: SentinelOne Linux process-creation telemetry with the creator process
// TUNING: None expected beyond rare custom Redis integrations. Review the command line of any hit.
// LOOKBACK: 30d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A child started through a double fork, so that redis-server is no longer its creator, is not matched.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation'
endpoint.os in:anycase ('linux')
src.process.name = 'redis-server'
tgt.process.name in ('sh', 'bash', 'dash', 'zsh', 'curl', 'wget', 'nc', 'ncat', 'python', 'python3', 'perl', 'busybox', 'chmod', 'crontab')
| columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdline
| sort -event.time
| limit 200Automated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeInitiatingProcessFileName: Creator process nameFileName: Created process name
Recommended fields
ProcessCommandLine: 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: redis-server spawning a shell or downloader (CyberXero)
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1190, T1059.004, T1105
// CONF: high | FP: low
// FALSE POSITIVES: Rare custom Redis integrations.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: a shell, downloader or interpreter created by redis-server. The creator is InitiatingProcessFileName. Both name matches are case-sensitive as in the CQL.
// REQUIRES: Defender for Endpoint for Linux process-creation telemetry (DeviceProcessEvents)
// TUNING: None expected beyond rare custom Redis integrations. Review the command line of any hit.
// LOOKBACK: 30d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A child started through a double fork, so that redis-server is no longer its creator, is not matched.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceProcessEvents
| where Timestamp >= ago(30d)
| where InitiatingProcessFileName == "redis-server"
| where FileName in ("sh", "bash", "dash", "zsh", "curl", "wget", "nc", "ncat", "python", "python3", "perl", "busybox", "chmod", "crontab")
| project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine
| sort by Timestamp desc
| take 200Looks for: Shell and file-tool commands that touch authorized_keys: echo or cat redirection, tee, cp, mv, sed, chattr and downloaders. Honest limit: when the write is done by redis-server itself through a Redis save, no process is created, so this query cannot see that path. Use the section 7 file sweep for it. FP: Configuration management, cloud-init and administrators add keys through these tools. Exclude by parent process and by the accounts that manage access.
Known limitations and deployment notes
- PowerQuery: An editor such as vi or nano that writes the file is not in the tool list, as in the CQL, and a write by a process that does not name the file on its command line is not seen.
- PowerQuery assumes: endpoint.os carries the value linux for Linux agents.
- KQL – Defender XDR: An editor such as vi or nano that writes the file is not in the tool list, as in the CQL, and a write by a process that does not name the file on its command line is not seen.
- KQL – Defender XDR assumes: The Linux sensor reports image names without a suffix and fills ProcessCommandLine.
// HUNT: authorized_keys written or edited by a shell or file tool (CyberXero) // MITRE: T1098.004 // CONF: medium FP: medium COST: low // REQUIRES: Linux process creation with command line (ProcessRollup2) // FALSE POSITIVES: Configuration management and cloud-init. // TUNING: exclude your configuration-management parents with the commented line; escalate when the writer's parent is a web server, redis-server or an interactive shell on a server that has no admin logon // LOOKBACK: 14d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | event_platform=Lin | CommandLine=/authorized_keys/ | FileName=/^(sh|bash|dash|zsh|tee|cp|mv|cat|echo|sed|printf|chattr|chmod|curl|wget|python3?|perl)$/ // | ParentBaseFileName!=/^(ansible.*|puppet|chef-client|salt-minion|cloud-init.*)$/i | table([@timestamp, aid, ComputerName, UserName, FileName, CommandLine, ParentBaseFileName])
4 required fields · View requirements
Required telemetry
- Process Creation events
Required fields
event.type: Event typeendpoint.os: Operating systemtgt.process.name: Created process nametgt.process.cmdline: Created command line
Recommended fields
src.process.name: Creator process name
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'Process Creation' endpoint.os = * tgt.process.name = * tgt.process.cmdline = * | limit 5 | columns event.type, endpoint.os, tgt.process.name, tgt.process.cmdline
// HUNT: authorized_keys written or edited by a shell or file tool (CyberXero)
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1098.004
// CONF: medium | FP: medium
// FALSE POSITIVES: Configuration management and cloud-init.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate on Linux: a shell or file tool whose command line names authorized_keys. Both the command-line match and the name match are case-sensitive as in the CQL.
// REQUIRES: SentinelOne Linux process-creation telemetry with the command line
// TUNING: Exclude your configuration-management parents by src.process.name. Escalate when the writer's creator is a web server, redis-server or an interactive shell on a server with no administrator logon.
// LOOKBACK: 14d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: An editor such as vi or nano that writes the file is not in the tool list, as in the CQL, and a write by a process that does not name the file on its command line is not seen.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation'
endpoint.os in:anycase ('linux')
tgt.process.name in ('sh', 'bash', 'dash', 'zsh', 'tee', 'cp', 'mv', 'cat', 'echo', 'sed', 'printf', 'chattr', 'chmod', 'curl', 'wget', 'python', 'python3', 'perl')
tgt.process.cmdline matches:matchcase 'authorized_keys'
| columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdline
| sort -event.time
| limit 200Automated 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: authorized_keys written or edited by a shell or file tool (CyberXero)
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1098.004
// CONF: medium | FP: medium
// FALSE POSITIVES: Configuration management and cloud-init.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: a shell or file tool whose command line names authorized_keys. matches regex without the (?i) prefix is case-sensitive, as is the CQL, and in is case-sensitive for the tool names.
// REQUIRES: Defender for Endpoint for Linux process-creation telemetry (DeviceProcessEvents)
// TUNING: Exclude your configuration-management parents by InitiatingProcessFileName. Escalate when the writer's creator is a web server, redis-server or an interactive shell on a server with no administrator logon.
// LOOKBACK: 14d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: An editor such as vi or nano that writes the file is not in the tool list, as in the CQL, and a write by a process that does not name the file on its command line is not seen.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceProcessEvents
| where Timestamp >= ago(14d)
| where FileName in ("sh", "bash", "dash", "zsh", "tee", "cp", "mv", "cat", "echo", "sed", "printf", "chattr", "chmod", "curl", "wget", "python", "python3", "perl")
| where ProcessCommandLine matches regex @"authorized_keys"
| project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine
| sort by Timestamp desc
| take 200Looks for: Redis is being reached from outside private space, which is the precondition for the rogue-replication path. Grouped per host and source so exposure is visible as a short list. FP: Intentional public Redis or a managed-service peer. The right outcome is usually a firewall change, not an alert.
Known limitations and deployment notes
- PowerQuery: If the tenant does not populate the direction field, or puts the local port on the source side, the query returns nothing, which reads as a clean estate.
- PowerQuery assumes: event.network.direction is populated and holds INCOMING for accepted inbound connections.
- PowerQuery assumes: dst.port.number is the local listening port on an incoming event and src.ip.address is the remote peer.
- KQL – Defender XDR: If the tenant does not record InboundConnectionAccepted the query returns nothing, which reads as a clean estate.
- KQL – Defender XDR: RemoteIPType Public excludes link-local and carrier-grade NAT addresses, which the CQL treats as external.
- KQL – Defender XDR assumes: InboundConnectionAccepted is recorded on the tenant; it is attested in Microsoft-owned hunting repositories but not listed on the table's Learn page.
- KQL – Defender XDR assumes: RemoteIPType is Public for routable addresses and is populated on the tenant.
// HUNT: Inbound connection to Redis port 6379 from a public address (CyberXero) // MITRE: T1190, T1595.002 // CONF: medium FP: medium COST: medium // REQUIRES: Inbound accepted connection (NetworkReceiveAcceptIP4) // FALSE POSITIVES: Intentionally exposed Redis and known peers. // TUNING: exclude the public peer addresses you expect and treat every remaining source as an exposure finding // LOOKBACK: 7d #event_simpleName=NetworkReceiveAcceptIP4 | LocalPort=6379 | !cidr(RemoteAddressIP4, subnet="10.0.0.0/8") | !cidr(RemoteAddressIP4, subnet="172.16.0.0/12") | !cidr(RemoteAddressIP4, subnet="192.168.0.0/16") | !cidr(RemoteAddressIP4, subnet="127.0.0.0/8") | groupBy([aid, ComputerName, RemoteAddressIP4], function=[count(as=accepts), min(@timestamp, as=first_seen), max(@timestamp, as=last_seen)]) | sort(accepts, order=desc)
4 required fields · View requirements
Required telemetry
- IP Connect events
Required fields
event.type: Event typeevent.network.direction: Connection directiondst.port.number: Local portsrc.ip.address: Remote peer address
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'IP Connect' event.network.direction = * dst.port.number = * src.ip.address = * | limit 5 | columns event.type, event.network.direction, dst.port.number, src.ip.address
// HUNT: Inbound connection to Redis port 6379 from a public address (CyberXero)
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1190, T1595.002
// CONF: medium | FP: medium
// FALSE POSITIVES: Intentionally exposed Redis and known peers.
// EQUIVALENCE: approximate-analytic - The CQL reads an accepted-inbound-connection event on local port 6379. SentinelOne reports it as an IP Connect event whose direction is incoming, with the remote peer in the source address and the local listener in the destination. The direction field and the side of the local port are documented but not seen in shipped queries, so the match is an approximation until confirmed on a tenant.
// REQUIRES: SentinelOne network telemetry (IP Connect) with the connection direction
// TUNING: Exclude the public peer addresses you expect, and treat every remaining source as an exposure finding.
// LOOKBACK: 7d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: If the tenant does not populate the direction field, or puts the local port on the source side, the query returns nothing, which reads as a clean estate.
// VALIDATION LEVEL: static-reviewed
event.type = 'IP Connect'
event.network.direction in:anycase ('incoming')
dst.port.number = 6379
!(net_rfc1918(src.ip.address))
!(net_ipsubnet(src.ip.address, '127.0.0.0/8'))
| group accepts = count(), first_seen = min(event.time), last_seen = max(event.time) by endpoint.name, src.ip.address
| sort -accepts
| limit 200Automated validation: static-passed
4 required fields · View requirements
Required telemetry
- DeviceNetworkEvents
Required fields
Timestamp: Event timeActionType: Action typeLocalPort: Local portRemoteIPType: Remote address class
Recommended fields
RemoteIP: Remote address
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceNetworkEvents | where Timestamp > ago(1d) | where ActionType == "InboundConnectionAccepted" | project Timestamp, ActionType, LocalPort, RemoteIPType | take 5
// HUNT: Inbound connection to Redis port 6379 from a public address (CyberXero) // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1190, T1595.002 // CONF: medium | FP: medium // FALSE POSITIVES: Intentionally exposed Redis and known peers. // EQUIVALENCE: equivalent-with-schema-assumptions - Same network predicate: accepted inbound connections to local port 6379 from a public remote address, counted per host and source. RemoteIPType replaces the CQL subnet exclusions. // REQUIRES: Defender for Endpoint network telemetry (DeviceNetworkEvents) // TUNING: Exclude the public peer addresses you expect, and treat every remaining source as an exposure finding. // LOOKBACK: 7d // CONFIGURATION: No lookup objects required. // KNOWN GAPS: If the tenant does not record InboundConnectionAccepted the query returns nothing, which reads as a clean estate. RemoteIPType Public excludes link-local and carrier-grade NAT addresses, which the CQL treats as external. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed-with-warnings; fixtures=0/0 DeviceNetworkEvents | where Timestamp >= ago(7d) | where ActionType == "InboundConnectionAccepted" | where LocalPort == 6379 | where RemoteIPType == "Public" | summarize accepts = count(), first_seen = min(Timestamp), last_seen = max(Timestamp) by DeviceId, DeviceName, RemoteIP | sort by accepts desc | take 200
Looks for: Webshell execution as seen from the host: Apache, nginx, PHP-FPM, PHP-CGI, LiteSpeed PHP or IIS w3wp starting a shell or a recon tool. WSO-family shells run operator commands through PHP, so the parent is the PHP or web worker. This is the strongest endpoint signal for the webshell stage on a sensored web server. FP: Some PHP applications shell out to utilities and some IIS apps call cmd. Exclude the exact application command lines you know.
Known limitations and deployment notes
- PowerQuery: A worker with a name outside the list, such as a Tomcat or Node.js server, is not covered, as in the CQL.
- PowerQuery assumes: The creator name is reported as the bare image name, for example php-fpm8.2 or w3wp.exe.
- KQL – Defender XDR: A worker with a name outside the list, such as a Tomcat or Node.js server, is not covered, as in the CQL.
- KQL – Defender XDR assumes: The creator name is reported as the bare image name, for example php-fpm8.2 or w3wp.exe.
// HUNT: Web server worker spawning a shell or recon utility (CyberXero) // MITRE: T1505.003, T1059.004, T1059.003 // CONF: medium FP: medium COST: low // REQUIRES: Process creation with parent (ProcessRollup2) // FALSE POSITIVES: PHP or IIS applications that legitimately shell out. // TUNING: allowlist the exact CommandLine of known application helpers; keep whoami, id, uname, hostname and net/nltest recon unexcluded // LOOKBACK: 14d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | ParentBaseFileName=/^(apache2|httpd|nginx|php-fpm[0-9.]*|php-cgi|lsphp[0-9]*|w3wp)(\.exe)?$/i | FileName=/^(sh|bash|dash|zsh|cmd|powershell|pwsh|whoami|id|uname|hostname|curl|wget|nc|ncat|certutil|net|net1|nltest)(\.exe)?$/i | table([@timestamp, aid, ComputerName, event_platform, UserName, ParentBaseFileName, FileName, CommandLine]) | sort(@timestamp, order=desc)
3 required fields · View requirements
Required telemetry
- Process Creation events
Required fields
event.type: Event typesrc.process.name: Creator process nametgt.process.name: Created process name
Recommended fields
tgt.process.cmdline: Created command lineendpoint.os: Operating system
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'Process Creation' src.process.name = * tgt.process.name = * | limit 5 | columns event.type, src.process.name, tgt.process.name
// HUNT: Web server worker spawning a shell or recon utility (CyberXero) // SCHEMA PROFILE: sentinelone-endpoint-ocsf // MITRE: T1505.003, T1059.004, T1059.003 // CONF: medium | FP: medium // FALSE POSITIVES: PHP or IIS applications that legitimately shell out. // EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate on Windows and Linux: a shell, downloader or recon utility created by a web server worker. On a Process Creation event the created process is tgt.process.* and its creator, the worker, is src.process.*. matches is case-insensitive, which reproduces the CQL /i intent. // REQUIRES: SentinelOne process-creation telemetry with the creator process // TUNING: Allowlist the exact command line of known application helpers. Keep whoami, id, uname, hostname and net or nltest recon unexcluded. // LOOKBACK: 14d // CONFIGURATION: No lookup objects required. // KNOWN GAPS: A worker with a name outside the list, such as a Tomcat or Node.js server, is not covered, as in the CQL. // VALIDATION LEVEL: static-reviewed event.type = 'Process Creation' src.process.name matches '^(apache2|httpd|nginx|php-fpm[0-9.]*|php-cgi|lsphp[0-9]*|w3wp)(\\.exe)?$' tgt.process.name matches '^(sh|bash|dash|zsh|cmd|powershell|pwsh|whoami|id|uname|hostname|curl|wget|nc|ncat|certutil|net|net1|nltest)(\\.exe)?$' | columns event.time, endpoint.name, endpoint.os, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdline | sort -event.time | limit 200
Automated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeInitiatingProcessFileName: Creator process nameFileName: Created process name
Recommended fields
ProcessCommandLine: 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: Web server worker spawning a shell or recon utility (CyberXero) // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1505.003, T1059.004, T1059.003 // CONF: medium | FP: medium // FALSE POSITIVES: PHP or IIS applications that legitimately shell out. // EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: a shell, downloader or recon utility created by a web server worker. The creator is InitiatingProcessFileName. The (?i) prefix reproduces the CQL /i intent. // REQUIRES: Defender for Endpoint process-creation telemetry (DeviceProcessEvents) // TUNING: Allowlist the exact command line of known application helpers. Keep whoami, id, uname, hostname and net or nltest recon unexcluded. // LOOKBACK: 14d // CONFIGURATION: No lookup objects required. // KNOWN GAPS: A worker with a name outside the list, such as a Tomcat or Node.js server, is not covered, as in the CQL. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0 DeviceProcessEvents | where Timestamp >= ago(14d) | where InitiatingProcessFileName matches regex @"(?i)^(apache2|httpd|nginx|php-fpm[0-9.]*|php-cgi|lsphp[0-9]*|w3wp)(\.exe)?$" | where FileName matches regex @"(?i)^(sh|bash|dash|zsh|cmd|powershell|pwsh|whoami|id|uname|hostname|curl|wget|nc|ncat|certutil|net|net1|nltest)(\.exe)?$" | project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine | sort by Timestamp desc | take 200
Looks for: Tempo detector for the AI-orchestrated pipeline: four or more distinct tools launched by web workers on one host inside a two-minute bucket. The reported run deployed 32 shells in 61 seconds, so human-paced shell use and agent-paced use differ sharply. Threshold is a starting point. FP: Deployment hooks and PHP applications that run several helper tools at once. Raise the threshold or exclude the deploy window.
Known limitations and deployment notes
- PowerQuery: A burst split across two windows can fall under the threshold in both.
- PowerQuery assumes: estimate_distinct is exact at the small counts this threshold uses.
- PowerQuery assumes: timebucket windows are aligned to the platform clock rather than to the first event, so a burst that straddles an edge can split into two windows.
- KQL – Defender XDR: A burst split across two windows can fall under the threshold in both.
- KQL – Defender XDR assumes: bin windows are aligned to the clock, so a burst that straddles an edge can split into two windows.
// HUNT: Web worker child-process burst (machine-speed tempo) (CyberXero) // MITRE: T1505.003, T1059 // CONF: medium FP: medium COST: medium // REQUIRES: Process creation with parent (ProcessRollup2) // FALSE POSITIVES: Deployment hooks and chatty PHP applications. // TUNING: raise the distinct_tools threshold on busy application hosts or exclude the nightly deploy window; investigate any host that also fired Q15 // LOOKBACK: 7d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | ParentBaseFileName=/^(apache2|httpd|nginx|php-fpm[0-9.]*|php-cgi|lsphp[0-9]*|w3wp)(\.exe)?$/i | FileName=/^(sh|bash|dash|zsh|cmd|powershell|pwsh|whoami|id|uname|hostname|curl|wget|nc|ncat|certutil|net|net1|nltest|ls|cat|find|ps|ifconfig|ip)(\.exe)?$/i | bucket(span=2m, field=[aid, ComputerName], function=[count(FileName, distinct=true, as=distinct_tools), count(as=children)]) | test(distinct_tools >= 4) | sort(distinct_tools, order=desc)
3 required fields · View requirements
Required telemetry
- Process Creation events
Required fields
event.type: Event typesrc.process.name: Creator process nametgt.process.name: Created process name
Recommended fields
endpoint.name: Host name
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'Process Creation' src.process.name = * tgt.process.name = * | limit 5 | columns event.type, src.process.name, tgt.process.name
// HUNT: Web worker child-process burst (machine-speed tempo) (CyberXero)
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1505.003, T1059
// CONF: medium | FP: medium
// FALSE POSITIVES: Deployment hooks and chatty PHP applications.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same behaviour: children of a web server worker in the shell and recon list, bucketed into two-minute windows per host, kept when four or more distinct tools appear. timebucket gives fixed windows as the CQL bucket does, but the window edges are chosen by the platform and may differ from the CQL's. estimate_distinct stands in for the exact distinct count.
// REQUIRES: SentinelOne process-creation telemetry with the creator process
// TUNING: Raise the distinct_tools threshold on busy application hosts or exclude the nightly deploy window. Investigate any host that also fired the web-worker child-process card.
// LOOKBACK: 7d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A burst split across two windows can fall under the threshold in both.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation'
src.process.name matches '^(apache2|httpd|nginx|php-fpm[0-9.]*|php-cgi|lsphp[0-9]*|w3wp)(\\.exe)?$'
tgt.process.name matches '^(sh|bash|dash|zsh|cmd|powershell|pwsh|whoami|id|uname|hostname|curl|wget|nc|ncat|certutil|net|net1|nltest|ls|cat|find|ps|ifconfig|ip)(\\.exe)?$'
| group distinct_tools = estimate_distinct(tgt.process.name), children = count() by endpoint.name, window = timebucket('2m')
| filter distinct_tools >= 4
| sort -distinct_tools
| limit 200Automated validation: static-passed
3 required fields · View requirements
Required telemetry
- DeviceProcessEvents
Required fields
Timestamp: Event timeInitiatingProcessFileName: Creator process nameFileName: Created process name
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceProcessEvents | where Timestamp > ago(1d) | project Timestamp, InitiatingProcessFileName, FileName | take 5
// HUNT: Web worker child-process burst (machine-speed tempo) (CyberXero) // SCHEMA PROFILE: microsoft-defender-xdr // MITRE: T1505.003, T1059 // CONF: medium | FP: medium // FALSE POSITIVES: Deployment hooks and chatty PHP applications. // EQUIVALENCE: equivalent-with-schema-assumptions - Same behaviour: children of a web server worker in the shell and recon list, bucketed into two-minute windows per device, kept when four or more distinct tools appear. dcount is an estimate that is exact at these small counts. // REQUIRES: Defender for Endpoint process-creation telemetry (DeviceProcessEvents) // TUNING: Raise the distinct_tools threshold on busy application hosts or exclude the nightly deploy window. Investigate any host that also fired the web-worker child-process card. // LOOKBACK: 7d // CONFIGURATION: No lookup objects required. // KNOWN GAPS: A burst split across two windows can fall under the threshold in both. // VALIDATION LEVEL: schema-aligned // AUTOMATED VALIDATION: static-passed; static=passed-with-warnings; fixtures=0/0 DeviceProcessEvents | where Timestamp >= ago(7d) | where InitiatingProcessFileName matches regex @"(?i)^(apache2|httpd|nginx|php-fpm[0-9.]*|php-cgi|lsphp[0-9]*|w3wp)(\.exe)?$" | where FileName matches regex @"(?i)^(sh|bash|dash|zsh|cmd|powershell|pwsh|whoami|id|uname|hostname|curl|wget|nc|ncat|certutil|net|net1|nltest|ls|cat|find|ps|ifconfig|ip)(\.exe)?$" | summarize distinct_tools = dcount(FileName), children = count() by DeviceId, DeviceName, Window = bin(Timestamp, 2m) | where distinct_tools >= 4 | sort by distinct_tools desc | take 200
Looks for: Command lines naming the campaign's own artifacts: a wp2shell_ plus eight hex plugin directory, a WSO-Shell.php file, or a wp2_ plus eight hex account. Hits come from responder activity, cleanup scripts, wp-cli, mysql clients or shell access to the plugin folder. Weak as a standalone detector because creation happens through the web application, not a process. It is a cheap retrospective sweep. FP: Low. Your own incident responders will match once they start cleanup.
Known limitations and deployment notes
- PowerQuery: An artifact touched without appearing on any command line, for example by a web shell request, is not seen.
- PowerQuery assumes: tgt.process.cmdline holds the full command line of the created process.
- KQL – Defender XDR: An artifact touched without appearing on any command line, for example by a web shell request, is not seen.
- KQL – Defender XDR assumes: ProcessCommandLine holds the full command line of the created process.
// HUNT: CyberXero artifact names in a command line (CyberXero) // MITRE: T1505.003, T1136.001 // CONF: high FP: low COST: low // REQUIRES: Process creation with command line (ProcessRollup2) // FALSE POSITIVES: Responder cleanup commands. // LOOKBACK: 30d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | CommandLine=/(wp2shell_[0-9a-f]{8}|WSO-Shell\.php|\bwp2_[0-9a-f]{8}\b)/i | table([@timestamp, aid, ComputerName, UserName, FileName, CommandLine, ParentBaseFileName])
2 required fields · View requirements
Required telemetry
- Process Creation events
Required fields
event.type: Event typetgt.process.cmdline: Created command line
Recommended fields
tgt.process.name: Created process namesrc.process.name: Creator process name
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'Process Creation' tgt.process.cmdline = * | limit 5 | columns event.type, tgt.process.cmdline
// HUNT: CyberXero artifact names in a command line (CyberXero)
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1505.003, T1136.001
// CONF: high | FP: low
// FALSE POSITIVES: Responder cleanup commands.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: a command line naming one of the three artifact patterns, wp2shell_ plus eight hex digits, WSO-Shell.php, or wp2_ plus eight hex digits on word boundaries. matches is case-insensitive, which reproduces the CQL /i intent.
// REQUIRES: SentinelOne process-creation telemetry with the command line
// TUNING: Responder cleanup commands that name the artifacts are the known false positive: confirm the account and the ticket before closing.
// LOOKBACK: 30d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: An artifact touched without appearing on any command line, for example by a web shell request, is not seen.
// VALIDATION LEVEL: static-reviewed
event.type = 'Process Creation'
tgt.process.cmdline matches '(wp2shell_[0-9a-f]{8}|WSO-Shell\\.php|\\bwp2_[0-9a-f]{8}\\b)'
| columns event.time, endpoint.name, src.process.user, src.process.name, tgt.process.name, tgt.process.cmdline
| sort -event.time
| limit 200Automated 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: CyberXero artifact names in a command line (CyberXero)
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1505.003, T1136.001
// CONF: high | FP: low
// FALSE POSITIVES: Responder cleanup commands.
// EQUIVALENCE: equivalent-with-schema-assumptions - Same process-creation predicate: a command line naming one of the three artifact patterns. The (?i) prefix reproduces the CQL /i intent.
// REQUIRES: Defender for Endpoint process-creation telemetry (DeviceProcessEvents)
// TUNING: Responder cleanup commands that name the artifacts are the known false positive: confirm the account and the ticket before closing.
// LOOKBACK: 30d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: An artifact touched without appearing on any command line, for example by a web shell request, is not seen.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceProcessEvents
| where Timestamp >= ago(30d)
| where ProcessCommandLine matches regex @"(?i)(wp2shell_[0-9a-f]{8}|WSO-Shell\.php|\bwp2_[0-9a-f]{8}\b)"
| project Timestamp, ReportId, DeviceId, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine
| sort by Timestamp desc
| take 200Looks for: Retrospective hash sweep: stager32.bin, the obfuscated WSO-Shell.php, and the two Chinese-cluster staging payloads 1.bin and config.bin. Honest limit: .php and .bin files are not executables, so the sensor hashes them only if they run or are written as an executable type. Expect few or no hits even on an affected host, and treat a miss as no evidence. FP: None expected.
Known limitations and deployment notes
- PowerQuery: A file that the agent hashes with SHA-1 only, or does not hash at all, is not matched.
- PowerQuery: There is no per-format write event, so a native executable written without a create or modify event is not seen.
- PowerQuery assumes: tgt.process.image.sha256 and tgt.file.sha256 are populated for the events of interest on the tenant.
- KQL – Defender XDR: The process-start half of the CQL is not covered: SHA256 is often unpopulated on DeviceProcessEvents, so a file that was already on disk and then ran is missed.
- KQL – Defender XDR: Advanced Hunting keeps 30 days; the CQL tab covers 90 days.
- KQL – Defender XDR assumes: SHA256 is populated on DeviceFileEvents rows on the tenant.
// HUNT: Hash sweep of the four published CyberXero files (CyberXero) // MITRE: T1105, T1505.003, T1027 // CONF: medium FP: low COST: low // REQUIRES: Process, PE and ELF file telemetry with SHA-256 // FALSE POSITIVES: None expected: published attacker file hashes. // LOOKBACK: 90d #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2|PeFileWritten|NewExecutableWritten|ELFFileWritten)$/ | in(field=SHA256HashData, values=["92a789444708fa1cb4cc5a89e0aa6cc7a279b62a7b8a4d2857255a18197d0090","a5ae0aab352871bc0b038b3aa43b03eb223425628c884af7b9fc592cd34eb86c","71e21094c1ac1cf0275c91ed377965e248bca1c12711f6dd20e2682681fc1192","59c535f47ab4d35f6d9fc8b8aec4a72438ea0b89e5a4dcea74b05d2d32cfa483"]) | table([@timestamp, aid, ComputerName, event_platform, FileName, SHA256HashData])
3 required fields · View requirements
Required telemetry
- Process Creation events
- File Creation and File Modification events
Required fields
event.type: Event typetgt.process.image.sha256: Started process hashtgt.file.sha256: Written file hash
Recommended fields
tgt.file.path: Written file path
Fallbacks
endpoint.name→agent.uuid: Changes the displayed host identifier only.
Readiness test
event.type = 'File Creation' tgt.file.sha256 = * | limit 5 | columns event.type, tgt.process.image.sha256, tgt.file.sha256
// HUNT: Hash sweep of the four published CyberXero files (CyberXero)
// SCHEMA PROFILE: sentinelone-endpoint-ocsf
// MITRE: T1105, T1505.003, T1027
// CONF: medium | FP: low
// FALSE POSITIVES: None expected: published attacker file hashes.
// EQUIVALENCE: approximate-analytic - The CQL sweeps SHA-256 across process starts and PE, native executable and ELF file writes. SentinelOne has no per-format write events, so the hunt reads the hash of a started process and the hash of a created or modified file. Hash population on file events is tenant-dependent.
// REQUIRES: SentinelOne process-creation and file telemetry with SHA-256 populated
// TUNING: None expected: the hashes are published attacker file hashes. Review any hit before closing it.
// LOOKBACK: 90d
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: A file that the agent hashes with SHA-1 only, or does not hash at all, is not matched. There is no per-format write event, so a native executable written without a create or modify event is not seen.
// VALIDATION LEVEL: static-reviewed
(event.type = 'Process Creation' tgt.process.image.sha256 in:anycase ('92a789444708fa1cb4cc5a89e0aa6cc7a279b62a7b8a4d2857255a18197d0090', 'a5ae0aab352871bc0b038b3aa43b03eb223425628c884af7b9fc592cd34eb86c', '71e21094c1ac1cf0275c91ed377965e248bca1c12711f6dd20e2682681fc1192', '59c535f47ab4d35f6d9fc8b8aec4a72438ea0b89e5a4dcea74b05d2d32cfa483')) or (event.type in ('File Creation', 'File Modification') tgt.file.sha256 in:anycase ('92a789444708fa1cb4cc5a89e0aa6cc7a279b62a7b8a4d2857255a18197d0090', 'a5ae0aab352871bc0b038b3aa43b03eb223425628c884af7b9fc592cd34eb86c', '71e21094c1ac1cf0275c91ed377965e248bca1c12711f6dd20e2682681fc1192', '59c535f47ab4d35f6d9fc8b8aec4a72438ea0b89e5a4dcea74b05d2d32cfa483'))
| columns event.time, endpoint.name, event.type, src.process.name, tgt.process.name, tgt.process.image.sha256, tgt.file.path, tgt.file.sha256
| sort -event.time
| limit 200Automated validation: static-passed
2 required fields · View requirements
Required telemetry
- DeviceFileEvents
Required fields
Timestamp: Event timeSHA256: File hash
Recommended fields
FolderPath: File pathInitiatingProcessFileName: Writer process
Fallbacks
DeviceName→DeviceId: Changes the displayed host identifier only.
Readiness test
DeviceFileEvents | where Timestamp > ago(1d) | project Timestamp, FileName, SHA256 | take 5
// HUNT: Hash sweep of the four published CyberXero files (CyberXero)
// SCHEMA PROFILE: microsoft-defender-xdr
// MITRE: T1105, T1505.003, T1027
// CONF: medium | FP: low
// FALSE POSITIVES: None expected: published attacker file hashes.
// EQUIVALENCE: approximate-analytic - The CQL sweeps SHA-256 across process starts and PE, native executable and ELF file writes. Defender keeps SHA256 reliably populated on file events but not on DeviceProcessEvents, so the hunt reads file events only.
// REQUIRES: Defender for Endpoint file telemetry (DeviceFileEvents)
// TUNING: None expected: the hashes are published attacker file hashes. Review any hit before closing it.
// LOOKBACK: 30d (Advanced Hunting retention; the CQL tab covers 90d)
// CONFIGURATION: No lookup objects required.
// KNOWN GAPS: The process-start half of the CQL is not covered: SHA256 is often unpopulated on DeviceProcessEvents, so a file that was already on disk and then ran is missed. Advanced Hunting keeps 30 days; the CQL tab covers 90 days.
// VALIDATION LEVEL: schema-aligned
// AUTOMATED VALIDATION: static-passed; static=passed; fixtures=0/0
DeviceFileEvents
| where Timestamp >= ago(30d)
| where SHA256 in~ ("92a789444708fa1cb4cc5a89e0aa6cc7a279b62a7b8a4d2857255a18197d0090", "a5ae0aab352871bc0b038b3aa43b03eb223425628c884af7b9fc592cd34eb86c", "71e21094c1ac1cf0275c91ed377965e248bca1c12711f6dd20e2682681fc1192", "59c535f47ab4d35f6d9fc8b8aec4a72438ea0b89e5a4dcea74b05d2d32cfa483")
| project Timestamp, ReportId, DeviceId, DeviceName, InitiatingProcessFileName, ActionType, FileName, FolderPath, SHA256
| sort by Timestamp desc
| take 200Detection Rules by Platform
Three queries are clean enough to promote from hunt to Custom IOA. All are detect only. The pack recommends no prevention action: every indicator traces to one originating report, and the behaviours sit on stock binaries (powershell.exe, wmic.exe, redis-cli, sshd) that must never be prevented on the strength of a name.
CrowdStrike: Custom IOA
| IOA name | From | Rule type | Pattern | Exclusions | Action |
|---|---|---|---|---|---|
| CyberXero, service created as UpdSvc or with team server in image path | Promote Q3 | Service creation (Windows) | Service name ^UpdSvc$ or image path containing 42.193.227.214 | Vendor updater whose image path is a signed binary under Program Files | Detect: High |
| CyberXero, redis-server spawning a shell or downloader | Promote Q12 | Process Creation (Linux) | Parent filename ^redis-server$ and image filename ^(sh|bash|dash|zsh|curl|wget|nc|ncat|python3?|perl|busybox|chmod|crontab)$ | None expected | Detect: High |
| CyberXero, PowerShell IEX against a CyberXero address | Promote Q1 | Process Creation (Windows) | Command line containing 42.193.227.214 (any image) | None expected | Detect: High |
Pattern syntax follows the Custom IOA regular-expression fields. Confirm the exact escaping in your console, then create each rule in Monitor on a pilot policy for one business week. Not recommended as IOAs: Q2, Q4, Q5, Q8, Q9, Q10, Q13, Q14, Q15, Q16 (administrative or application noise), Q6, Q7, Q17, Q18 (indicator sweeps that belong in IOC Management and scheduled hunts).
SentinelOne: custom detection rules
| Rule | Source query | Run as | Notes |
|---|---|---|---|
| CyberXero, service created as UpdSvc or with team server in image path | Q3, PowerQuery tab | Hunt only until the gap is closed | Q3 is only an approximation here. SentinelOne has no service-creation event in the attested field model. The service exists as a value written under the Services registry key, so the hunt reads Registry Value Modified: a key named UpdSvc, a value equal to UpdSvc (display name), or a value naming 42.193.227.214 (image path). The CQL.... This pack's own text mentions a baseline or pilot; follow it as written |
| CyberXero, redis-server spawning a shell or downloader | Q12, PowerQuery tab | Scheduled custom detection rule | Bind entities so the alert names the host instead of "Unknown Device". This pack's own text mentions a baseline or pilot; follow it as written |
| CyberXero, PowerShell IEX against a CyberXero address | Q1, PowerQuery tab | Scheduled custom detection rule | Bind entities so the alert names the host instead of "Unknown Device". This pack's own text mentions a baseline or pilot; follow it as written |
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 |
|---|---|---|---|
| CyberXero, service created as UpdSvc or with team server in image path | Q3, KQL – Defender XDR tab | Hunt only until the gap is closed | Q3 is only an approximation here. ServiceInstalled is recorded only when the Audit Security System Extension policy is deployed, so the hunt reads the registry write that creates the service instead: a key named UpdSvc, a value equal to UpdSvc (display name), or a value naming 42.193.227.214 (image path).. This pack's own text mentions a baseline or pilot; follow it as written |
| CyberXero, redis-server spawning a shell or downloader | Q12, 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. This pack's own text mentions a baseline or pilot; follow it as written |
| CyberXero, PowerShell IEX against a CyberXero address | 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. This pack's own text mentions a baseline or pilot; follow it as written |
Q2, Q4, Q5, Q6, Q7, Q8, Q9, Q10, Q11, Q13, Q14, Q15, Q16, Q17 and Q18 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
Blocks tuned to this campaign. The CSV is the only block that feeds the provenance gate: all twelve rows are atomic indicators that appear in saved snapshot 01-socradar-cyberxero.txt (the five IPs also appear in snapshot 02). The wp2_ account, wp2shell_ plugin and stager path shapes are patterns, not atomic IOCs, so they live in the behavioural block.
type,value,action,severity,expiration,description,tags sha256,92a789444708fa1cb4cc5a89e0aa6cc7a279b62a7b8a4d2857255a18197d0090,detect,high,2027-04-13,stager32.bin Cobalt Strike x86 stager (Pwn3rs Team 4.9.1 build),campaign:CyberXero;actor:CyberXero sha256,a5ae0aab352871bc0b038b3aa43b03eb223425628c884af7b9fc592cd34eb86c,detect,high,2027-04-13,WSO-Shell.php WSO webshell obfuscated with R00t-Shell.com 2.0.15,campaign:CyberXero;actor:CyberXero sha256,71e21094c1ac1cf0275c91ed377965e248bca1c12711f6dd20e2682681fc1192,detect,high,2027-04-13,1.bin Chinese-cluster staging payload,campaign:CyberXero;actor:CyberXero sha256,59c535f47ab4d35f6d9fc8b8aec4a72438ea0b89e5a4dcea74b05d2d32cfa483,detect,high,2027-04-13,config.bin Chinese-cluster staging payload,campaign:CyberXero;actor:CyberXero ipv4,46.21.250.135,detect,high,2027-04-13,Primary workstation and open directory seed node,campaign:CyberXero;actor:CyberXero ipv4,45.88.106.2,detect,high,2027-04-13,Provisioning server port 1500,campaign:CyberXero;actor:CyberXero ipv4,45.88.106.78,detect,high,2027-04-13,Mass scanning server,campaign:CyberXero;actor:CyberXero ipv4,42.193.227.214,detect,high,2027-04-13,Cobalt Strike team server (1002 HTTPS beacon / 8044 HTTP staging / 8033 PS stager / 9995),campaign:CyberXero;actor:CyberXero ipv4,42.193.100.94,detect,high,2027-04-13,Redis exploitation node and PentAGI agents,campaign:CyberXero;actor:CyberXero ipv4,49.234.12.182,detect,high,2027-04-13,Staging and payload delivery (Chinese cluster),campaign:CyberXero;actor:CyberXero ipv4,212.193.31.189,detect,high,2027-04-13,Multi-chain CryptoPay gateway,campaign:CyberXero;actor:CyberXero ipv4,91.208.184.148,detect,high,2027-04-13,Secondary workstation,campaign:CyberXero;actor:CyberXero
indicatorType,indicatorValue,action,title,description,expirationTime,severity,recommendedActions,rbacGroups,category,mitretechniques,GenerateAlert FileSha256,92a789444708fa1cb4cc5a89e0aa6cc7a279b62a7b8a4d2857255a18197d0090,Audit,stager32.bin Cobalt Strike x86 stager,stager32.bin Cobalt Strike x86 stager (Pwn3rs Team 4.9.1 build),2027-04-13T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True FileSha256,a5ae0aab352871bc0b038b3aa43b03eb223425628c884af7b9fc592cd34eb86c,Audit,WSO-Shell.php WSO webshell obfuscated with R00t-Shell.com 2.,WSO-Shell.php WSO webshell obfuscated with R00t-Shell.com 2.0.15,2027-04-13T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True FileSha256,71e21094c1ac1cf0275c91ed377965e248bca1c12711f6dd20e2682681fc1192,Audit,1.bin Chinese-cluster staging payload,1.bin Chinese-cluster staging payload,2027-04-13T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True FileSha256,59c535f47ab4d35f6d9fc8b8aec4a72438ea0b89e5a4dcea74b05d2d32cfa483,Audit,config.bin Chinese-cluster staging payload,config.bin Chinese-cluster staging payload,2027-04-13T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True IpAddress,46.21.250.135,Audit,Primary workstation and open directory seed node,Primary workstation and open directory seed node,2027-04-13T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True IpAddress,45.88.106.2,Audit,Provisioning server port 1500,Provisioning server port 1500,2027-04-13T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True IpAddress,45.88.106.78,Audit,Mass scanning server,Mass scanning server,2027-04-13T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True IpAddress,42.193.227.214,Audit,Cobalt Strike team server,Cobalt Strike team server (1002 HTTPS beacon / 8044 HTTP staging / 8033 PS stager / 9995),2027-04-13T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True IpAddress,42.193.100.94,Audit,Redis exploitation node and PentAGI agents,Redis exploitation node and PentAGI agents,2027-04-13T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True IpAddress,49.234.12.182,Audit,Staging and payload delivery,Staging and payload delivery (Chinese cluster),2027-04-13T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True IpAddress,212.193.31.189,Audit,Multi-chain CryptoPay gateway,Multi-chain CryptoPay gateway,2027-04-13T00:00:00.0Z,High,Investigate the device and pivot into the pack's queries,,,,True IpAddress,91.208.184.148,Audit,Secondary workstation,Secondary workstation,2027-04-13T00:00:00.0Z,High,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.
CyberXero - behavioural signatures (survive IP and hash rotation)
B1 WordPress administrator whose login matches ^wp2_[0-9a-f]{8}$
B2 Plugin directory matching wp2shell_[0-9a-f]{8} under wp-content/plugins
B3 WSO-Shell.php registered as an active plugin
B4 Windows service UpdSvc, or any service whose binPath runs powershell/cmd with IEX or a URL
B5 PowerShell IEX download from http://<bare IPv4>:<port>/<13 lowercase alphanumerics>
B6 services.exe parenting a scripting host with a download token
B7 WmiPrvSE.exe parenting cmd/powershell, or wmic /node: from a non-admin host
B8 redis-cli SLAVEOF/REPLICAOF/CONFIG SET dir|dbfilename on a Redis host, or redis-server parenting a shell
B9 New or changed ~/.ssh/authorized_keys on a Redis host with no change ticket
B10 Web worker (apache2/httpd/nginx/php-fpm/w3wp) parenting several distinct tools within two minutes
B11 Redis 6379 reachable from non-private addresses
Named malware and tooling (names exactly as SOCRadar uses them)
wp2shell actor's own Python package: REST batch desync, SQL injection, rogue admin, WSO webshell as plugin
WSO-Shell.php WSO-family webshell, obfuscated with R00t-Shell.com 2.0.15
Cobalt Strike 4.9.1, unauthorized Pwn3rs Team build; svc.cna (UpdSvc) and scan_pth.cna aggressor scripts
PentAGI open-source AI pentest framework wired to the team server through an AI provider API
Claude Code up to 51 specialised agent definitions on the primary workstation
Telegram bot compromise notifications (actor side)
VLESS/Xray node layer anonymising attack traffic (actor side)
Role map: 42.193.227.214 team server (1002 HTTPS beacon, 8044 HTTP staging, 8033 PowerShell stager, 9995 team server)
42.193.100.94 Redis exploitation node; 49.234.12.182 staging; 46.21.250.135 workstation + open directory
45.88.106.2 provisioning (port 1500); 45.88.106.78 mass scanner; 212.193.31.189 CryptoPay; 91.208.184.148 secondary workstation
# Read-only audit helpers. Run through RTR, your RMM or a local shell.
# A. Windows: UpdSvc and scripting-host services
Get-Service -Name UpdSvc -ErrorAction SilentlyContinue
Get-CimInstance Win32_Service | Where-Object { $_.PathName -match '(powershell|pwsh|mshta|rundll32)' -and $_.PathName -match '(iex|invoke-expression|downloadstring|http)' } |
Select-Object Name, DisplayName, StartMode, PathName
# B. Linux: authorized_keys inventory (all users)
for h in /root /home/*; do f="$h/.ssh/authorized_keys"; [ -f "$f" ] && { echo "== $f"; stat -c '%y %U' "$f"; cut -c1-80 "$f"; }; done
# C. Linux: Redis exposure and replication
ss -ltnp | grep ':6379'
redis-cli INFO replication # unexpected master_host = investigate
# D. WordPress (wp-cli): rogue administrators and plugin directories
wp user list --role=administrator --fields=ID,user_login,user_registered | grep -E 'wp2_[0-9a-f]{8}'
find wp-content/plugins -maxdepth 1 -name 'wp2shell_*' ; find . -name 'WSO-Shell.php'
Action policy: nothing in the CSV is set to prevent. The whole set originates from one report (two-source rule), the hashes belong to non-executable files in three of four cases, and the IPs are cloud-hosted and will be retired. Expiry is six months. Promote an IP to prevent only after an independent vendor lists it.
Detection Validation Gates
Work these in order. A query that has not cleared gate 2 has no business being an alert.
| Gate | What to prove | How | Pass criteria |
|---|---|---|---|
| G1 · Telemetry ready | The events each query depends on arrive in your tenant | Run each filter alone over 24h with count(): process creation with parent and command line (CrowdStrike: ProcessRollup2. SentinelOne: Process Creation. Defender: DeviceProcessEvents), service creation (CrowdStrike: CreateService; outside endpoint telemetry on SentinelOne and Defender, use event 7045), outbound connection with process, inbound accepted connection. Confirm Linux sensors are on the web and Redis hosts. | Non-zero counts on Windows and Linux hosts; every missing source recorded as a gap |
| G2 · Benign baseline | Noise level before alerting | Run Q2, Q4, Q5, Q8, Q9, Q10, Q13, Q14, Q15 and Q16 over 14 days and tabulate hits by process, parent and account | Medium-FP queries explained by a short, named exclusion list; low-FP queries return zero or are explained one by one |
| G3 · Positive test | Detections fire on safe stand-ins | In a lab, create a service named UpdSvc with a harmless binPath; run a PowerShell command line containing a documentation-range bare IP and port with an IEX token; run redis-cli CONFIG SET dir on a throwaway Redis; start a shell from a test PHP script. No real attacker infrastructure is contacted. | Q3, Q2, Q11 and Q15 each return the lab event |
| G4 · Negative test | Known-good activity stays quiet | Run an approved RMM install, an Ansible key push, and a normal PHP page that calls a helper | Q4, Q13 and Q15 either stay quiet or are covered by a documented exclusion |
| G5 · Promotion | Move to Custom IOA in Monitor mode | Promote Q1, Q3 and Q12 on a pilot policy for one week | No unexplained detections; owner assigned |
| G6 · Response readiness | Someone can act on a hit | Walk section 14 with the owning web, database and Windows teams | Isolation path and credential-rotation owner agreed |
Hardening: Tiered
Each control is mapped to the technique, then to a MITRE mitigation (the why, read from the saved pages) and a vendor or best-practice authority (the what and where). Where no formal benchmark exists the control says so. Verification for each is given in the playbook (section 13).
- I1 · Take Redis off the internet. Bind to loopback or a private interface, keep protected mode on, require authentication or ACLs, and firewall 6379. T1098.004 and T1190. M1042 and M1018 (MITRE T1098.004). Authority: Redis security documentation (snapshot 11). Playbook P1.
- I2 · Neutralise the Redis lever. Rename or disable CONFIG and the replication commands through
rename-commandor ACLs, and run Redis as an unprivileged user that cannot write any user's .ssh directory. M1042, M1022. Authority: Redis security documentation. Playbook P1. - I3 · Lock down authorized_keys. Point sshd at a root-owned key directory so a service account cannot plant a key, set restrictive modes, and audit writes. M1022, M1018 (T1098.004). ⚠ best-practice, no formal benchmark saved in this pack. Playbook P2.
- I4 · WordPress write-surface reduction.
DISALLOW_FILE_EDIT, strict file permissions, no write for the web user on plugin directories where operations allow, delete unused plugins. M1042, M1018 (T1505.003). Authority: WordPress Hardening handbook (snapshot 12).DISALLOW_FILE_MODSis a documented core constant but is not in the saved page (⚠ verify against the handbook). Playbook P3. - I5 · Run the rogue-admin and plugin audits now. Section 7 N2, N3 and N5. Playbook P6.
- N1 · PowerShell visibility and constraint. Enable script block and module logging, move servers toward Constrained Language Mode with WDAC/AppLocker where a baseline exists. T1059.001. M1038, M1045, M1049, M1042, M1026 (MITRE T1059.001). Authority: Microsoft Learn about_Logging_Windows (snapshot 13). Playbook P4.
- N2 · Service creation auditing. Alert on event 7045 and 4697 with scripting-host binPaths. T1543.003. M1047 Audit, M1018, M1028 (MITRE T1543.003). Playbook P5.
- N3 · Remote WMI restriction. Limit inbound WMI and DCOM to management hosts; pilot the ASR rule that blocks process creation from PSExec and WMI commands in audit mode. T1047. M1040, M1038, M1026, M1018 (MITRE T1047). The ASR rule GUID is from Microsoft documentation not saved in this pack (⚠ verify the GUID before deploying). Playbook P4.
- N4 · Server egress control. Default-deny outbound from web and Redis servers with an allow list; block the team server port set to non-approved destinations. T1071.001. ⚠ best-practice, no formal benchmark saved in this pack.
- N5 · Apply the vendor fix for the WordPress core and plugin flaws used as delivery, and for Support Board, Magento and PrestaShop where present. Follow the separate CVE pack's guidance rather than duplicating it here.
- S1 · Segment the web tier. Web servers must not reach internal Windows hosts or the Redis tier except on named ports. Limits the Cobalt Strike pivot and WMI lateral movement. ⚠ best-practice, no formal benchmark saved in this pack.
- S2 · Application allow-listing on servers (WDAC or AppLocker) so a scripting host launched by services.exe or a web worker cannot run arbitrary content. M1038 (T1059.001, T1047).
- S3 · External attack-surface monitoring. Continuously find internet-reachable Redis and unpatched WordPress and e-commerce estates, the same way the actor's scanner does.
- S4 · Treat AI agent session logs as credential-grade data. SOCRadar's guidance: retain, encrypt and restrict them like credential logs or keystores. Relevant only if you run agents with terminal or network access.
Deployable Playbooks
Test every playbook on a pilot host first. P5 and P6 are read-only. Each playbook lists its prerequisites, reboot requirement and rollback. Example paths and the REPLACE_WITH_ secret are placeholders for you to set.
P1 · Redis hardening (I1, I2)
# P1 · Redis: private bind, authentication, no CONFIG, unprivileged (I1, I2) # Prerequisites: root on the Redis host; a client inventory so you do not break legitimate callers; Redis 6 or later for ACL. # Reboot required: no (restart the redis service) # Rollback: restore the saved copy: cp /etc/redis/redis.conf.pre-hardening /etc/redis/redis.conf ; systemctl restart redis cp /etc/redis/redis.conf /etc/redis/redis.conf.pre-hardening # edit /etc/redis/redis.conf bind 127.0.0.1 -::1 # or the private interface address only protected-mode yes requirepass REPLACE_WITH_LONG_RANDOM_SECRET rename-command CONFIG "" rename-command SLAVEOF "" rename-command REPLICAOF "" rename-command MODULE "" # if replicas are required, use ACLs for the replication user instead of leaving REPLICAOF open systemctl restart redis # verify ss -ltn | grep 6379 # must not show 0.0.0.0:6379 or [::]:6379 redis-cli -a "$REDIS_PASSWORD" CONFIG GET dir # expected: unknown command # network: allow tcp/6379 only from named client addresses, drop everything else
P2 · sshd root-owned keys and auditing (I3)
# P2 · sshd: root-owned authorized keys and write auditing (I3) # Prerequisites: root; every account that needs key login has a key file staged in the new directory first. # Reboot required: no (reload sshd). Test a second session before closing the first. # Rollback: remove the AuthorizedKeysFile line (default ~/.ssh/authorized_keys returns); systemctl reload sshd; remove the audit rule file install -d -m 755 -o root -g root /etc/ssh/authorized_keys # for each user: install -m 644 -o root -g root <key file> /etc/ssh/authorized_keys/<user> # in /etc/ssh/sshd_config: AuthorizedKeysFile /etc/ssh/authorized_keys/%u systemctl reload sshd # audit writes to any user key file (auditd) cat > /etc/audit/rules.d/authkeys.rules <<'EOF' -w /etc/ssh/authorized_keys -p wa -k authkeys -w /root/.ssh/authorized_keys -p wa -k authkeys EOF augenrules --load # verify sshd -T | grep -i authorizedkeysfile auditctl -l | grep authkeys
P3 · WordPress write-surface reduction (I4)
# P3 · WordPress: reduce the write surface (I4)
# Prerequisites: shell on the web host; a staging copy; know which plugin updates are done by hand or by CI.
# Reboot required: no
# Rollback: remove the added define() lines from wp-config.php; restore modes from the saved listing: setfacl --restore=/root/wp-perms.acl -R (or re-apply the previous chmod/chown)
getfacl -R /var/www/html > /root/wp-perms.acl 2>/dev/null # save current state (path is an example)
# wp-config.php
define( 'DISALLOW_FILE_EDIT', true );
# optional, blocks plugin and theme install and update from the dashboard; updates then run from CI or wp-cli:
define( 'DISALLOW_FILE_MODS', true );
# permissions per the WordPress handbook (example path; adjust to your layout)
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;
chmod 640 /var/www/html/wp-config.php
# remove inactive plugins, then verify
wp plugin list --status=inactive
wp plugin delete <inactive-plugin-slug>
wp user list --role=administrator --fields=user_login,user_registeredP4 · PowerShell logging and ASR audit (N1, N3)
# P4 · Windows: PowerShell logging, and ASR rule for PSExec/WMI process creation in audit mode (N1, N3)
# Prerequisites: Windows PowerShell 5.1 or 7 on test hosts; local admin; Defender Antivirus active for the ASR step; SIEM able to receive 4104.
# Reboot required: no
# Rollback: delete the policy keys (Remove-Item) and run Remove-MpPreference -AttackSurfaceReductionRules_Ids d1e49aac-8f56-4280-b9ba-993a6d77406c
New-Item -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging' -Force | Out-Null
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging' -Name EnableScriptBlockLogging -Value 1 -Type DWord
New-Item -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging' -Force | Out-Null
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging' -Name EnableModuleLogging -Value 1 -Type DWord
# ASR: block process creations from PSExec and WMI commands, AUDIT first (verify the GUID against Microsoft Learn)
Add-MpPreference -AttackSurfaceReductionRules_Ids d1e49aac-8f56-4280-b9ba-993a6d77406c -AttackSurfaceReductionRules_Actions AuditMode
# verify
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-PowerShell/Operational'; Id=4104} -MaxEvents 3
(Get-MpPreference).AttackSurfaceReductionRules_Ids
# note: audit-mode results land in the Defender operational log; endpoint-management and SCCM use WMI, so review before moving to BlockP5 · Service-creation review (N2)
# P5 · Windows: alert on suspicious service creation (N2), read-only query plus a forwarding hint
# Prerequisites: System log retention; PowerShell 5.1+; optionally a WEF/SIEM subscription for event 7045.
# Reboot required: no
# Rollback: none required (read-only)
Get-WinEvent -FilterHashtable @{LogName='System'; Id=7045; StartTime=(Get-Date).AddDays(-30)} |
Where-Object { $_.Message -match '(UpdSvc|powershell|pwsh|mshta|rundll32)' } |
Select-Object TimeCreated, @{n='Detail';e={$_.Message -replace '\s+',' '}}
# Security log 4697 (service installed) needs 'Audit Security System Extension' enabled:
auditpol /get /subcategory:"Security System Extension"P6 · Rogue-admin and webshell audit (I5)
# P6 · Rogue-admin and webshell audit across WordPress hosts (I5), read-only
# Prerequisites: wp-cli and shell access on each WordPress host; run from the WordPress root.
# Reboot required: no
# Rollback: none required (read-only). Do not delete a hit until its files are preserved for forensics.
wp user list --role=administrator --field=user_login | grep -E '^wp2_[0-9a-f]{8}$'
wp plugin list --status=active --fields=name,version | grep -E '^wp2shell_[0-9a-f]{8}'
find wp-content/plugins -maxdepth 1 -type d -name 'wp2shell_*' -printf '%TY-%Tm-%Td %p\n'
find . -type f -name 'WSO-Shell.php' -printf '%TY-%Tm-%Td %p\n'
# Redis hosts
for h in /root /home/*; do f="$h/.ssh/authorized_keys"; [ -f "$f" ] && stat -c '%y %n' "$f"; done
Containment Runbook
Sequencing rule: CyberXero is a broker. Assume any access it obtained has been or will be sold, so removing the shell is not closure. Rotate every credential stored on or reachable from a compromised web or Redis host, and treat the database as exfiltrated.
| Phase | Actions | Owner | Evidence to capture |
|---|---|---|---|
| C0 · Triage 0 to 15 min | Identify which query fired, the host and the account. Check whether Q1, Q3, Q6, Q12 and Q15 also fired on the same aid. Confirm whether the host is internet-facing and what it can reach. | SOC L1 | Falcon process tree; query output; host role |
| Isolate 15 to 60 min | Network-contain the host with the EDR isolation action. Block the eight published IPs and the port set at the egress firewall as a temporary measure (attacker-owned, cloud-hosted). Take the WordPress site offline or behind maintenance if a rogue admin or webshell is confirmed. | SOC L2 / network | Isolation confirmation; firewall change 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 L2 / network | Isolation confirmation; firewall change record |
| Preserve | Image the web root, the plugin directory, authorized_keys, shell history and web logs before cleanup. Capture memory on Windows hosts that ran the stager. | IR | Hashes and copies; chain of custody |
| Eradicate (Windows) | Stop and delete UpdSvc and any scripting-host service. Remove the beacon, scheduled tasks and WMI subscriptions found. Rebuild the host if a team server session was established. | IR / endpoint | Service export; registry hive copy |
| Eradicate (Linux and web) | Remove rogue wp2_ administrators, wp2shell_ plugin directories and WSO-Shell.php. Remove unattributed authorized_keys entries and rotate host keys if the key was in place. Re-image the Redis host if the process spawned children. Patch and apply P1 to P3 before returning to service. | Web / platform | List of removed accounts, files and keys |
| Rotate | Rotate WordPress salts, database credentials, application secrets, SSH keys, API tokens and any payment-gateway credentials on the host. Reset all WordPress administrator passwords and force re-authentication. | Platform / IAM | Rotation log |
| Recover | Return to service only after the full section 7 sweep is clean. Monitor Q1, Q3, Q6, Q12, Q15 and Q17 at a short interval for 30 days. Assess personal-data notification duties if customer data was reachable. | Service owner / legal | Sign-off record |
Detection Coverage Map
| Technique | Behavior | CQL | IOA | Hardening | CrowdStrike coverage | SentinelOne | Defender XDR |
|---|---|---|---|---|---|---|---|
| T1059.001 | PowerShell IEX stager from the team server | Q1, Q2 | Promote Q1 | N1, S2 | GOOD Strong on sensored Windows hosts | Good, with assumptions | Good, with assumptions |
| T1543.003 | UpdSvc and scripting-host services | Q3, Q4, Q5 | Promote Q3 | N2 | GOOD Service creation is outside endpoint telemetry on some platforms | Partial: Q3 approximate, Q4 approximate | Partial: Q3 approximate, Q4 approximate |
| T1071.001 | Beacon and staging to published IPs and ports | Q6, Q7, Q8 | No | N4 | PARTIAL Perishable IPs; port plan may change; no domain indicators published | Partial: Q7 approximate | Partial: same limit as CrowdStrike |
| T1047 | WMI remote execution | Q9, Q10 | No | N3 | PARTIAL Only the process side; no WMI event-subscription telemetry in this pack | Partial: same limit as CrowdStrike | Partial: same limit as CrowdStrike |
| T1098.004 | SSH key injection through Redis | Q11, Q12, Q13 | Promote Q12 | I2, I3 | PARTIAL The Redis save that writes the key creates no process: native N5 only | Partial: same limit as CrowdStrike | Partial: same limit as CrowdStrike |
| T1190 | Exposed Redis | Q14 | No | I1 | PARTIAL Intent unknowable; exposure finding, not proof | Partial: Q14 approximate | Partial: same limit as CrowdStrike |
| T1505.003 | Webshell command execution on sensored web servers | Q15, Q16, Q17 | No | I4 | PARTIAL Webshell file write and request path are outside endpoint telemetry | Partial: same limit as CrowdStrike | Partial: same limit as CrowdStrike |
| T1136.001 | Rogue wp2_ administrators | Q17 | No | I5 | GAP Account creation is a database write through the web app; native N2 only | GAP: same limit as CrowdStrike | GAP: same limit as CrowdStrike |
| T1190 / T1595.002 | Mass WordPress scanning and panel compromise | Q7 | No | N5 | GAP Web-server and database log territory; sensors see neither the HTTP request nor the SQL | GAP: same limit as CrowdStrike | GAP: same limit as CrowdStrike |
| T1550.002 | Pass-the-hash via scan_pth.cna | None | No | S1 | GAP Not covered; the source names the script only | GAP | GAP |
| T1102.002 | Telegram bot notification | None | No | None | GAP Actor-side | GAP | GAP |
| T1105 / T1027 | Published file hashes | Q18 | No | None | PARTIAL Most published files are not executables; expect few hits | Partial: Q18 approximate | Partial: Q18 approximate |
Validation gates (summary): telemetry ready (G1), benign baseline (G2), positive test (G3), negative test (G4), Monitor-mode promotion (G5), response readiness (G6). Full table in section 11.
Honest scope: this pack cannot see the mass WordPress compromise, the SQL injection, the rogue-administrator database write, the file write of the webshell, the Redis-side write to authorized_keys, pass-the-hash, or anything on the actor's side. It detects what the actor does on hosts you have sensors on: the stager, the service, WMI, shell and Redis process activity, webshell-spawned commands, and contact with published infrastructure. Hosts with no sensor depend on the section 7 native checks and on egress logs.
Hunt Summary Ticket
TITLE: CyberXero: AI-augmented initial access broker (Cobalt Strike, Redis, WordPress webshells)
SEVERITY: High. SOCRadar report 2026-10-06; active at publication; Ukrainian energy and utilities plus global WordPress and e-commerce
SCOPE: Sensored Windows hosts (stager, UpdSvc, WMI), sensored Linux web and Redis servers, and egress logs for unsensored hosts.
HYPOTHESIS: A host ran a PowerShell IEX stager against a CyberXero team server, persisted as a UpdSvc service, moved by WMI; or a web or
Redis server was breached, given a wp2shell_ plugin or an injected SSH key, and operated at machine pace.
QUERIES:
Q1 Process command line references CyberXero infrastructure CONF high | FP low | COST low
Q2 PowerShell or cmd IEX download from a bare-IP URL with a high port CONF medium | FP medium | COST low
Q3 UpdSvc service created (Cobalt Strike svc.cna persistence) CONF high | FP low | COST low
Q4 Service created with a scripting-host binPath that downloads or decodes CONF medium | FP medium | COST low
Q5 Script host spawned by services.exe with a download or decode token CONF medium | FP medium | COST low
Q6 Outbound connection to a published CyberXero address CONF high | FP low | COST low
Q7 Inbound connection accepted from a published CyberXero address CONF medium | FP low | COST low
Q8 External connection on the team server port set CONF medium | FP medium | COST medium
Q9 Command shell or script host spawned by WmiPrvSE.exe CONF medium | FP medium | COST low
Q10 WMI remote-execution initiators on the source host CONF medium | FP medium | COST medium
Q11 redis-cli replication or config abuse on a Linux host CONF medium | FP medium | COST low
Q12 redis-server spawning a shell or downloader CONF high | FP low | COST low
Q13 authorized_keys written or edited by a shell or file tool CONF medium | FP medium | COST low
Q14 Inbound connection to Redis port 6379 from a public address CONF medium | FP medium | COST medium
Q15 Web server worker spawning a shell or recon utility CONF medium | FP medium | COST low
Q16 Web worker child-process burst (machine-speed tempo) CONF medium | FP medium | COST medium
Q17 CyberXero artifact names in a command line CONF high | FP low | COST low
Q18 Hash sweep of the four published CyberXero files CONF medium | FP low | COST low
DO FIRST: 1. Q1, Q3, Q6, Q12, Q17 across 30 days (near-zero FP)
2. Q15 and Q16 on every sensored web server; Q14 to find public Redis
3. Section 7 native checks N2, N3, N5 (rogue admins, plugin dirs, authorized_keys)
4. Apply I1 and I2 (Redis) and I4 (WordPress) hardening
FINDINGS: [ ] Q1 hits: ______ [ ] Q3 hits: ______ [ ] Q6 hits: ______ [ ] Q12 hits: ______
[ ] Q15/Q16 hits: ______ [ ] Rogue wp2_ admins: ______ [ ] Unattributed authorized_keys: ______
[ ] Hosts with 2+ query hits in 24h (auto-escalate): ______
GAPS: - Mass WordPress scanning, SQL injection, rogue-admin DB write: outside endpoint telemetry
- Redis save that writes authorized_keys creates no process; only native N5 sees it
- Pass-the-hash (scan_pth.cna) has no query
- Telegram, VLESS/Xray, session logs: actor side
- Service creation is a cross-platform gap outside the CrowdStrike sensor
- All indicators single-originated at SOCRadar; nothing ships at prevent
ACTIONS: [ ] Promote Q1, Q3, Q12 to Custom IOA (Monitor mode, pilot policy, 1 week)
[ ] Import the section 10 CSV into IOC Management (detect, 6 month expiry)
[ ] Deploy Immediate hardening I1 to I5
[ ] Confirm Linux sensors on web and Redis hosts (gate G1)
OWNER: ______________________
VERSION: v0.1 - 2026-10-13Changelog
References
| Tier | Source | Used for | Accessed |
|---|---|---|---|
| 1 | SOCRadar: CyberXero, An AI-Augmented Initial Access Broker Targeting Ukrainian Critical Infrastructure (2026-10-06) | Yes | 2026-10-13 |
| 2 | GBHackers: Russian-Speaking CyberXero Uses AI Agent Swarm (2026-10-07) | Yes (narrative, five IPs) | 2026-10-13 |
| 2 | Security Affairs: CyberXero Used 51 AI Agents to Steal 628,000 Ukrainian Records (2026-10-12) | Yes (narrative) | 2026-10-13 |
| 2 | The Hacker News: CyberXero Uses Claude Code in Campaign That Stole Over 628,000 Ukrainian Records (2026-10-12) | Yes (narrative) | 2026-10-13 |
| 2 | eSecurityPlanet: CyberXero Uses Claude Code in Ukraine Data Theft (2026-10-12) | Yes (narrative) | 2026-10-13 |
| 1 | MITRE ATT&CK T1098.004, T1505.003, T1543.003, T1047, T1059.001 | Yes | 2026-10-13 |
| 1 | Redis documentation: Redis security | Yes (hardening) | 2026-10-13 |
| 1 | WordPress Developer Resources: Hardening WordPress | Yes (hardening) | 2026-10-13 |
| 1 | Microsoft Learn: about_Logging_Windows | Yes (hardening) | 2026-10-13 |
Full text of every cited page is saved in CyberXero-AI-IAB-Hunt-sources/ (13 snapshots).