Detection rules › Kusto

Suspicious Sign In Followed by MFA Modification

Status
available
Severity
medium
Time window
1d
Group by
InitiatorUPN, UserPrincipalName
Source
github.com/Azure/Azure-Sentinel

This query looks uses Microsoft Sentinel's UEBA features to look for suspicious logons followed by modifications to MFA settings by that user.

MITRE ATT&CK coverage

Event coverage

Rules detecting the same action

Other rules on this platform that filter on the same API call or operation.

Rule body kusto

id: aec77100-25c5-4254-a20a-8027ed92c46c
name: Suspicious Sign In Followed by MFA Modification
description: |
  'This query looks uses Microsoft Sentinel's UEBA features to look for suspicious logons followed by modifications to MFA settings by that user.'
severity: Medium
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
      - AuditLogs
  - connectorId: BehaviorAnalytics
    dataTypes:
      - BehaviorAnalytics
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
eventGroupingSettings:
  aggregationKind: AlertPerResult
status: Available
tactics:
  - InitialAccess
  - DefenseEvasion
relevantTechniques:
  - T1078.004
  - T1556.006
query: |
  let PriorityScore = 9;
  BehaviorAnalytics
  | where ActionType == "Sign-in"
  | where InvestigationPriority > PriorityScore
  | extend UserPrincipalName = tolower(UserPrincipalName)
  | extend LogOnTime = TimeGenerated
  | join kind=inner (AuditLogs
  | where Category =~ "UserManagement" 
  | where OperationName in~ ("Admin registered security info", "Admin updated security info", "Admin deleted security info", "User registered security info", "User changed default security info", "User deleted security info","User registered all required security info","User started security info registration") 
  | extend InitiatorUPN = tolower(tostring(InitiatedBy.user.userPrincipalName))
  | extend InitiatorID = tostring(InitiatedBy.user.id)
  | extend FromIP = tostring(InitiatedBy.user.ipAddress) 
  | extend TargetUPN = tolower(tostring(TargetResources[0].userPrincipalName))
  | extend TargetId = tostring(TargetResources[0].id)
  | extend MFAModTime = TimeGenerated
  | where isnotempty(InitiatorUPN)) on $left.UserPrincipalName == $right.InitiatorUPN
  | where MFAModTime between((LogOnTime-30m)..(LogOnTime+1h))
  | extend InitiatorName = tostring(split(InitiatorUPN, "@")[0]), InitiatorUPNSuffix = tostring(split(InitiatorUPN, "@")[1]), TargetName = tostring(split(TargetUPN, "@")[0]), TargetUPNSuffix = tostring(split(TargetUPN, "@")[1])
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: InitiatorUPN
      - identifier: Name
        columnName: InitiatorName
      - identifier: UPNSuffix
        columnName: InitiatorUPNSuffix
  - entityType: Account
    fieldMappings:
      - identifier: AadUserId
        columnName: InitiatorID
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: TargetUPN
      - identifier: Name
        columnName: TargetName
      - identifier: UPNSuffix
        columnName: TargetUPNSuffix
  - entityType: Account
    fieldMappings:
      - identifier: AadUserId
        columnName: TargetId
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: FromIP
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: SourceIPAddress
alertDetailsOverride:
  alertDisplayNameFormat: Suspicious Sign In by {{InitiatorUPN}} Followed by MFA Modification to {{TargetUPN}}
  alertDescriptionFormat: |
    This query looks uses Microsoft Sentinel's UEBA features to look for suspicious logons followed by modifications to MFA settings by that user.
    In this case {{InitiatorUPN}} logged in followed by a modification to MFA settings for {{TargetUPN}}.
    The sign in was from {{SourceIPAddress}}.
version: 1.0.1
kind: Scheduled

Stages and Predicates

Parameters

let PriorityScore = 9;

Stage 1: source

BehaviorAnalytics

Stage 2: where

| where ActionType == "Sign-in"

Stage 3: where

| where InvestigationPriority > PriorityScore

Stage 4: extend

| extend UserPrincipalName = tolower(UserPrincipalName)

Stage 5: extend

| extend LogOnTime = TimeGenerated

Stage 6: join

| join kind=inner (AuditLogs
| where Category =~ "UserManagement" 
| where OperationName in~ ("Admin registered security info", "Admin updated security info", "Admin deleted security info", "User registered security info", "User changed default security info", "User deleted security info","User registered all required security info","User started security info registration") 
| extend InitiatorUPN = tolower(tostring(InitiatedBy.user.userPrincipalName))
| extend InitiatorID = tostring(InitiatedBy.user.id)
| extend FromIP = tostring(InitiatedBy.user.ipAddress) 
| extend TargetUPN = tolower(tostring(TargetResources[0].userPrincipalName))
| extend TargetId = tostring(TargetResources[0].id)
| extend MFAModTime = TimeGenerated
| where isnotempty(InitiatorUPN)) on $left.UserPrincipalName == $right.InitiatorUPN

Stage 7: where

| where MFAModTime between((LogOnTime-30m)..(LogOnTime+1h))

Stage 8: extend

| extend InitiatorName = tostring(split(InitiatorUPN, "@")[0]), InitiatorUPNSuffix = tostring(split(InitiatorUPN, "@")[1]), TargetName = tostring(split(TargetUPN, "@")[0]), TargetUPNSuffix = tostring(split(TargetUPN, "@")[1])

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
ActionTypeeq
  • Sign-in transforms: cased
Categoryeq
  • UserManagement
InitiatorUPNis_not_null
  • (no value, null check)
InvestigationPrioritygt
  • 9 transforms: cased
OperationNamein
  • Admin deleted security info
  • Admin registered security info
  • Admin updated security info
  • User changed default security info
  • User deleted security info
  • User registered all required security info
  • User registered security info
  • User started security info registration

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
UserPrincipalNameextend
LogOnTimeextend
InitiatorNameextend
InitiatorUPNSuffixextend
TargetNameextend
TargetUPNSuffixextend