← Back to SOC feed Coverage →

Exchange Worker Process Making Remote Call

kql MEDIUM Azure-Sentinel
T1059.001T1059.003
DeviceProcessEventsW3CIISLog
exploitmicrosoftofficialpowershell
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-03-25T03:06:09Z · Confidence: medium

Hunt Hypothesis

Exchange Worker Process Making Remote Call detects potential command and control activity where the IIS worker process is used to execute remote commands via cmd.exe or PowerShell, indicating possible compromise of Exchange servers. SOC teams should proactively hunt for this behavior in Azure Sentinel to identify and mitigate early-stage adversary access and exfiltration attempts.

KQL Query

let suspiciousCmdLineKeywords = dynamic(["http://", "https://"]);
// Identify exchange servers based on known paths
// Summarize these to get a list of exchange server hostnames
let exchangeServers = W3CIISLog
| where csUriStem has_any("/owa/","/ews/","/ecp/","/autodiscover/")
// Only where successful, rule out failed scanning
| where scStatus startswith "2"
| summarize by Computer;
DeviceProcessEvents
| where DeviceName in~ (exchangeServers)
// Where the IIS worker process initiated CMD or PowerShell
| where InitiatingProcessParentFileName == "w3wp.exe"
| where InitiatingProcessFileName has_any("cmd.exe", "powershell.exe")
// Where CMD or PowerShell command line included parameters associated with CVE-2022-41040/CVE-2022-41082 exploitation
| where ProcessCommandLine has_any(suspiciousCmdLineKeywords)
| project TimeGenerated, DeviceId, DeviceName, InitiatingProcessFileName, ProcessCommandLine, AccountDomain = InitiatingProcessAccountDomain, AccountName = InitiatingProcessAccountName
| extend Account = strcat(AccountDomain, "\\", AccountName)
| extend HostName = tostring(split(DeviceName, ".")[0]), DomainIndex = toint(indexof(DeviceName, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(DeviceName, DomainIndex + 1), DeviceName)

Analytic Rule Definition

id: 2c701f94-783c-4cd4-bc9b-3b3334976090
name: Exchange Worker Process Making Remote Call
description: |
  'This query dynamically identifies Exchange servers and then looks for instances where the IIS worker process initiates a call out to a remote URL using either cmd.exe or powershell.exe.
  This behaviour was described as post-compromise behaviour following exploitation of CVE-2022-41040 and CVE-2022-41082, this pattern of activity was use to download additional tools to the server. This suspicious activity is generic.'
severity: Medium
requiredDataConnectors:
  - connectorId: AzureMonitor(IIS)
    dataTypes:
      - W3CIISLog
  - connectorId: MicrosoftThreatProtection
    dataTypes:
    - DeviceProcessEvents
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt 
triggerThreshold: 0
tactics:
  - Execution
relevantTechniques:
  - T1059.001
  - T1059.003
query: |
  let suspiciousCmdLineKeywords = dynamic(["http://", "https://"]);
  // Identify exchange servers based on known paths
  // Summarize these to get a list of exchange server hostnames
  let exchangeServers = W3CIISLog
  | where csUriStem has_any("/owa/","/ews/","/ecp/","/autodiscover/")
  // Only where successful, rule out failed scanning
  | where scStatus startswith "2"
  | summarize by Computer;
  DeviceProcessEvents
  | where DeviceName in~ (exchangeServers)
  // Where the IIS worker process initiated CMD or PowerShell
  | where InitiatingProcessParentFileName == "w3wp.exe"
  | where InitiatingProcessFileName has_any("cmd.exe", "powershell.exe")
  // Where CMD or PowerShell command line included parameters associated with CVE-2022-41040/CVE-2022-41082 exploitation
  | where ProcessCommandLine has_any(suspiciousCmdLineKeywords)
  | project TimeGenerated, DeviceId, DeviceName, InitiatingProcessFileName, ProcessCommandLine, AccountDomain = InitiatingProcessAccountDomain, AccountName = InitiatingProcessAccountName
  | extend Account = strcat(AccountDomain, "\\", AccountName)
  | extend HostName = tostring(split(DeviceName, ".")[0]), DomainIndex = toint(indexof(DeviceName, '.'))
  | extend HostNameDomain = iff(DomainIndex != -1, substring(DeviceName, DomainIndex + 1), DeviceName)
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: Account
      - identifier: Name
        columnName: AccountName
      - identifier: NTDomain
        columnName: AccountDomain
  - entityType: Host
    fieldMappings:
      - identifier: FullName
        columnName: DeviceName
      - identifier: HostName
        columnName: HostName
      - identifier: NTDomain
        columnName: HostNameDomain
version: 1.1.2
kind: Scheduled
metadata:
    source:
        kind: Community
    author:
        name: Microsoft Security Community
    support:
        tier: Community
    categories:
        domains: [ "Application" ]

Required Data Sources

Sentinel TableNotes
DeviceProcessEventsEnsure this data connector is enabled
W3CIISLogEnsure this data connector is enabled

MITRE ATT&CK Context

References

False Positive Guidance

Original source: https://github.com/Azure/Azure-Sentinel/blob/main/Detections/MultipleDataSources/ExchangeWorkerProcessMakingRemoteCall.yaml