13.13 Detection Engineering

2–3 hours · Module 13

Detection Engineering

Every investigation should produce at least one new detection rule. This incident produced six.

Rule 1: Token replay from novel IP

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
let known_user_ips =
    SigninLogs
    | where TimeGenerated > ago(30d)
    | where ResultType == 0
    | distinct UserPrincipalName, IPAddress;
AADNonInteractiveUserSignInLogs
| where TimeGenerated > ago(1h)
| where ResultType == 0
| join kind=anti known_user_ips on UserPrincipalName, IPAddress
| extend Country = tostring(LocationDetails.countryOrRegion)
| summarize EventCount = count(), Apps = make_set(AppDisplayName),
    Countries = make_set(Country)
    by UserPrincipalName, IPAddress
| where EventCount > 3

Config: Scheduled, 15-minute interval. Severity: High. Entity mapping: Account + IP. Automated response: revoke sessions via playbook.

Rule 2: Inbox rule with suspicious keywords (NRT)

1
2
3
4
5
6
CloudAppEvents
| where TimeGenerated > ago(1m)
| where ActionType in ("New-InboxRule", "Set-InboxRule")
| extend Params = tostring(RawEventData.Parameters)
| where Params has_any ("security", "password", "unusual", "alert",
    "phishing", "hack", "compromised", "reset", "verify", "suspicious")

Config: NRT (every minute). Severity: Medium. Entity mapping: Account + IP.

Rule 3: Phishing kit URL pattern (NRT)

1
2
3
4
EmailUrlInfo
| where TimeGenerated > ago(1m)
| where Url matches regex @"/auth/[a-f0-9]{32}/login"
| join kind=inner (EmailEvents | where TimeGenerated > ago(1m)) on NetworkMessageId

Config: NRT. Severity: High. Automated response: soft delete matched emails.

Rule 4: Sign-in followed by inbox rule within 30 minutes

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
let recent_signins =
    SigninLogs
    | where TimeGenerated > ago(1h)
    | where ResultType == 0
    | project SigninTime = TimeGenerated, User = UserPrincipalName, SigninIP = IPAddress;
CloudAppEvents
| where TimeGenerated > ago(1h)
| where ActionType == "New-InboxRule"
| project RuleTime = TimeGenerated, User = AccountDisplayName, RuleIP = IPAddress
| join kind=inner recent_signins on User
| where RuleTime > SigninTime
| extend MinutesGap = datetime_diff('minute', RuleTime, SigninTime)
| where MinutesGap < 30

Config: Scheduled, 15 minutes. Severity: High.

1
2
3
4
5
6
7
UrlClickEvents
| where TimeGenerated > ago(15m)
| where IsClickedThrough == true
| summarize ClickCount = count(), Users = dcount(AccountUpn),
    Urls = make_set(Url)
    by UrlDomain
| where ClickCount > 3

Detects multiple users clicking through Safe Links warnings for the same domain — a strong campaign indicator.

Rule 6: New MFA method registered from unfamiliar IP

1
2
3
4
5
6
7
8
9
AuditLogs
| where TimeGenerated > ago(1h)
| where OperationName has "User registered security info"
| extend User = tostring(TargetResources[0].userPrincipalName)
| extend IP = tostring(InitiatedBy.user.ipAddress)
| join kind=anti (
    SigninLogs | where TimeGenerated > ago(30d) | where ResultType == 0
    | distinct UserPrincipalName, IPAddress
) on $left.User == $right.UserPrincipalName, $left.IP == $right.IPAddress

Detects MFA registration from an IP the user has never signed in from — catching the persistence technique where the attacker registers their own MFA method.

MITRE ATT&CK mapping

RuleTechniqueID
1 (Token replay)Steal Web Session CookieT1539
2 (Inbox rule)Email Hiding RulesT1564.008
3 (Phishing URL)Spearphishing LinkT1566.002
4 (Sign-in + rule)Valid Accounts + PersistenceT1078 + T1564
5 (Click-throughs)Spearphishing LinkT1566.002
6 (MFA registration)Modify Authentication ProcessT1556

Check your understanding

1. Why are Rules 2 and 3 configured as NRT (every minute) while Rules 1 and 4 are scheduled (every 15 minutes)?

Inbox rule creation and phishing email delivery are time-critical — every minute of delay means the persistence mechanism is active or the phishing email is accessible. Token replay detection and sign-in correlation can tolerate 15-minute latency because containment is less urgent once the initial indicators are identified.
NRT rules are always better
NRT rules cost less