← Back to SOC feed Coverage →

Rare-process-as-a-service

kql MEDIUM Azure-Sentinel
T1543T1543.003
DeviceFileEventsDeviceImageLoadEventsDeviceNetworkEventsDeviceProcessEvents
huntingmicrosoftofficial
This rule was pulled from an open-source repository and enriched with AI. Validate in a test environment before deploying to production.
View original rule at Azure-Sentinel →
Retrieved: 2026-05-23T23:00:00Z · Confidence: medium

Hunt Hypothesis

Adversaries may use rare processes launched as a service to evade detection and maintain persistence. SOC teams should proactively hunt for this behavior in Azure Sentinel to identify potential stealthy malware or unauthorized process execution.

KQL Query

let LookupTime = 30d;
let WhiteList = pack_array(
"svchost.exe",
"mssense.exe",
"msmpeng.exe",
"searchindexer.exe",
"microsoftedgeupdate.exe"
);
let GetServices = materialize (
DeviceProcessEvents
| where Timestamp > ago(LookupTime)
| where InitiatingProcessParentFileName contains "services.exe"
| where InitiatingProcessFileName !in~(WhiteList)
| project Timestamp, DeviceName, StartedChildProcess = FileName, StartedChildProcessSHA1 = SHA1, StartedChildProcessCmdline = ProcessCommandLine, ServiceProcessSHA1 = InitiatingProcessSHA1, ServiceProcess = InitiatingProcessFileName, ServiceProcessCmdline = InitiatingProcessCommandLine, ServiceProcessID = InitiatingProcessId, ServiceProcessCreationTime = InitiatingProcessCreationTime, ServiceProcessUser = InitiatingProcessAccountName
);
GetServices
| summarize count() by ServiceProcess, DeviceName
| where count_ < 6 
| join kind = inner GetServices on ServiceProcess, DeviceName 
| join kind = leftouter ( 
DeviceNetworkEvents 
| where Timestamp > ago(LookupTime)
| where InitiatingProcessParentFileName contains "services.exe"
| where InitiatingProcessFileName !in~(WhiteList)
| project Timestamp, DeviceName, ServiceProcessSHA1 = InitiatingProcessSHA1, ServiceProcess = InitiatingProcessFileName, ServiceProcessCmdline = InitiatingProcessCommandLine, ServiceProcessID = InitiatingProcessId, ServiceProcessCreationTime = InitiatingProcessCreationTime, ServiceProcessUser = InitiatingProcessAccountName, NetworkAction = ActionType, RemoteIP, RemoteUrl
) on DeviceName, ServiceProcess, ServiceProcessCmdline, ServiceProcessCreationTime, ServiceProcessID, ServiceProcessUser, ServiceProcessSHA1
| join kind = leftouter (
DeviceFileEvents
| where Timestamp > ago(LookupTime)
| where InitiatingProcessParentFileName contains "services.exe"
| where InitiatingProcessFileName !in~(WhiteList)
| project Timestamp, DeviceName, ServiceProcessSHA1 = InitiatingProcessSHA1, ServiceProcess = InitiatingProcessFileName, ServiceProcessCmdline = InitiatingProcessCommandLine, ServiceProcessID = InitiatingProcessId, ServiceProcessCreationTime = InitiatingProcessCreationTime, ServiceProcessUser = InitiatingProcessAccountName, FileAction = ActionType, ModifiedFile = FileName, ModifiedFileSHA1 = SHA1, ModifiedFilePath = FolderPath
) on DeviceName, ServiceProcess, ServiceProcessCmdline, ServiceProcessCreationTime, ServiceProcessID, ServiceProcessUser, ServiceProcessSHA1
| join kind = leftouter (
DeviceImageLoadEvents
| where Timestamp > ago(LookupTime)
| where InitiatingProcessParentFileName contains "services.exe"
| where InitiatingProcessFileName !in~(WhiteList)
| project Timestamp, DeviceName, ServiceProcessSHA1 = InitiatingProcessSHA1, ServiceProcess = InitiatingProcessFileName, ServiceProcessCmdline = InitiatingProcessCommandLine, ServiceProcessID = InitiatingProcessId, ServiceProcessCreationTime = InitiatingProcessCreationTime, ServiceProcessUser = InitiatingProcessAccountName, LoadedDLL = FileName, LoadedDLLSHA1 = SHA1, LoadedDLLPath = FolderPath
) on DeviceName, ServiceProcess, ServiceProcessCmdline, ServiceProcessCreationTime, ServiceProcessID, ServiceProcessUser, ServiceProcessSHA1
| summarize ConnectedAddresses = make_set(RemoteIP), ConnectedUrls = make_set(RemoteUrl), FilesModified = make_set(ModifiedFile),FileModFolderPath = make_set(ModifiedFilePath),FileModHA1s = make_set(ModifiedFileSHA1), ChildProcesses = make_set(StartedChildProcess), ChildCommandlines = make_set(StartedChildProcessCmdline), DLLsLoaded = make_set(LoadedDLL), DLLSHA1 = make_set(LoadedDLLSHA1) by DeviceName, ServiceProcess, ServiceProcessCmdline, ServiceProcessCreationTime, ServiceProcessID, ServiceProcessUser, ServiceProcessSHA1

