Detection rules › Kusto

Probable AdFind Recon Tool Usage

Status
available
Severity
high
Time window
1h
Source
github.com/Azure/Azure-Sentinel

This query identifies the host and account that executed AdFind, by hash and filename, in addition to the flags commonly utilized by various threat actors during the reconnaissance phase.

MITRE ATT&CK coverage

Event coverage

Rule body kusto

id: c63ae777-d5e0-4113-8c9a-c2c9d3d09fcd
name: Probable AdFind Recon Tool Usage
description: |
  'This query identifies the host and account that executed AdFind, by hash and filename, in addition to the flags commonly utilized by various threat actors during the reconnaissance phase.'
severity: High
status: Available
requiredDataConnectors:
  - connectorId: MicrosoftThreatProtection
    dataTypes:
      - DeviceProcessEvents
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Discovery
relevantTechniques:
  - T1016
  - T1018
  - T1069.002
  - T1087.002
  - T1482
query: |
 let args = dynamic(["objectcategory","domainlist","dcmodes","adinfo","trustdmp","computers_pwdnotreqd","Domain Admins", "objectcategory=person", "objectcategory=computer", "objectcategory=*","dclist"]);
 let parentProcesses = dynamic(["pwsh.exe","powershell.exe","cmd.exe"]);
 DeviceProcessEvents
 //looks for execution from a shell
 | where InitiatingProcessFileName in~ (parentProcesses)
 // main filter
 | where FileName =~ "AdFind.exe" or SHA256 == "c92c158d7c37fea795114fa6491fe5f145ad2f8c08776b18ae79db811e8e36a3"
    // AdFind common Flags to check for from various threat actor TTPs
     or ProcessCommandLine has_any (args)
 | extend HostName = split(DeviceName, '.', 0)[0], DnsDomain = strcat_array(array_slice(split(DeviceName, '.'), 1, -1), '.'), FileHashAlgorithm = "SHA256"
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: AccountName
      - identifier: UPNSuffix
        columnName: AccountDomain 
  - entityType: Host
    fieldMappings:
      - identifier: HostName
        columnName: HostName
      - identifier: DnsDomain
        columnName: DnsDomain
  - entityType: Process
    fieldMappings:
      - identifier: ProcessId
        columnName: InitiatingProcessFileName
      - identifier: CommandLine
        columnName: ProcessCommandLine
  - entityType: FileHash
    fieldMappings:
      - identifier: Algorithm
        columnName: FileHashAlgorithm
      - identifier: Value
        columnName: SHA256

version: 1.0.3
kind: Scheduled

Stages and Predicates

Parameters

let parentProcesses = dynamic(["pwsh.exe","powershell.exe","cmd.exe"]);

Let binding: args

let args = dynamic(["objectcategory","domainlist","dcmodes","adinfo","trustdmp","computers_pwdnotreqd","Domain Admins", "objectcategory=person", "objectcategory=computer", "objectcategory=*","dclist"]);

Stage 1: source

DeviceProcessEvents

Stage 2: where

| where InitiatingProcessFileName in~ (parentProcesses)

Stage 3: where

| where FileName =~ "AdFind.exe" or SHA256 == "c92c158d7c37fea795114fa6491fe5f145ad2f8c08776b18ae79db811e8e36a3"
    or ProcessCommandLine has_any (args)

References args (defined above).

Stage 4: extend

| extend HostName = split(DeviceName, '.', 0)[0], DnsDomain = strcat_array(array_slice(split(DeviceName, '.'), 1, -1), '.'), FileHashAlgorithm = "SHA256"

Indicators

Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.

FieldKindValues
FileNameeq
  • AdFind.exe
InitiatingProcessFileNamein
  • cmd.exe corpus 15 (elastic 10, splunk 4, kusto 1)
  • powershell.exe corpus 15 (elastic 12, kusto 2, splunk 1)
  • pwsh.exe
ProcessCommandLinematch
  • Domain Admins corpus 3 (sigma 2, splunk 1)
  • adinfo corpus 2 (sigma 2)
  • computers_pwdnotreqd corpus 2 (sigma 2)
  • dclist
  • dcmodes corpus 2 (sigma 2)
  • domainlist corpus 2 (sigma 2)
  • objectcategory
  • objectcategory=*
  • objectcategory=computer
  • objectcategory=person
  • trustdmp corpus 2 (sigma 2)
SHA256eq
  • c92c158d7c37fea795114fa6491fe5f145ad2f8c08776b18ae79db811e8e36a3 transforms: cased corpus 2 (kusto 2)

Output fields

Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.

FieldSource
DnsDomainextend
FileHashAlgorithmextend
HostNameextend