Query Details

NTLM Network Logon Anomalies Lateral Movement

Query

# *NTLM Network Logon Anomalies (Lateral Movement)*

## Query Information

#### MITRE ATT&CK Technique(s)

| Technique ID | Title    | Link    |
| ---  | --- | --- |
| T1021 | Remote Services | https://attack.mitre.org/techniques/T1021/ |
| T1078 | Valid Accounts | https://attack.mitre.org/techniques/T1078/ |

#### Description

This rule detects anomalous NTLM network logon activity that could indicate lateral movement within an environment. It identifies accounts performing successful NTLM network logons to multiple devices within a short timeframe, especially when the activity significantly exceeds a historical baseline for that account. The rule filters out service accounts and specific excluded servers to reduce noise.

#### Author <Optional>
- **Name: Benjamin Zulliger**
- **Github: https://github.com/benscha/KQLAdvancedHunting**
- **LinkedIn: https://www.linkedin.com/in/benjamin-zulliger/**


## Defender XDR
```KQL
let ExcludedServer = dynamic(["YOUREXLUDEDSERVER"]); //SCCM Server
let lookback = 1d;
let knownServiceAccounts = dynamic(["svc-backup", "healthservice", "svc-scan"]);
let baseline = DeviceLogonEvents
    | where TimeGenerated between (ago(14d) .. ago(7d))
    | where LogonType == "Network" and Protocol == "NTLM"
    | where AccountName !endswith "$"
    | summarize BaselineDevices = dcount(DeviceName) by AccountName;
DeviceLogonEvents
| where TimeGenerated > ago(lookback)
| where LogonType == "Network"
| where Protocol == "NTLM"
| where ActionType == "LogonSuccess"
| where AccountName !endswith "$"
| where AccountName !in (knownServiceAccounts)
| where AccountName !startswith "svc-"
| where AccountName != "ANONYMOUS LOGON"
| where DeviceName !in (ExcludedServer)
| where isnotempty(AccountName)
| summarize
    DeviceCount    = dcount(DeviceName),
    Devices        = make_set(DeviceName, 10),
    FirstLogon     = min(TimeGenerated),
    LastLogon      = max(TimeGenerated),
    LogonCount     = count()
    by AccountName, AccountDomain
| where DeviceCount >= 2
| extend TimeSpanMin = datetime_diff('minute', LastLogon, FirstLogon)
| extend DevicesPerHour = round(toreal(DeviceCount) / (toreal(TimeSpanMin) / 60.0 + 1), 1)
| join kind=leftouter baseline on AccountName
| extend BaselineDevices = coalesce(BaselineDevices, 0)
| where DeviceCount > BaselineDevices * 1.5 or BaselineDevices == 0
| extend RiskLevel = case(
    DeviceCount >= 3 and TimeSpanMin < 30, "CRITICAL - Rapid Wide Movement",
    DeviceCount >= 5,                      "HIGH - Wide Movement",
    TimeSpanMin < 30,                      "CRITICAL - Rapid Movement",
    DeviceCount >= 2,                      "MEDIUM - Possible Lateral Movement",
    "LOW")
| where DevicesPerHour > 2
| project AccountName, AccountDomain, DeviceCount, BaselineDevices,
          DevicesPerHour, TimeSpanMin, RiskLevel, Devices, FirstLogon, LastLogon
| order by DeviceCount desc, TimeSpanMin asc
```

Explanation

This query is designed to detect unusual NTLM network logon activities that might indicate lateral movement within a network. Here's a simplified breakdown of what the query does:

  1. Setup Exclusions and Lookback Period:

    • It defines a list of servers to exclude from the analysis and specifies a lookback period of one day for recent logon events.
    • It also identifies known service accounts to exclude from the analysis to reduce noise.
  2. Establish a Baseline:

    • The query looks at logon events from 7 to 14 days ago to establish a baseline of how many different devices each account typically logs into using NTLM network logons.
  3. Analyze Recent Logon Events:

    • It examines recent logon events (within the last day) to identify accounts that have successfully logged into multiple devices using NTLM.
    • It filters out service accounts, anonymous logons, and logons to excluded servers.
  4. Identify Anomalies:

    • The query calculates the number of devices each account has logged into, the time span of these logons, and the rate of logons per hour.
    • It compares the recent activity against the established baseline to identify accounts that have logged into significantly more devices than usual.
  5. Assess Risk Level:

    • It assigns a risk level to each account based on the number of devices accessed and the speed of access:
      • "CRITICAL" for rapid or wide movement.
      • "HIGH" for wide movement.
      • "MEDIUM" for possible lateral movement.
      • "LOW" for less concerning activity.
  6. Output Results:

    • The query outputs a list of accounts with their domain, the number of devices accessed, baseline device count, logon rate, time span, risk level, and the first and last logon times.
    • The results are sorted by the number of devices accessed and the time span of the logons.

In essence, this query helps identify potential lateral movement by highlighting accounts that show unusual patterns of accessing multiple devices in a short period, which could indicate malicious activity.

Details

Benjamin Zulliger profile picture

Benjamin Zulliger

Released: May 21, 2026

Tables

DeviceLogonEvents

Keywords

DevicesAccountNameAccountDomainDeviceLogonEventsLogonTypeProtocolActionTypeTimeGeneratedDeviceNameBaselineDevicesRiskLevelDevicesPerHourTimeSpanMinLogonCountFirstLogonLastLogon

Operators

letdynamicbetweenagoendswithsummarizedcountbywhere!endswith!in!startswith!=isnotemptymake_setminmaxcountextenddatetime_diffroundtoreal/+joinkind=leftouteroncoalesce*caseprojectorder bydescasc

Actions