Detection rules › Kusto

Potential NTLM Relay Attack to Domain Controller

Author
Cyb3rMonk
Source
github.com/Cyb3r-Monk/Threat-Hunting-and-Detection

Below query detects NTLM authentication coming from Domain Controller machine accounts. This is not an expected behavior and it's an indication of NTLM relay attack.
If NTLM Relaying is done towards a Linux machine, this query won't detect that. The attacker must have access to a Linux device in that case though.

MITRE ATT&CK coverage

TacticTechniques
Credential AccessNo specific technique

Event coverage

Rule body kusto

// Author       : Cyb3rMonk(https://twitter.com/Cyb3rMonk, https://mergene.medium.com)
//
// Link to original post:
// https://posts.bluraven.io/detecting-petitpotam-and-other-domain-controller-account-takeovers-d3364bd9ee0a
//
// Description  : NTLM authentication coming from Domain Controller machine accounts. This is not an expected behavior and it's an indication of NTLM relay attack.   
//                If NTLM Relaying is done towards a Linux machine, this query won't detect that. The attacker must have access to a Linux device in that case though. 
//
// Query parameters:
//
// put FQDNs of the DCs into the list
let DCs = dynamic(["yourdc1.yourdomain.local","yourdc2.yourdomain.local"]);
DeviceLogonEvents
| where Protocol == "NTLM"
| where AccountName endswith "$"
| where DCs has replace_string(AccountName,"$","")

Stages and Predicates

Parameters

let DCs = dynamic(["yourdc1.yourdomain.local","yourdc2.yourdomain.local"]);

Stage 1: source

DeviceLogonEvents

Stage 2: where

| where Protocol == "NTLM"

Stage 3: where

| where AccountName endswith "$"

Stage 4: where

| where DCs has replace_string(AccountName,"$","")

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
AccountNameends_with
  • $ corpus 5 (elastic 4, kusto 1)
Protocoleq
  • NTLM transforms: cased corpus 2 (kusto 2)