Adversaries may attempt to modify or access registry keys associated with Microsoft Entra ID Health service agents to compromise or disable critical identity services. SOC teams should proactively hunt for this behavior in Azure Sentinel to identify potential tampering with infrastructure components that support secure authentication and access control.
KQL Query
// ADHealth Monitoring Agent Registry Key
let aadHealthMonAgentRegKey = "\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\MicrosoftOnline\\Reporting\\MonitoringAgent";
// Filter out known processes
let aadConnectHealthProcs = dynamic ([
'Microsoft.Identity.Health.Adfs.DiagnosticsAgent.exe',
'Microsoft.Identity.Health.Adfs.InsightsService.exe',
'Microsoft.Identity.Health.Adfs.MonitoringAgent.Startup.exe',
'Microsoft.Identity.Health.Adfs.PshSurrogate.exe',
'Microsoft.Identity.Health.Common.Clients.ResourceMonitor.exe',
'Microsoft.Identity.Health.AadSync.MonitoringAgent.Startup.exe',
'Microsoft.Identity.AadConnect.Health.AadSync.Host.exe',
'Microsoft.Azure.ActiveDirectory.Synchronization.Upgrader.exe',
'miiserver.exe'
]);
(union isfuzzy=true
(
SecurityEvent
| where EventID == '4656'
| where EventData has aadHealthMonAgentRegKey
| extend EventData = parse_xml(EventData).EventData.Data
| mv-expand bagexpansion=array EventData
| evaluate bag_unpack(EventData)
| extend Key = tostring(column_ifexists('@Name', "")), Value = column_ifexists('#text', "")
| evaluate pivot(Key, any(Value), TimeGenerated, Computer, EventID)
| extend ObjectName = column_ifexists("ObjectName", ""),
ObjectType = column_ifexists("ObjectType", "")
| where ObjectType == 'Key'
| where ObjectName == aadHealthMonAgentRegKey
| extend SubjectUserName = column_ifexists("SubjectUserName", ""),
SubjectDomainName = column_ifexists("SubjectDomainName", ""),
ProcessName = column_ifexists("ProcessName", "")
| extend Process = split(ProcessName, '\\', -1)[-1],
Account = strcat(SubjectDomainName, "\\", SubjectUserName)
| where Process !in (aadConnectHealthProcs)
| summarize StartTime = max(TimeGenerated), EndTime = min(TimeGenerated), count() by EventID, Account, Computer, Process, SubjectUserName, SubjectDomainName, ObjectName, ObjectType, ProcessName
),
( WindowsEvent
| where EventID == '4656' and EventData has aadHealthMonAgentRegKey
| extend ObjectType = tostring(EventData.ObjectType)
| where ObjectType == 'Key'
| extend ObjectName = tostring(EventData.ObjectName)
| where ObjectName == aadHealthMonAgentRegKey
| extend ProcessName = tostring(EventData.ProcessName)
| extend Process = tostring(split(ProcessName, '\\')[-1])
| where Process !in (aadConnectHealthProcs)
| extend Account = strcat(tostring(EventData.SubjectDomainName),"\\", tostring(EventData.SubjectUserName))
| extend SubjectUserName = tostring(EventData.SubjectUserName)
| extend SubjectDomainName = tostring(EventData.SubjectDomainName)
| summarize StartTime = max(TimeGenerated), EndTime = min(TimeGenerated), count() by EventID, Account, Computer, Process, SubjectUserName, SubjectDomainName, ObjectName, ObjectType, ProcessName
),
(
SecurityEvent
| where EventID == '4663'
| where ObjectType == 'Key'
| where ObjectName == aadHealthMonAgentRegKey
| extend Process = tostring(split(ProcessName, '\\', -1)[-1])
| where Process !in (aadConnectHealthProcs)
| summarize StartTime = max(TimeGenerated), EndTime = min(TimeGenerated), count() by EventID, Account, Computer, Process, SubjectUserName, SubjectDomainName, ObjectName, ObjectType, ProcessName
),
( WindowsEvent
| where EventID == '4663' and EventData has aadHealthMonAgentRegKey
| extend ObjectType = tostring(EventData.ObjectType)
| where ObjectType == 'Key'
| extend ObjectName = tostring(EventData.ObjectName)
| where ObjectName == aadHealthMonAgentRegKey
| extend ProcessName = tostring(EventData.ProcessName)
| extend Process = tostring(split(ProcessName, '\\')[-1])
| where Process !in (aadConnectHealthProcs)
| extend Account = strcat(tostring(EventData.SubjectDomainName),"\\", tostring(EventData.SubjectUserName))
| extend SubjectUserName = tostring(EventData.SubjectUserName)
| extend SubjectDomainName = tostring(EventData.SubjectDomainName)
| summarize StartTime = max(TimeGenerated), EndTime = min(TimeGenerated), count() by EventID, Account, Computer, Process, SubjectUserName, SubjectDomainName, ObjectName, ObjectType, ProcessName
)
)
// You can filter out potential machine accounts
//| where AccountType != 'Machine'
| extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
| extend Name = tostring(split(Account, "\\")[1]), NTDomain = tostring(split(Account, "\\")[0])
id: 06bbf969-fcbe-43fa-bac2-b2fa131d113a
name: Microsoft Entra ID Health Service Agents Registry Keys Access
description: |
'This detection uses Windows security events to detect suspicious access attempts to the registry key values and sub-keys of Microsoft Entra ID Health service agents (e.g AD FS).
Information from AD Health service agents can be used to potentially abuse some of the features provided by those services in the cloud (e.g. Federation).
This detection requires an access control entry (ACE) on the system access control list (SACL) of the following securable object: HKLM:\SOFTWARE\Microsoft\ADHealthAgent.
Make sure you set the SACL to propagate to its sub-keys. You can find more information in here https://github.com/OTRF/Set-AuditRule/blob/master/rules/registry/aad_connect_health_service_agent.yml
'
severity: Medium
requiredDataConnectors:
- connectorId: SecurityEvents
dataTypes:
- SecurityEvent
- connectorId: WindowsSecurityEvents
dataTypes:
- SecurityEvents
- connectorId: WindowsForwardedEvents
dataTypes:
- WindowsEvent
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Collection
relevantTechniques:
- T1005
tags:
- SimuLand
query: |
// ADHealth Monitoring Agent Registry Key
let aadHealthMonAgentRegKey = "\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\MicrosoftOnline\\Reporting\\MonitoringAgent";
// Filter out known processes
let aadConnectHealthProcs = dynamic ([
'Microsoft.Identity.Health.Adfs.DiagnosticsAgent.exe',
'Microsoft.Identity.Health.Adfs.InsightsService.exe',
'Microsoft.Identity.Health.Adfs.MonitoringAgent.Startup.exe',
'Microsoft.Identity.Health.Adfs.PshSurrogate.exe',
'Microsoft.Identity.Health.Common.Clients.ResourceMonitor.exe',
'Microsoft.Identity.Health.AadSync.MonitoringAgent.Startup.exe',
'Microsoft.Identity.AadConnect.Health.AadSync.Host.exe',
'Microsoft.Azure.ActiveDirectory.Synchronization.Upgrader.exe',
'miiserver.exe'
]);
(union isfuzzy=true
(
SecurityEvent
| where EventID == '4656'
| where EventData has aadHealthMonAgentRegKey
| extend EventData = parse_xml(EventData).EventData.Data
| mv-expand bagexpansion=array EventData
| evaluate bag_unpack(EventData)
| extend Key = tostring(column_ifexists('@Name', "")), Value = column_ifexists('#text', "")
| evaluate pivot(Key, any(Value), TimeGenerated, Computer, EventID)
| extend ObjectName = column_ifexists("ObjectName", ""),
ObjectType = column_ifexists("ObjectType", "")
| where ObjectType == 'Key'
| where ObjectName == aadHealthMonAgentRegKey
| extend SubjectUserName = column_ifexists("SubjectUserName", ""),
SubjectDomainName = column_ifexists("SubjectDomainName", ""),
ProcessName = column_ifexists("ProcessName", "")
| extend Process = split(ProcessName, '\\', -1)[-1],
Account = strcat(SubjectDomainName, "\\", SubjectUserName)
| where Process !in (aadConnec
| Sentinel Table | Notes |
|---|---|
SecurityEvent | Ensure this data connector is enabled |
WindowsEvent | Ensure this data connector is enabled |
Scenario: Scheduled Task for Health Service Agent Maintenance
Description: A legitimate scheduled task runs to maintain or update the Microsoft Entra ID Health Service Agent.
Filter/Exclusion: EventID=41 and TaskName contains “HealthServiceAgent” or “Microsoft Entra ID Health”
Scenario: Admin Task to Configure Health Service Agent Settings
Description: An administrator manually configures the Health Service Agent settings via the registry during routine maintenance.
Filter/Exclusion: EventID=41 and User is a known admin account (e.g., Administrator, Domain Admins) and ProcessName contains “regedit.exe” or “reg.exe”
Scenario: PowerShell Script for Agent Configuration
Description: A PowerShell script is used to configure or troubleshoot the Health Service Agent.
Filter/Exclusion: EventID=41 and ProcessName contains “powershell.exe” and CommandLine includes “Microsoft Entra ID” or “HealthServiceAgent”
Scenario: System Update or Patching Process
Description: A system update or patching process modifies registry keys related to the Health Service Agent.
Filter/Exclusion: EventID=41 and ProcessName contains “wusa.exe” or “msiexec.exe” and EventID is associated with system updates (e.g., 6006, 6008)
Scenario: Third-Party Tool for Monitoring or Compliance
Description: A third-party monitoring or compliance tool accesses the Health Service Agent registry keys for audit or reporting purposes.
Filter/Exclusion: EventID=41 and ProcessName contains “Splunk”, “LogParser”, or “Microsoft Monitoring Agent” and User is a