Detection rules › Kusto

PROD (TM011.1) - LAPS - Tier Level Computer Object LAPS Password Expiration Time Set Manually

Status
available
Severity
low
Time window
5h
Source
github.com/Azure/Azure-Sentinel

Alert if a Tier Model computer object LAPS password was manually expired.

MITRE ATT&CK coverage

Telemetry coverage

Rule body

id: daf2b9f7-dcf2-4b45-831a-d7142318c7e9
name: 'PROD (TM011.1) - LAPS - Tier Level Computer Object LAPS Password Expiration Time Set Manually'
description: |
  Alert if a Tier Model computer object LAPS password was manually expired.
severity: Low
requiredDataConnectors:
  - connectorId: SecurityEvents
    dataTypes:
      - SecurityEvent
  - connectorId: WindowsSecurityEvents
    dataTypes:
      - SecurityEvent
queryFrequency: 5h
queryPeriod: 5h
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
  - Discovery
relevantTechniques:
  - T1087.001
query: |
  SecurityEvent
  | where EventID == 5136
      and (EventData matches regex @"(?i)OU=Domain Controllers"
          or EventData matches regex @"(?i)OU=Tier 0 PAW"
          or EventData matches regex @"(?i)OU=Tier 1 PAW"
          or EventData matches regex @"(?i)OU=Tier 2 PAW"
          or EventData matches regex @"(?i)OU=Tier 0 Member Servers"
          or EventData matches regex @"(?i)OU=Tier 1 Member Servers")
      and AccountType == "User"
  | extend AttributeLDAP = extract("<Data Name=\"AttributeLDAPDisplayName\">([^<]+)</Data>", 1, EventData)
  | where AttributeLDAP has "msLAPS-PasswordExpirationTime"
  | extend ObjectName_e = extract("<Data Name=\"ObjectDN\">([^<]+)</Data>", 1, EventData)
  | extend ObjectName = extract("(?i)CN=([^,]+)", 1, ObjectName_e)
  | extend ObjectTier = case(
      ObjectName_e has "Tier 0", "Tier 0",
      ObjectName_e has "Tier 1", "Tier 1",
      ObjectName_e has "Tier Model Administration", "Tier 0",
      ObjectName_e has "Tier Model Computer Quarantine", "Tier 0",
      ObjectName_e has "Domain Controllers", "Tier 0",
      "Unknown")
  | extend ActivityType = extract("([a-zA-Z]+)\\.$", 1, Activity)
  | extend Domain = extract("([^.]+\\.[^.]+)$", 1, Computer)
  | extend OperationType = iff(EventData has 'OperationType">%%14674', "Added", tostring(OperationType))
  | project TimeGenerated
     , ObjectName
     , ObjectTier
     , AttributeLDAP
     , ActivityType
     , 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
  AttributeLDAP: AttributeLDAP
  ActivityType: ActivityType
  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: '(TM011.1) A {{ObjectTier}} LAPS password was expired by {{Account}} manually.'
  alertDescriptionFormat: 'The LAPS password for {{ObjectName}} was expired manually.'
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

SecurityEvent

Stage 2: where

| where EventID == 5136
    and (EventData matches regex @"(?i)OU=Domain Controllers"
        or EventData matches regex @"(?i)OU=Tier 0 PAW"
        or EventData matches regex @"(?i)OU=Tier 1 PAW"
        or EventData matches regex @"(?i)OU=Tier 2 PAW"
        or EventData matches regex @"(?i)OU=Tier 0 Member Servers"
        or EventData matches regex @"(?i)OU=Tier 1 Member Servers")
    and AccountType == "User"

Stage 3: extend

| extend AttributeLDAP = extract("<Data Name=\"AttributeLDAPDisplayName\">([^<]+)</Data>", 1, EventData)

Stage 4: where

| where AttributeLDAP has "msLAPS-PasswordExpirationTime"

Stage 5: extend (6 consecutive steps)

| extend ObjectName_e = extract("<Data Name=\"ObjectDN\">([^<]+)</Data>", 1, EventData)
| extend ObjectName = extract("(?i)CN=([^,]+)", 1, ObjectName_e)
| extend ObjectTier = case(
    ObjectName_e has "Tier 0", "Tier 0",
    ObjectName_e has "Tier 1", "Tier 1",
    ObjectName_e has "Tier Model Administration", "Tier 0",
    ObjectName_e has "Tier Model Computer Quarantine", "Tier 0",
    ObjectName_e has "Domain Controllers", "Tier 0",
    "Unknown")
| extend ActivityType = extract("([a-zA-Z]+)\\.$", 1, Activity)
| extend Domain = extract("([^.]+\\.[^.]+)$", 1, Computer)
| extend OperationType = iff(EventData has 'OperationType">%%14674', "Added", tostring(OperationType))

Stage 6: project

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

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
AccountTypeeq
  • User corpus 6 (kusto 6)
field:"AccountType" kind:eq value:"User"
AttributeLDAPmatch
  • msLAPS-PasswordExpirationTime transforms: term
field:"AttributeLDAP" kind:match value:"msLAPS-PasswordExpirationTime"
EventDataregex_match
  • (?i)OU=Domain Controllers corpus 8 (kusto 8)
  • (?i)OU=Tier 0 Member Servers corpus 8 (kusto 8)
  • (?i)OU=Tier 0 PAW corpus 6 (kusto 6)
  • (?i)OU=Tier 1 Member Servers corpus 8 (kusto 8)
  • (?i)OU=Tier 1 PAW corpus 6 (kusto 6)
  • (?i)OU=Tier 2 PAW corpus 6 (kusto 6)
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
ObjectNameproject
ObjectTierproject
TimeGeneratedproject