Analytic Rule Definition

id: a60ac80f-dce6-43ec-b102-9ae8c094d5dc
name: Rare-process-as-a-service
description: |
  This query is looking for rarely seen processes which are launched as a service. 
  Author: Jouni Mikkola
  More info: https://threathunt.blog/rare-process-launch-as-a-service/
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
  dataTypes:
  - DeviceProcessEvents
  - DeviceNetworkEvents
  - DeviceFileEvents
  - DeviceImageLoadEvents
tactics:
  - Persistence
relevantTechniques:
  - T1543
  - T1543.003
query: |
  let LookupTime = 30d;
  let WhiteList = pack_array(
  "svchost.exe",
  "mssense.exe",
  "msmpeng.exe",
  "searchindexer.exe",
  "microsoftedgeupdate.exe"
  );
  let GetServices = materialize (
  DeviceProcessEvents
  | where Timestamp > ago(LookupTime)
  | where InitiatingProcessParentFileName contains "services.exe"
  | where InitiatingProcessFileName !in~(WhiteList)
  | project Timestamp, DeviceName, StartedChildProcess = FileName, StartedChildProcessSHA1 = SHA1, StartedChildProcessCmdline = ProcessCommandLine, ServiceProcessSHA1 = InitiatingProcessSHA1, ServiceProcess = InitiatingProcessFileName, ServiceProcessCmdline = InitiatingProcessCommandLine, ServiceProcessID = InitiatingProcessId, ServiceProcessCreationTime = InitiatingProcessCreationTime, ServiceProcessUser = InitiatingProcessAccountName
  );
  GetServices
  | summarize count() by ServiceProcess, DeviceName
  | where count_ < 6 
  | join kind = inner GetServices on ServiceProcess, DeviceName 
  | join kind = leftouter ( 
  DeviceNetworkEvents 
  | where Timestamp > ago(LookupTime)
  | where InitiatingProcessParentFileName contains "services.exe"
  | where InitiatingProcessFileName !in~(WhiteList)
  | project Timestamp, DeviceName, ServiceProcessSHA1 = InitiatingProcessSHA1, ServiceProcess = InitiatingProcessFileName, ServiceProcessCmdline = InitiatingProcessCommandLine, ServiceProcessID = InitiatingProcessId, ServiceProcessCreationTime = InitiatingProcessCreationTime, ServiceProcessUser = InitiatingProcessAccountName, NetworkAction = ActionType, RemoteIP, RemoteUrl
  ) on DeviceName, ServiceProcess, ServiceProcessCmdline, ServiceProcessCreationTime, ServiceProcessID, ServiceProcessUser, ServiceProcessSHA1
  | join kind = leftouter (
  DeviceFileEvents
  | where Timestamp > ago(LookupTime)
  | where InitiatingProcessParentFileName contains "services.exe"
  | where InitiatingProcessFileName !in~(WhiteList)
  | project Timestamp, DeviceName, ServiceProcessSHA1 = InitiatingProcessSHA1, ServiceProcess = InitiatingProcessFileName, ServiceProcessCmdline = InitiatingProcessCommandLine, ServiceProcessID = InitiatingProcessId, ServiceProcessCreationTime = InitiatingProcessCreationTime, ServiceProcessUser = InitiatingProcessAccountName, FileAction = ActionType, ModifiedFile = FileName, ModifiedFileSHA1 = SHA1, ModifiedFilePath = FolderPath
  ) on DeviceName, ServiceProcess, ServiceProcessCmdline, ServiceProcessCreationTime, ServiceProcessID, ServiceProcessUser, ServiceProcessSHA1
  | j

Required Data Sources

Sentinel TableNotes
DeviceFileEventsEnsure this data connector is enabled
DeviceImageLoadEventsEnsure this data connector is enabled
DeviceNetworkEventsEnsure this data connector is enabled
DeviceProcessEventsEnsure this data connector is enabled

MITRE ATT&CK Context

References

False Positive Guidance

Original source: https://github.com/Azure/Azure-Sentinel/blob/main/Hunting Queries/Microsoft 365 Defender/Persistence/Rare-process-as-a-service.yaml