Attackers may be using Adfind to enumerate domain controllers or ADFS servers as part of reconnaissance during a potential compromise. SOC teams should proactively hunt for this behavior in Azure Sentinel to identify early-stage adversary activity and prevent further lateral movement or privilege escalation.
KQL Query
let startdate = 10d;
let lookupwindow = 2m;
let threshold = 3; //number of commandlines in the set below
let DCADFSServersList = dynamic (["DCServer01", "DCServer02", "ADFSServer01"]); // Enter a reference list of hostnames for your DC/ADFS servers
let tokens = dynamic(["objectcategory","domainlist","dcmodes","adinfo","trustdmp","computers_pwdnotreqd","Domain Admins", "objectcategory=person", "objectcategory=computer", "objectcategory=*"]);
DeviceProcessEvents
| where Timestamp between (ago(startdate) .. now())
//| where DeviceName in (DCADFSServersList) // Uncomment to limit it to your DC/ADFS servers list if specified above or any pattern in hostnames (startswith, matches regex, etc).
| where ProcessCommandLine has_any (tokens)
| where ProcessCommandLine matches regex "(.*)>(.*)"
| summarize Commandlines = make_set(ProcessCommandLine), LastObserved=max(Timestamp) by bin(Timestamp, lookupwindow), AccountName, DeviceName, InitiatingProcessFileName, FileName
| extend Count = array_length(Commandlines)
| where Count > threshold
id: 9df6cf43-679c-4ffe-8da7-7b1174b17e5b
name: SuspiciousEnumerationUsingAdfind[Nobelium]
description: |
Attackers can use Adfind which is administrative tool to gather information about domain controllers or ADFS servers. They may also rename executables with other benign tools on the system.
The below query will look for Adfind usage in command line arguments irrespective of executable name in short span of time. You can limit query this to your DC and ADFS servers.
Below references talk about suspicious use of adfind by adversaries.
1. AdFind Recon
2. Navigating the MAZE: Tactics, Techniques and Procedures Associated With MAZE Ransomware Incidents
3. Analyzing Solorigate, the compromised DLL file that started a sophisticated cyberattack, and how Microsoft Defender helps protect customers
This query is inspired by a Azure Sentinel detection.
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- DeviceProcessEvents
tactics:
- Execution
- Discovery
- Collection
tags:
- Nobelium
query: |
let startdate = 10d;
let lookupwindow = 2m;
let threshold = 3; //number of commandlines in the set below
let DCADFSServersList = dynamic (["DCServer01", "DCServer02", "ADFSServer01"]); // Enter a reference list of hostnames for your DC/ADFS servers
let tokens = dynamic(["objectcategory","domainlist","dcmodes","adinfo","trustdmp","computers_pwdnotreqd","Domain Admins", "objectcategory=person", "objectcategory=computer", "objectcategory=*"]);
DeviceProcessEvents
| where Timestamp between (ago(startdate) .. now())
//| where DeviceName in (DCADFSServersList) // Uncomment to limit it to your DC/ADFS servers list if specified above or any pattern in hostnames (startswith, matches regex, etc).
| where ProcessCommandLine has_any (tokens)
| where ProcessCommandLine matches regex "(.*)>(.*)"
| summarize Commandlines = make_set(ProcessCommandLine), LastObserved=max(Timestamp) by bin(Timestamp, lookupwindow), AccountName, DeviceName, InitiatingProcessFileName, FileName
| extend Count = array_length(Commandlines)
| where Count > threshold
| Sentinel Table | Notes |
|---|---|
DeviceProcessEvents | Ensure this data connector is enabled |
Scenario: Adfind is used by an administrator for legitimate domain enumeration
Filter/Exclusion: Check the user context (e.g., user = domain_admin or user = enterprise_admin) and verify if the command is part of a known administrative task (e.g., adfind -b dc=example,dc=com -s base -t dc).
Suggested Filter: user = domain_admin or user = enterprise_admin and command_line contains "adfind -b dc=example,dc=com"
Scenario: Scheduled job runs Adfind for routine health checks
Filter/Exclusion: Identify and exclude scheduled tasks that are known to run Adfind for monitoring purposes (e.g., HealthCheck-ADDomain).
Suggested Filter: process_name = "schtasks.exe" and task_name contains "HealthCheck-ADDomain"
Scenario: Adfind is renamed to a benign tool name (e.g., net.exe) for obfuscation
Filter/Exclusion: Check for renamed executables by comparing the file hash against known benign tools (e.g., net.exe or dsquery.exe).
Suggested Filter: file_hash != known_benign_hashes or file_name != "net.exe"
Scenario: Adfind is used by a service account during domain synchronization
Filter/Exclusion: Exclude service accounts that are known to perform domain synchronization tasks (e.g., syncsvc$).
Suggested Filter: user = syncsvc$ or user = domain_sync_account
Scenario: Adfind is used to gather information about ADFS servers during a legitimate audit
Filter/Exclusion: Identify and exclude audit activities that involve querying ADFS servers (e.g., `adfind -b CN=ADFS,C