Detection rules › Kusto

PROD (TM015.1) - ACL - Modified at KRBTGT or AdminSDHolder Object Level

Status
available
Severity
high
Time window
5m
Source
github.com/Azure/Azure-Sentinel

ACL changes to the KRBTGT or AdminSDHolder special objects.

MITRE ATT&CK coverage

Telemetry coverage

Rule body

id: a9f94bf1-856e-40ff-a176-24f967da1e27
name: 'PROD (TM015.1) - ACL - Modified at KRBTGT or AdminSDHolder Object Level'
description: |
  ACL changes to the KRBTGT or AdminSDHolder special objects.
severity: High
requiredDataConnectors:
  - connectorId: SecurityEvents
    dataTypes:
      - SecurityEvent
  - connectorId: WindowsSecurityEvents
    dataTypes:
      - SecurityEvent
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
  - Persistence
relevantTechniques:
  - T1078.002
query: |
  SecurityEvent 
  | where EventID == 5136 
      and (EventData matches regex @"(?i)CN=AdminSDHolder" or EventData matches regex @"(?i)CN=krbtgt")
      and Activity has "modified"
      and (EventData has '"ObjectClass">container' or EventData matches regex @"(?i)user")
      and EventData has '<Data Name="AttributeLDAPDisplayName">nTSecurityDescriptor</Data>' 
      and EventData has '"OperationType">%%14674'
  | extend ObjectName = extract("<Data Name=\"ObjectDN\">(((?i)CN=[^,]+,?)+),[dD][cC]=", 1, EventData)
  | extend ObjectTier = "Tier 0"
  | extend AttributeLDAP = extract("<Data Name=\"AttributeLDAPDisplayName\">([^<]+)</Data>", 1, EventData)
  | extend OperationType = iff(EventData has 'nTSecurityDescriptor', "ACL Modified", tostring(OperationType))
  | extend ActivityType = extract("([a-zA-Z]+)\\.$", 1, Activity)
  | extend ObjectClass = extract("<Data Name=\"ObjectClass\">([^<]+)</Data>", 1, EventData)
  | extend Domain = extract("([^.]+\\.[^.]+)$", 1, Computer)
  | project TimeGenerated
     , ObjectName
     , ObjectTier
     , ObjectClass
     , OperationType
     , ActivityType
     , AttributeLDAP
     , Account
     , Domain
     , Computer
     , Channel
     , EventID
     , EventData
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: ObjectName
  - entityType: Host
    fieldMappings:
      - identifier: HostName
        columnName: Computer
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: Account
customDetails:
  ObjectName: ObjectName
  ObjectTier: ObjectTier
  ObjectClass: ObjectClass
  OperationType: OperationType
  ActivityType: ActivityType
  AttributeLDAP: AttributeLDAP
  Account: Account
  Domain: Domain
  Computer: Computer
  Channel: Channel
  EventID: EventID
  EventData: EventData
eventGroupingSettings:
  aggregationKind: AlertPerResult
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: false
    reopenClosedIncident: false
    lookbackDuration: PT5H
    matchingMethod: AllEntities
alertDetailsOverride:
  alertDisplayNameFormat: '(TM015.1) The {{ObjectTier}} {{ObjectName}} ACL was modified'
  alertDescriptionFormat: 'The following user {{Account}} modified the {{ObjectName}} ACLs.'
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

SecurityEvent

Stage 2: where

| where EventID == 5136 
    and (EventData matches regex @"(?i)CN=AdminSDHolder" or EventData matches regex @"(?i)CN=krbtgt")
    and Activity has "modified"
    and (EventData has '"ObjectClass">container' or EventData matches regex @"(?i)user")
    and EventData has '<Data Name="AttributeLDAPDisplayName">nTSecurityDescriptor</Data>' 
    and EventData has '"OperationType">%%14674'

Stage 3: extend (7 consecutive steps)

| extend ObjectName = extract("<Data Name=\"ObjectDN\">(((?i)CN=[^,]+,?)+),[dD][cC]=", 1, EventData)
| extend ObjectTier = "Tier 0"
| extend AttributeLDAP = extract("<Data Name=\"AttributeLDAPDisplayName\">([^<]+)</Data>", 1, EventData)
| extend OperationType = iff(EventData has 'nTSecurityDescriptor', "ACL Modified", tostring(OperationType))
| extend ActivityType = extract("([a-zA-Z]+)\\.$", 1, Activity)
| extend ObjectClass = extract("<Data Name=\"ObjectClass\">([^<]+)</Data>", 1, EventData)
| extend Domain = extract("([^.]+\\.[^.]+)$", 1, Computer)

Stage 4: project

| project TimeGenerated
   , ObjectName
   , ObjectTier
   , ObjectClass
   , OperationType
   , ActivityType
   , AttributeLDAP
   , Account
   , Domain
   , Computer
   , Channel
   , EventID
   , EventData

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
Activitymatch
  • modified transforms: term corpus 10 (kusto 10)
field:"Activity" kind:match value:"modified"
EventDatamatch
  • "ObjectClass">container transforms: term
  • "OperationType">%%14674 transforms: term corpus 7 (kusto 7)
  • <Data Name="AttributeLDAPDisplayName">nTSecurityDescriptor</Data> transforms: term corpus 3 (kusto 3)
field:"EventData" kind:match
EventDataregex_match
  • (?i)CN=AdminSDHolder
  • (?i)CN=krbtgt
  • (?i)user
field:"EventData" kind:regex_match
EventIDeq
  • 5136 corpus 45 (splunk 24, kusto 18, elastic 3)
field:"EventID" kind:eq value:"5136"

Output fields

These fields are emitted when the rule matches.

FieldSource
Accountproject
ActivityTypeproject
AttributeLDAPproject
Channelproject
Computerproject
Domainproject
EventDataproject
EventIDproject
ObjectClassproject
ObjectNameproject
ObjectTierproject
OperationTypeproject
TimeGeneratedproject